DOWNSTREAM: Fastfoward camx Topic branch to AU200
* commit '14416b24d6229fcacde62b3826e6e60898a2c53a':
msm: ipa: add new IP filtering bitmaps
ARM: dts: msm: Add battery data for MLP356477 battery
msm: kgsl: Avoid sending 0 BW and GPU freq to GMU
kernel: Restrict permissions of /proc/iomem.
defconfig: sdm845: enable refgen regulator driver
ARM: dts: msm: keep refgen regulator always-on for SDM845 v2
ARM: dts: msm: add refgen regulator device for SDM845 v2
defconfig: sdm845: enable regulator proxy consumer driver
regulator: add refgen regulator driver
ARM: dts: msm: update the energy model for SDM845v2
msm: kgsl: Remove GPU_CC_GX_CXO_CLK from list of clocks
ARM: dts: msm: Add the silver BIN1 table for SDM845 v2
diag: Fix possible usage of freed resource issue
msm: ADSPRPC: validate user buffers after copying from user
leds: qpnp-wled: Cap the lower limit of brightness level
drm/msm/sde: handle color processing in secure state
drm/msm/sde: cleanup handling of secure buffer in planes
drm/msm/sde: manage secure and non-secure transition in sde
msm: gsi: check channel state on timeout
drm/dp: add HBR3 link rate definitions
ANDROID: fix acl leaks
power: smblib: make OTG_VOTER suspend input only in OTG state
cpufreq: schedutil: Add current capacity info to schedutil tracepoint
msm: vidc: Add new trace events
Enable multi-channel bit for SCO Tx with water mark level 1
msm: kgsl: Pass GPU HW version to GMU
msm: vidc: Send profile/level to the userspace
msm: vidc: Support low latency for decode
tracing: do not leak kernel addresses
msm: kgsl: Update the smmu magic for A6XX preemption
drm/msm/dp: add dp_debug module
drivers: cpuidle: check if its okay to do cluster low power modes
clk: qcom: clk-cpu-osm: Updates to OSM DATA MEM programming
ARM: dts: msm: add msm-ext-display module for sdm845
drm/sde: set DisplayPort/HDMI switch
drm/msm/dp: add audio support
qcdev: Check the digest length during the SHA operations
ASoC: sdm660: Remove LPI gpio configuration for codec interrupt
iommu: arm-smmu: Enable sid switch usecase
iommu: arm-smmu: Remove unused functions for qsmmuv500
iommu: arm-smmu: Remove regulator_bulk_enable call
drm/msm/dp: add hardware catalog for audio
platform: msm: add support for external display module
leds: remove unused driver leds-qpnp-flash.c
ARM: dts: msm: disable reg dma block for sdm845
ARM: dts: msm: Add MX regulator thermal config for SDM845
defconfig: Enable regulator cooling device for SDM845
drivers: thermal: regulator_cdev: Add a voltage regulator cooling device
netfilter: xt_quota2: 4.9 netlink notification fix
power: qpnp-fg-gen3: improve cycle counter algorithm
power: qpnp-fg-gen3: make TTF monotonic by limiting slope
power: qpnp-fg-gen3: optimize TTF for QNOVO
power: qpnp-fg-gen3: prepare for QNOVO TTF
ARM64: Increase the number of gpios to 1280
defconfig: Enable regulator AOP cooling device for SDM845 and SDM670
msm: kgsl: Trigger preemption only when preemption is enabled
time: sched_clock: record cycle count in suspend and resume
msm: adsprpc: Avoid leak info of pointers addresses to dmesg
ARM: dts: msm: Add support for haptics on PM660
ARM: dts: msm: add SPMI PMIC arbiter device for sdxpoorwills
msm: kgsl: Disable microcode save/restore of perf counter values on A6x
iommu/io-pgtable-fast: invalidate TLBs on unmap
clk: qcom: clk-cpu-osm: Update logic to check if OSMs been enabled in TZ
driver: thermal: regulator_aop: Rename AOP Regulator cooling device
cpufreq: schedutil: Avoid WALT logic when WALT sysctl flag not set
checkpatch: Check to make sure DT property names are lowercase
checkpatch: Only newline after };
drm/msm/sde: add check for inline rotation source split cfg
drm/msm/sde: add ubwc equivalent tile formats
ARM: dts: msm: Resolve XPU fault on qseecom memory on sdm845
power: fg-util: add median filter for circular buffer
power: qpnp-fg-gen3: use the CC_STEP and CC_STEP_SEL properties
power_supply: add CC_STEP and CC_STEP_SEL properties
qpnp-smb2: Ignore status 7 register while qnovo is enabled
qcom: qnovo: restart pulse train in stall state
qpnp-qnovo: add debounce for charger
qpnp-qnovo: prevent pulse train while esr is in progress
qpnp-fg-gen3: qnovo ESR/IADC workarounds
qpnp-qnovo: IADC/ESR workarounds
power: qcom-step-chg: Add temperature based step-charging
msm: ipa: fix race condition around sys->len
qpnp-smb2: Support faking battery full status in WiPower
qcom: battery: Fix parallel disabled issue on charging boot
drivers: qcom: system_pm: allow idle drivers to query system state
ASoC: msm: make SND_SOC_660 to depend on ARCH_QCOM instead of specific SOC
msm: vidc: add P010 support in uapi
media: broadcast: tspp: Add SMMU translation for ION buffers
ASoC: msm: qdspv2: initialize struct member before being used
msm: vidc: Update core and stage selection logic
drm/msm/sde: switch to lp2 for pm suspend call during lp1
ARM: dts: msm: Update memory map for sdm845
spi: spi-geni-qcom: Introduce GSI DMA mode
power: qcom: smb-lib: optimize parallel current limiting with PD
msm: ipa: fix client cons check on hw stats
platform: msm: qcom-geni-se: Modify GSI switch sequence
msm: sde: cleanup format validation for sbuf mode
ARM: dts: msm: move PMI8998 devices into overlays for sdm845
usb: dwc3: Suspend USB SS PHY in host mode with device connect case
platform: msm: qcom-geni-se: Fix error during bus voting
drivers: qcom: rpmh: export controller status
drm/msm/sde: fix validation in secure state check
ASoC: wcd-mbhc: Increase number of measurements for impedance calc to 900
ASoC: APR: initialize struct member before being used
ASoC: msm: Free the gpio on remove
btfm: Correct the slimbus turn on/off sequence for FM ports
ASoC: msm: qdsp6v2: Replace default Tx voice topology
drm/msm/sde: move lp handling to kickoff callback
ARM: dts: msm: Change battery profile for QRD845 device
ARM: dts: msm: Add battery profile for GT3746A6 battery
tty: serial: msm_geni_serial: Fix the race condition during RX
input: misc: hbtp_input: Support for Region of Interest/sensors
i2c: qcom: geni: Use GSI DMA-engine if FIFO is disabled
drm/msm/sde: set inline rotator output x & y offset to 0
ARM: dts: msm: configure vref LDO for isens hardware in SDM845
dwc3-msm: Add functionality to restart USB host mode
drivers: qcom: rpmh: crash on lack of response
spcom: ignore CONNECTED notification while closing the channel
drivers: swr-wcd-ctrl: Fix wsa mute at boot
mm: cma: fix stack corruption due to sprintf usage
drm/msm/sde: update te vsync enable sequence change
spcom: avoid race condition when handling commands
spcom: move SPCOM_MAX_CHANNELS define to uapi/linux/spcom.h
ARM: dts: msm: Enable auto-calibration for WLED on PM660/PMI8998
leds: qpnp-wled: Add auto-calibration logic for WLED
Revert "ARM: dts: msm: Defer regulator disable for SDM845 GPU SMMU"
Revert "arm64: defconfig: Enable QSEE IPC irq bridge"
Revert "ARM: dts: msm: Enable support for QSEE IPC irq bridge on sdm845"
ARM: dts: msm: Add display support for SDM845 based SMD670 interposer
driver: thermal: lmh-dcvsh: Expose lmh frequency limit sysfs
drm/msm/dp: use fixed NVID for VGA dongles
ARM: dts: msm: Update the CPU clock speedbin table for SDM845v2
drm/msm/sde: Update color processing on suspend/resume transitions
msm: sde: move vbif init after clock enable
drm/msm/sde: override kms post open function
drm/msm/sde: update sspp dirty flags if inline cfg changes
drm/msm/sde: clear vbif errors before kickoff
drm/msm/sde: delay inline rotate start until kickoff
msm: kgsl: Add support for GPU AB voting
ARM: dts: msm: Add support for GPU AB vote on SDM845
cma: Store a name in the cma structure
ARM: dts: msm: Add FastRPC QoS latency control for sdm845
msm: ADSPRPC: add support for fastrpc control interface
diag: Add support for header untagging
ARM: dts: msm: Add audio support for SDM845 Interposer SDM670
ARM: dts: msm: Initial change for audio on sdm670
defconfig: msm: Add perf configuration support for sdm670
btfm: provide a way to query wcn3990 status
msm: msm_bus: Do not send tcs sets when size is 0
ARM: dts: msm: vote for half of GPU IB in DCVS in SDM845
ARM: dts: msm: update APC0 speed bin 1 CPRh regulator config for SDM845 v2
ARM: dts: msm: Specify bmd-en-delay-ms for QRD845 device
power: qpnp-fg-gen3: Add property to set delay between RID and BMD
usb: pd: Support revision 3.0 in sink-only mode
usb: pd: simplify pd_phy_write() and pd_phy_signal() usage
usb: pd: rename enum pd_msg_type to pd_sop_type
ARM: dts: msm: Change memlat freq tables for SDM845
clk: qcom: gpucc-sdm845: Fix gfx3d clock frequency for SDM845 V2
drm/msm/dsi-staging: add dsi phy isolate enable config
drm/msm/sde: return last misr status during idle pc
ARM: dts: msm: update dual dsi sim panel res for sdm845 target
defconfig: sdxpoorwills: disable DCC console
drm/msm/sde: memory leak fix for virtual plane formats
drm/msm/sde: virtual plane validation fixes for tiled formats
drm/msm/sde: set the tile height for all supported formats
msm: vidc: Print noc error information after pagefault
msm: vidc: Handle rotation during capability check
msm: kgsl: Dump GMU snapshot
ARM: dts: msm: Fix mic detection for SDM845 QRD
drivers: soc: apr: add initialization of a local variable
drm/msm: support backoff time update only in sde rsc
drm/msm: update irq registration during seamless mode switch
drm/msm: fix sde debug bus test point for valid status
ARM: dts: msm: Update latency for Sleep modes
drivers: lmh-dcvsh: Add isens vref regulator support
btfm: Enable multichannel bit for SCO Rx
ASoC: msm: add support for bit width selection
nl80211: Update ERP info using NL80211_CMD_UPDATE_CONNECT_PARAMS
msm: vidc: Add support for TME
cfg80211: Include length of kek in rekey data
qbt1000: Validate FP app name before qseecom_start_app
arm: dma-mapping: Add dma_remap functions
msm: msm_bus: Ignore -EBUSY from RPMH when sending AWAKE requests
seemp: adjust interpretation of rooting report
defconfig: sdm845: Enable FORTIFY_SOURCE
drm/msm/sde: add null checks for pingpong and encoder hardware
drm/msm: allow rsc clients to wait on crtc id on transition
ARM: dts: msm: Add the syscon compatible string to clock nodes on SDM845v2
drivers: edac: Update banks for edac sysfs entry
clk: Add separate function to print clocks enabled during suspend
clk: qcom: Fix clock GPUCC PLL1 crash when call regulator_set_voltage
drm/msm/sde: increase gpu input fence timeout to 10 seconds
drm/msm: dispatch sync commit to display thread
drm/msm/sde: reuse rotator from previous crtc states
msm: sde: allow offline session to wait for inline closing
drm/msm: clean up inline rotator register dump
msm: sde: clean up evtlog & trace for inline rotator
drm/msm/sde: toggle vblank using enable state in display thread
msm: kgsl: Always do an OOB for DCVS
msm: kgsl: Use the proper power level indexes
msm: kgsl: Use OPP API to query VLVL of GPU/GMU frequency
msm: kgsl: Remove code that touches GFX clock
msm: kgsl: Update the context create flags
msm: vidc: Return only active state VBs during flush
drm/msm: Fix potential buffer overflow issue
ARM: dts: msm: Add SDM845 Interposer SDM670 support
mm: run the showmem notifier in alloc failure
mm, oom: run the showmem notifier in oom
mm: cma: Register with show_mem notification framework
lowmemorykiller: Run the showmem notifier when killing
mm: cma: print allocation failure reason and bitmap status
diag: Add NULL pointer checks
ion: Correct argument of Set/ClearPagePrivate of secure CMA
ARM: dts: msm: Defer regulator disable for SDM845 GPU SMMU
iommu/arm-smmu: Add support for regulator deferred disable
msm: ADSPRPC: Queue one more intent to avoid race condition
wil6210: protect against invalid length of tx management frame
ASoC: msm: Add support for Stereo EC Reference
ASoC: msm_sdw: Set codec directory name at runtime
pinctrl: lpi: Update LPI address size and offset for SDM670
pinctrl: qcom: Add direct connect configuration for sdm670
Prevent heap overflow in uvc driver
ANDROID: ion: Fix uninitialized variable
ANDROID: ion: Protect kref from userspace manipulation
video: adf: zero out mapping data on adf_buffer_map() failure
CHROMIUM: usb: gadget: configfs: Fix KASAN use-after-free
android: fiq_debugger: restrict access to critical commands.
ANDROID: ion: check for kref overflow
cgroup: prefer %pK to %p
ion: Convert allocation counters to long
iommu: io-pgtable-arm: Remove duplicate tlb flush
ARM: dts: msm: Correct required clocks for kgsl_iommu for sdm845
iommu: arm-smmu: Disable ATOS feature for the QSMMUV2 model
ASoC: msm: qdsp6v2: Set path type to LIVE_REC in LISTEN passthrough case
msm: vidc: Fix VP9 decoder failure due to scaling feature
usb: misc: lvstest: add entry to place port in compliance mode
usb: xhci: Support enabling of compliance mode for xhci 1.1
drivers: mailbox: qti-tcs: fix for h/w issue with RSC clock gating
ARM: dts: msm: add PM8998 LDO 1 active-only regulator device for sdm845
scsi: ufs: add ufs card removal support
regulator: rpmh-regulator: correct initial wake-only state request
USB: f_ccid: Unblock ccid_ctrl_read() during disconnect
ARM: dts: msm: Update USB bus voting to allow low svs on SDM845
drm/msm/sde: correct scale offset for some gamut modes
tty: serial: msm_geni_serial: Add SE DMA transfer mode support
drm/msm/sde: handle atomic commit with dynamic mode switch
drm/msm/dsi-staging: add support for dynamic mode switch
drm/msm: defer DSI panel timing parameter parsing
msm: kgsl: Dump the RB registers correctly on A6XX
mfd: wcd9xxx: Add support for gpio controlled buck VSEL pin
msm: kgsl: Do not memset pages to zero while adding to pool
ARM: dts: msm: Enable SMMU GDSCs for sdm670
icnss: Delay Shutdown/reinit sequence for all cases
ARM: dts: msm: Add fastrpc device tree nodes for sdm670
ASoC: core: Fix possible NULL pointer dereference
msm: ipa3: Fix IPA aggregation force close call
ARM: dts: msm: switch to RPMh controlled PMIC regulators for sdm670
core_ctl: Switch isolation to new hotplug state callbacks
include/linux/string.h: add the option of fortified string.h functions
lkdtm: hide stack overflow warning for corrupt-stack test
lkdtm: Prevent the compiler from optimising lkdtm_CORRUPT_STACK()
lkdtm: Add tests for struct list corruption
IB/rxe: do not copy extra stack memory to skb
staging/rts5208: Fix read overflow in memcpy
kexec_file: adjust declaration of kexec_purgatory
efi: avoid fortify checks in EFI stub
arm64, vdso: Define vdso_{start,end} as array
arm64: Use __pa_symbol for kernel symbols
arm64: Add cast for virt_to_pfn
mm: Introduce lm_alias
msm: vidc: Map rate control vbr_vfr to vbr_cfr
ARM: dts: msm: Update the SDCC2 clock frequency on SDM845 v2
serial: msm_geni_serial: Remove proxy driver resource vote for HS UART
lpm: add sysfs tunable for bias hyst
soc: qcom: scm: fix boot issue when compiled with clang
msm: ipa3: fix the Use-after-free in ipa3_dma_destroy
soc: qcom: ipc_router: Improve IPC attribution
coresight: tmc: Fix the spinlock release in tmc etr disable function
msm:kgsl: Add Limits Management code to A6XX platform
ASoC: msm: qdspv2: Fix missing mutex unlock in LSM client driver
ASoC: msm: qdsp6v2: Add support to query AVCS version info
drm/msm/dp: retry failed AUX transactions
drm/msm/dp: update parsing of AUX configuration settings
msm: ipa: Fix wrong usage and cleanup code
msm: ipa: Fix invalid source pipe index
msm: ipa3: Fix Q6 resourse manager de-init
cpufreq: cpu-boost: utilize latest sched_boost API
ARM: dts: msm: Update the revision id for v1 chips on SDM845
arm64: ascii armor the arm64 boot init stack canary
random,stackprotect: introduce get_random_canary function
random: convert get_random_int/long into get_random_u32/u64
kthread: Fix use-after-free if kthread fork fails
arm64: uaccess: consistently check object sizes
clk: qcom: clk-cpu-osm: Rework the MEM_ACC_LEVEL setting logic
power: pmic-voter: make debug status more parsable
ARM: dts: msm: Add graphic clock support for SDM845 v2
clk: qcom: Add GPU CC and GFX clock driver support for SDM845 v2
clk: qcom: gcc-sdm845: Enable the gcc_aggre_noc_pcie_tbu_clk explicitly
drm/msm/dsi-staging: fix DSI controller init sequence
msm: wlan: Regulatory updates
sched: Don't update idle_cpus_mask during core isolation
ASoC: msm: Change wsa dt property to optional
ASoC: wsa881x: Add support to stub out wsa functionality
ARM: dts: msm: Add DT node for aop-qmp clock controller on SDM845 v2
clk: qcom: clk-aop-qmp: Add support for the qdss_ao clock resource
usb: gadget: mtp: Move mutex_init() to alloc_inst_mtp_ptp()
USB: f_mtp: Perform vfs_write under mutex protection
SDM660: ADSPRPC: Align the size of IOVA to 128MB
msm: ipa: Fix for missing int overflow check in the refcount library
msm: ipa3: Fix to avoid accessing of uninitialized structure
soc: qcom: Notify to app pd clients in ind_ack thread
sdm660: ADSPRPC: Null check file session ctx during mmap create
msm: ADSPRPC: avoid sending new requests to dsp while device_release
mmc: host: Capture error states in Trace logs.
defconfig: sdm845: Enable CTR crypto in kernel
defconfig: sdm670: Remove msm-core driver
soc: qcom: msm_performance: Include msm-core header
msm: ipa: add support for packet length update
msm: vidc: Convert useltr index value to bit mask
ARM: dts: msm: Enable llc bw voting as per load
msm: vidc: Add support for llc split bandwidth
msm: vidc: Add support for runtime input CR
sched: bring back sched_migrate_task trace point
sched: move task_util() to sched.h
soc: eud: Fix event handling for input suspend/unsuspend
ASoC: msm: qdsp6v2: Add capture support for MultiMedia10 FE
crypto: msm: Fix buffer overflow issue
ARM: dts: msm: Remove the qcom,pc-override-index flag on SDM845
btfm: cleanup slimbus device node in failure scenerios
crypto: Change format specifier %p to %pK
soc: qcom: pil: Signal call to cleanup TZ internal state in failure
crypto: msm: Fix several race condition issues in crypto drivers
ASoC: msm8996: remove unused machine driver
compat_qcedev: Fix accessing userspace memory in kernel space
usb: dwc3: dwc3-msm: Handle floating charger PMI notification properly
usb: pd: policy_engine: Add support to handle floating charger
usb: dwc3-msm: Add support to handle floating D+/D- lines
pinctrl: qcom: Update pinctrl for SDM845 v2
pinctrl: qcom: Dynamic detection of tile bases
ARM: dts: msm: Enable the OSM clock driver support on SDM845 v2
ARM: dts: msm: Enable support for QSEE IPC irq bridge on sdm845
arm64: defconfig: Enable QSEE IPC irq bridge
soc: qcom: Add Snapshot of QSEE IPC irq driver
drivers: soc: qcom: Ensure bytes_received is initialized
qcom: scm: Remove inputs printing from scm_call2_atomic
drivers: cpuidle: lpm-levels: respect CPU bias
ARM: dts: msm: Add PIL sub-system for IPA FWs on sdxpoorwills
sched: add sched_get_cpu_last_busy_time() API
Perf: core: create/delete shared kernel events
msm: ADSPRPC: Fix for NULL pointer dereference
arm: dma-mapping: flush highmem mappings
ARM: dma-mapping: Allow highmem pages to not have a mapping
arm: dma: Allow CMA pages to not have a kernel mapping.
mmc: core: fix typo in mmc_stop_host
msm: kgsl: Enable dynamic bus scaling for the GPU
clk: qcom: clk-cpu-osm: Correct the logic to return the CPU cycle counter
msm: vidc: Update profile/level capabilities
ARM: dts: msm: add VDD_APC0/1 CPR regulator configurations for sdm845v2
regulator: cprh-kbss-regulator: add support for SDM845v2 CPR controllers
ARM: dts: msm: Update count unit for CPU bwmon on sdm845v2
drm/msm/sde: enable write_gather_en in VBIF for all write clients
msm: ipa4: add unit test for statistics
drm/msm/sde: report qseed3 h/w version in plane caps
drm/msm/sde: register set_power callback for dsi driver
drm/msm/dsi-staging: add lp1/lp2 command support
drm/msm/sde: select shorter idle pc timeout for lp modes
ASoC: wcd934x-dsp-cntl: notify online event after clocks are disabled
ARM: dts: msm: modify mdss mdp clock rates for sdm845 HW
msm: ipa4: add support for statistics
clk: qcom: gcc-sdm845: Update the SDCC2 clock frequency on SDM845 v2
drm/msm: add more vbif error info to vbif debug bus dump
arm64: dma-mapping: fix aliasing issues with non-CMA alloc
ion: Set the page private bit for secure CMA buffers
ASoC: msm: qdsp6v2: make audio debugfs read and release exclusive
arm: Skip DMA zeroing completely only if specified
msm: kgsl: Fix a race condition when destroying fence events
f_audio_source: Use f_audiosource as first device name
mmc: card: blk: Add support for deferred SD bus resume
ARM: dts: msm: Add sdhc1 for sdm670 rumi
soc: qcom: secure_buffer: Remove deprecated functions
ARM: dts: msm: modify QRD panel support configuration for SDM845
trace: prevent NULL pointer dereference
msm: vidc: Flush debug message queue before power collpase
coresight: tmc: Read the TMC mode register only if clk is enabled
coresight: stm: Fix missing disable flag when disabling STM
ARM: dts: msm: specify haptics device for sdm845 QRD
soc: qcom: msm_bus: add mutex lock for cllist data
usb: bam: Remove inactivity_timer sysfs attribute
msm: vidc: Fix use-after-free memory failure
clk: qcom: clk-cpu-osm: Add support for trustzone enablement of OSM
power: qpnp-fg-gen3: Use msoc for recharge-soc comparison
power: smb-lib: enable DPDM regulator at CC attach
power: smb-lib: Update the FLOAT detection logic
power: smb-lib: Move to SW based step-charging
power: qcom-step-chg: Add a new file for step-charging
power: smb-lib: Restart charging from soft JEITA
drivers: cpuidle: lpm-levels: Update ordering for broadcast timer
msm: kgsl: Bypass GMU write/read buffers
power: smb-lib: Improve the OTG enable workaround for PM660
smb-lib: fix usbin_icl_change interrupt storm
power: smb138x-charger: set buck freq to 700kHz in slave mode
ASoC: wcd-dsp-mgr: fix race during subsystem restart
ARM: dts: msm: add QUAT TDM pinctrl configurations on SDM845
msm: vidc: Video system cache resource management update
msm: ipa: add new API for ipa bridge (formerly ODU bridge)
Kconfig: enable default config for audio.
msm: ADSPRPC: Queue receive intent for adsprpc glink channel
msm: vidc: Allocate bus vote data memory correctly
ARM: dts: msm: remove SDR104 workaround from SDM845 v2
soc: qcom: sleepstate: Enable/Disable IPCRTR wakelocks
ARM: dts: msm: Reduce CNOC bus voting for USB slave on SDM845
sched: Scheduler pl enhancement
spi: spi-geni-qcom: Set oversampling based on core revision
msm: ipa3: add a lock for active client logging
ARM: dts: msm: change VDD_APC1 CPR regulator compatible string for sdm845
clk: qcom: clk-rcg2: Allow DFS clients to scale the RCG while its enabled
ARM: dts: msm: Enable SMMU stage 1 bypass mode with USB on SDM845
power: pmic-voter: use force_val in rerun election
leds: qpnp-flash-v2: Calculate the IRES current dynamically
ASoC: codecs: Update Depends on macro for HDMI codec
ASoC: msm: Use CONFIG_SND_SOC_660 to compile machine driver
msm: kgsl: Dump the A6XX VBIF debugbus correctly
sched: walt: Add CFS_BANDWIDTH support
cfg80211: Add macros to indicate backport support for FILS
cfg80211: Add support for FILS shared key authentication offload
cfg80211: Use a structure to pass connect response params
wireless: define cipher/AKM suites using a macro
cfg80211: Fix documentation for connect result
msm: wlan: Define CFG80211_CONNECT_TIMEOUT_REASON_CODE
cfg80211: Specify the reason for connect timeout
SoC: msm: audio-effects: return directly to avoid integer overflow
msm: vidc: Add HFI interfaces for TME support
msm: ADSPRPC: Null check for file session context
ARM: dts: msm: Add support for CDSP PIL on sdm670
ARM: dts: msm: Add support for Venus PIL on sdm670
ARM: dts: msm: Add priority to QMP device tree on sdm670
ARM: dts: msm: add spss_utils to sdm845 v2
coresight-ost: switch to no log api for STM device writes
msm: vidc: Skip cache invalidating extradata buffer
sched: walt: move the cumulative window demand updates to enqueue
sched: walt: fix cumulative window demand update bugs
sched: walt: refactor the walt stats update code
sched: remove "hmp" references in the code
defconfig: Enable sysmon communication for SDM845
dtc: add integer overflow checks in fdt header
drm/msm/sde: modify pitch verification condition for linear format
drivers: mailbox: qti-tcs: increase debug verbosity
msm: kgsl: Don't signal the timeline if its refcount is zero
ASoC: msm: Add support for sdm670 soundcard
msm: kgsl: Prevent a deadlock when removing debugfs nodes
diag: Flush control workqueue immediately on channel close
ARM: dts: msm: Remove WLED short circuit properties for PM660
drm/msm/dp: add input validation for bpc function
drm/msm/hdcp1x: add support for HDCP 1.x
drm/msm/dp: add a separate header for register definitions
drm/msm/dp: add support for HDCP 2.2
coresight-tmc: add support to configure flush and reset CTIs
coresight: add support to read cti data
Linux 4.9.40
alarmtimer: don't rate limit one-shot timers
tracing: Fix kmemleak in instance_rmdir
PM / Domains: defer dev_pm_domain_set() until genpd->attach_dev succeeds if present
reiserfs: Don't clear SGID when inheriting ACLs
spmi: Include OF based modalias in device uevent
of: device: Export of_device_{get_modalias, uvent_modalias} to modules
acpi/nfit: Fix memory corruption/Unregister mce decoder on failure
ovl: fix random return value on mount
hfsplus: Don't clear SGID when inheriting ACLs
mlx5: Avoid that mlx5_ib_sg_to_klms() overflows the klms[] array
drm/mst: Avoid processing partially received up/down message transactions
drm/mst: Avoid dereferencing a NULL mstb in drm_dp_mst_handle_up_req()
drm/mst: Fix error handling during MST sideband message reception
RDMA/core: Initialize port_num in qp_attr
ceph: fix race in concurrent readdir
staging: lustre: ko2iblnd: check copy_from_iter/copy_to_iter return code
staging: sm750fb: avoid conflicting vesafb
staging: comedi: ni_mio_common: fix AO timer off-by-one regression
staging: rtl8188eu: add TL-WN722N v2 support
Revert "perf/core: Drop kernel samples even though :u is specified"
perf annotate: Fix broken arrow at row 0 connecting jmp instruction to its target
iser-target: Avoid isert_conn->cm_id dereference in isert_login_recv_done
target: Fix COMPARE_AND_WRITE caw_sem leak during se_cmd quiesce
udf: Fix deadlock between writeback and udf_setsize()
NFS: only invalidate dentrys that are clearly invalid.
sunrpc: use constant time memory comparison for mac
IB/core: Namespace is mandatory input for address resolution
IB/iser: Fix connection teardown race condition
Input: i8042 - fix crash at boot time
MIPS: Fix a typo: s/preset/present/ in r2-to-r6 emulation error message
MIPS: Send SIGILL for R6 branches in `__compute_return_epc_for_insn'
MIPS: Send SIGILL for linked branches in `__compute_return_epc_for_insn'
MIPS: Rename `sigill_r6' to `sigill_r2r6' in `__compute_return_epc_for_insn'
MIPS: Send SIGILL for BPOSGE32 in `__compute_return_epc_for_insn'
MIPS: math-emu: Prevent wrong ISA mode instruction emulation
MIPS: Fix unaligned PC interpretation in `compute_return_epc'
MIPS: Actually decode JALX in `__compute_return_epc_for_insn'
MIPS: Save static registers before sysmips
MIPS: Fix MIPS I ISA /proc/cpuinfo reporting
x86/ioapic: Pass the correct data to unmask_ioapic_irq()
x86/acpi: Prevent out of bound access caused by broken ACPI tables
Revert "ACPI / EC: Enable event freeze mode..." to fix a regression
ACPI / EC: Drop EC noirq hooks to fix a regression
ubifs: Don't leak kernel memory to the MTD
MIPS: Negate error syscall return in trace
MIPS: Fix mips_atomic_set() with EVA
MIPS: Fix mips_atomic_set() retry condition
ftrace: Fix uninitialized variable in match_records()
nvme-rdma: remove race conditions from IB signalling
vfio: New external user group/file match
vfio: Fix group release deadlock
ovl: drop CAP_SYS_RESOURCE from saved mounter's credentials
drm/ttm: Fix use-after-free in ttm_bo_clean_mm
f2fs: Don't clear SGID when inheriting ACLs
f2fs: sanity check size of nat and sit cache
xfs: Don't clear SGID when inheriting ACLs
ipmi:ssif: Add missing unlock in error branch
ipmi: use rcu lock around call to intf->handlers->sender()
drm/radeon: Fix eDP for single-display iMac10,1 (v2)
drm/radeon/ci: disable mclk switching for high refresh rates (v2)
drm/amd/amdgpu: Return error if initiating read out of range on vram
s390/syscalls: Fix out of bounds arguments access
Raid5 should update rdev->sectors after reshape
ext2: Don't clear SGID when inheriting ACLs
libnvdimm: fix badblock range handling of ARS range
libnvdimm, btt: fix btt_rw_page not returning errors
cx88: Fix regression in initial video standard setting
x86/xen: allow userspace access during hypercalls
md: don't use flush_signals in userspace processes
usb: renesas_usbhs: gadget: disable all eps when the driver stops
usb: renesas_usbhs: fix usbhsc_resume() for !USBHSF_RUNTIME_PWCTRL
USB: cdc-acm: add device-id for quirky printer
usb: storage: return on error to avoid a null pointer dereference
mxl111sf: Fix driver to use heap allocate buffers for USB messages
xhci: Bad Ethernet performance plugged in ASM1042A host
xhci: Fix NULL pointer dereference when cleaning up streams for removed host
xhci: fix 20000ms port resume timeout
ipvs: SNAT packet replies only for NATed connections
PCI/PM: Restore the status of PCI devices across hibernation
PCI: rockchip: Use normal register bank for config accessors
PCI: Work around poweroff & suspend-to-RAM issue on Macbook Pro 11
af_key: Fix sadb_x_ipsecrequest parsing
powerpc/mm/radix: Properly clear process table entry
powerpc/asm: Mark cr0 as clobbered in mftb()
powerpc: Fix emulation of mfocrf in emulate_step()
powerpc: Fix emulation of mcrf in emulate_step()
powerpc/64: Fix atomic64_inc_not_zero() to return an int
powerpc/pseries: Fix passing of pp0 in updatepp() and updateboltedpp()
xen/scsiback: Fix a TMR related use-after-free
iscsi-target: Add login_keys_workaround attribute for non RFC initiators
scsi: Add STARGET_CREATED_REMOVE state to scsi_target_state
scsi: ses: do not add a device to an enclosure if enclosure_add_links() fails.
PM / Domains: Fix unsafe iteration over modified list of domains
PM / Domains: Fix unsafe iteration over modified list of domain providers
PM / Domains: Fix unsafe iteration over modified list of device links
ASoC: compress: Derive substream from stream based on direction
igb: Explicitly select page 0 at initialization
btrfs: Don't clear SGID when inheriting ACLs
wlcore: fix 64K page support
Bluetooth: use constant time memory comparison for secret values
perf intel-pt: Clear FUP flag on error
perf intel-pt: Use FUP always when scanning for an IP
perf intel-pt: Ensure never to set 'last_ip' when packet 'count' is zero
perf intel-pt: Fix last_ip usage
perf intel-pt: Ensure IP is zero when state is INTEL_PT_STATE_NO_IP
perf intel-pt: Fix missing stack clear
perf intel-pt: Improve sample timestamp
perf intel-pt: Move decoder error setting into one condition
NFC: Add sockaddr length checks before accessing sa_family in bind handlers
nfc: Fix the sockaddr length sanitization in llcp_sock_connect
nfc: Ensure presence of required attributes in the activate_target handler
NFC: nfcmrvl: fix firmware-management initialisation
NFC: nfcmrvl: use nfc-device for firmware download
NFC: nfcmrvl: do not use device-managed resources
NFC: nfcmrvl_uart: add missing tty-device sanity check
NFC: fix broken device allocation
ath9k: fix an invalid pointer dereference in ath9k_rng_stop()
ath9k: fix tx99 bus error
ath9k: fix tx99 use after free
thermal: cpu_cooling: Avoid accessing potentially freed structures
thermal: max77620: fix device-node reference imbalance
s5p-jpeg: don't return a random width/height
dm mpath: cleanup -Wbool-operation warning in choose_pgpath()
ir-core: fix gcc-7 warning on bool arithmetic
disable new gcc-7.1.1 warnings for now
drm/msm/sde: handle retire fence during late ctl_start_irq
ARM: dts: msm: Add crypto smr-masks for sdm845
qce50: Add support for IOMMU S1 translation
usb: core: Honor device preferred configuration
ARM: RTIC 3.0: Enabling MPGen
Use %zu to print resid (size_t).
ARM: dts: msm: Reflect updates to the GCC clock frequency plan for SDM845
ASoC: msm: qdsp6v2: Open unique COPP port for concurrent ULL streams
mmc: sdhci-msm: consider clock frequency above 200MHz during DLL config
clk: qcom: gcc-sdm845: Reflect updates to the GCC clock frequency plan
usb: dwc3-msm: Ensure separate EUD extcon dev is used
drivers: mailbox: qti-tcs: add IPC logging support
msm: vidc: Update extradata plane size during valid extradata index
ARM: dts: msm: Add TSPP smr-masks for sdm845
media: broadcast: tspp: Add support for IOMMU S1 translation
diag: Free the read workqueue structure to avoid memory leak
ASoC: sdm845: add mixer control for MultiMedia5_RX QOS Vote
mm: add preempt points into __purge_vmap_area_lazy()
mm: mark all calls into the vmalloc subsystem as potentially sleeping
mm: add vfree_atomic()
mm: turn vmap_purge_lock into a mutex
mm: refactor __purge_vmap_area_lazy()
mm: remove free_unmap_vmap_area_addr()
mm: remove free_unmap_vmap_area_noflush()
defconfig: sdm670: Enable debugfs client for QMP
ARM: dts: msm: Add QMP debugfs client for sdm670
sched: remove the unused HMP specific code
sched: don't use preprocessor directives inside a macro
fuse: Add support for shortcircuited read/write for files
drm/msm: fix typo when enabling rsc debug bus
ARM: dts: msm: add device node for MSM HDCP driver on SDM845
drivers/misc: add HDCP 2.2 driver
drm/msm/sde: fix typo in sde QoS settings calculation
msm: ion: Fix crash when CP flags are none
drm/msm/sde: disable fast clear bit for ubwc with no alpha
icnss: Consolidate logging message
msm: msm_bus: limit max chars read by sscanf
icnss: Set crash state for PDR
usb: pd: start USB host mode with DR_SWAP when current_dr is UFP
diag: Add proper checks to fix possible out-of-bound issue
diag: Add protection while processing non-hdlc packets
diag: Fix to check for command length size
ANDROID: keychord: Fix a slab out-of-bounds read.
seemp: adjust hypervisor rooting report format
drm/msm: reduce sde evt32 logs to trace more commits
clk: qcom: gcc-sdm845: Keep the gcc_aggre_noc_pcie_tbu_clk enabled
ARM: dts: msm: update panel jitter for command mode panels
drm/msm/sde: update autorefresh enable/disable support
power: qpnp-fg-gen3: add DMA support for accessing FG SRAM
clk: qcom: clk-regmap: Add additional check for devm_clk_register_regmap
clk: Add additional checking
msm: vidc: Add support for decoder STOP command
pinctrl: qcom: Update irq handle for GPIO pins
mm: process reclaim: skip locked vmas
mm: avoid taking zone lock in pagetypeinfo_showmixed()
techpack: add tech package support
ASoC: sdm660: Initialize codec_reg_done to false
Asoc: sdm660: Move mbhc_hs_detect to late_probe
scsi: ufs: Serialise ufs clock gating and ungating
scsi: ufs: fix unclocked register access during UFS card detection
msm: ipa4: add HAL support for statistics
msm: ipa4: make rule_id unique across tables
ASoC: audio: add APIs to query for AVS version
security: mark LSM hooks as __ro_after_init
security: introduce CONFIG_SECURITY_WRITABLE_HOOKS
msm: vidc: Update input extradata min host buffer count
clk: qcom: clk-cpu-osm: Move the speedbin logic to after resource init
arm64: defconfig: enable USB_LINK_LAYER_TEST on sdm845
thermal: tsens: Update of_thermal registration
usb: core: Add support to handle multi config audio device
usb: core: Add support to parse config summary capability descriptors
ARM: dts: msm: Update glink and smp2p device nodes for ADSP of SDM670
cfg80211: Define macro for report better BSS in sched scan
cfg80211: Add support to sched scan to report better BSSs
cfg80211: Define macro to indicate support for Random TA for PA frames
cfg80211: Add support for randomizing TA of Public Action frames
cfg80211: size various nl80211 messages correctly
cfg80211: Define macro to indicate support for update connect params
cfg80211: Add support to update connection parameters
cfg80211: configure multicast to unicast for AP interfaces
cfg80211: Add KEK/nonces for FILS association frames
cfg80211: Add Fast Initial Link Setup (FILS) auth algs
cfg80211: Add feature flag for Fast Initial Link Setup (FILS) as STA
cfg80211: Rename SAE_DATA to more generic AUTH_DATA
cfg80211: validate beacon int as part of iface combinations
cfg80211: fix beacon interval in interface combination iteration
cfg80211: fix possible memory leak in cfg80211_iter_combinations()
net: core: neighbour: Change the print format for addresses
qcom: scm: remove printing input arguments
ARM: dts: msm: Avoid preparing L3 clock from devfreq for SDM845
drivers: qcom: rpmh: Cache write_passthru sleep/wake requests
drivers: mailbox: qti-tcs: various minor fixes
drm/msm: remove extra 1.6 GBps added to the ab vote
UPSTREAM: af_key: Fix sadb_x_ipsecrequest parsing
usb: pd: force disconnect upon unexpected SRC->SNK transition
ANDROID: lowmemorykiller: Add tgid to kill message
mmc: sdhci-mmc-ice: Factor out ice_cfg_start from sdhci_msm_ice_cfg
arm: dma-mapping: add dma mapper for io-pgtable-fast for 32 bit
arm: dma_mapping: Support for DOMAIN_ATTR_S1_BYPASS attribute
msm: kgsl: Remove context debugfs nodes when detaching it
ASoC: msm: add support for MI2S slave mode on SDM845
drm/msm: add validation for secure transition
regulator: cpr3-regulator: stop CPRh controller registration if initialized
Revert "ANDROID: proc: smaps: Allow smaps access for CAP_SYS_RESOURCE"
drm/msm/sde: unmap buffers when context is detached
soc: qom: add support to export socinfo id string
ASoC: msm: qdsp6v2: Initialize variables before use
4.9.39
kvm: vmx: allow host to access guest MSR_IA32_BNDCFGS
kvm: vmx: Check value written to IA32_BNDCFGS
kvm: x86: Guest BNDCFGS requires guest MPX support
kvm: vmx: Do not disable intercepts for BNDCFGS
tracing: Use SOFTIRQ_OFFSET for softirq dectection for more accurate results
PM / QoS: return -EINVAL for bogus strings
PM / wakeirq: Convert to SRCU
sched/topology: Fix overlapping sched_group_mask
sched/topology: Optimize build_group_mask()
sched/topology: Fix building of overlapping sched-groups
sched/fair, cpumask: Export for_each_cpu_wrap()
Revert "sched/core: Optimize SCHED_SMT"
crypto: caam - fix signals handling
crypto: caam - properly set IV after {en,de}crypt
crypto: sha1-ssse3 - Disable avx2
crypto: atmel - only treat EBUSY as transient if backlog
crypto: talitos - Extend max key length for SHA384/512-HMAC and AEAD
mm: fix overflow check in expand_upwards()
selftests/capabilities: Fix the test_execve test
mnt: Make propagate_umount less slow for overlapping mount propagation trees
mnt: In propgate_umount handle visiting mounts in any order
mnt: In umount propagation reparent in a separate pass
nvmem: core: fix leaks on registration errors
rcu: Add memory barriers for NOCB leader wakeup
vt: fix unchecked __put_user() in tioclinux ioctls
ARM64: dts: marvell: armada37xx: Fix timer interrupt specifiers
exec: Limit arg stack to at most 75% of _STK_LIM
s390: reduce ELF_ET_DYN_BASE
powerpc: move ELF_ET_DYN_BASE to 4GB / 4MB
arm64: move ELF_ET_DYN_BASE to 4GB / 4MB
arm: move ELF_ET_DYN_BASE to 4MB
binfmt_elf: use ELF_ET_DYN_BASE only for PIE
checkpatch: silence perl 5.26.0 unescaped left brace warnings
fs/dcache.c: fix spin lockup issue on nlru->lock
mm/list_lru.c: fix list_lru_count_node() to be race free
kernel/extable.c: mark core_kernel_text notrace
thp, mm: fix crash due race in MADV_FREE handling
tools/lib/lockdep: Reduce MAX_LOCK_DEPTH to avoid overflowing lock_chain/: Depth
parisc/mm: Ensure IRQs are off in switch_mm()
parisc: DMA API: return error instead of BUG_ON for dma ops on non dma devs
parisc: use compat_sys_keyctl()
parisc: Report SIGSEGV instead of SIGBUS when running out of stack
irqchip/gic-v3: Fix out-of-bound access in gic_set_affinity
cfg80211: Check if NAN service ID is of expected size
cfg80211: Check if PMKID attribute is of expected size
cfg80211: Validate frequencies nested in NL80211_ATTR_SCAN_FREQUENCIES
cfg80211: Define nla_policy for NL80211_ATTR_LOCAL_MESH_POWER_MODE
sfc: don't read beyond unicast address list
brcmfmac: Fix glom_skb leak in brcmf_sdiod_recv_chain
brcmfmac: Fix a memory leak in error handling path in 'brcmf_cfg80211_attach'
brcmfmac: fix possible buffer overflow in brcmf_cfg80211_mgmt_tx()
rds: tcp: use sock_create_lite() to create the accept socket
vrf: fix bug_on triggered by rx when destroying a vrf
net: ipv6: Compare lwstate in detecting duplicate nexthops
net: core: Fix slab-out-of-bounds in netdev_stats_to_stats64
vxlan: fix hlist corruption
ipv6: dad: don't remove dynamic addresses if link is down
net/mlx5e: Fix TX carrier errors report in get stats ndo
liquidio: fix bug in soft reset failure detection
net/mlx5: Cancel delayed recovery work when unloading the driver
net: handle NAPI_GRO_FREE_STOLEN_HEAD case also in napi_frags_finish()
bpf: prevent leaking pointer via xadd on unpriviledged
rocker: move dereference before free
bridge: mdb: fix leak on complete_info ptr on fail path
net: prevent sign extension in dev_get_stats()
tcp: reset sk_rx_dst in tcp_disconnect()
net: dp83640: Avoid NULL pointer dereference.
ipv6: avoid unregistering inet6_dev for loopback
net/phy: micrel: configure intterupts after autoneg workaround
net: sched: Fix one possible panic when no destroy callback
net_sched: fix error recovery at qdisc creation
xen-netfront: Rework the fix for Rx stall during OOM and network stress
defconfig: arm64: Enable debugfs client for QMP
ANDROID: android-verity: mark dev as rw for linear target
usb: pd: Add functionality to allow DP client to request DP mode
ANDROID: sdcardfs: Remove unnecessary lock
media: dvb-core: dmxdev: Add braces around suspicious indent
msm: sde: fix unaligned access problem
msm: sde: fix to handle invalid format in sde rotator
msm: sde: Remove output fence object after user request completed
ANDROID: binder: don't check prio permissions on restore.
ARM: dts: msm: Add display RSC device bindings for sdm670
msm: kgsl: Trigger preemption from command complete interrupt
drm/msm/sde: Update log for getting default dither config
drm/msm: move msm property dirty list to atomic state
msm:ipa: using rate limit api for ioctl calls
Add BINDER_GET_NODE_DEBUG_INFO ioctl
ANDROID: binder: add RT inheritance flag to node.
ANDROID: binder: improve priority inheritance.
ANDROID: binder: add min sched_policy to node.
ANDROID: binder: add support for RT prio inheritance.
ANDROID: binder: push new transactions to waiting threads.
ANDROID: binder: remove proc waitqueue
drivers: edac: Add PM notifier to check ECC during CPU_EXIT_PM
drm/msm: fix Y420CMDB EDID block parsing
clk: qcom: mdss: Fix DSI clock divider configuration
drm/msm/dsi-staging: enable frame MISR on DSI
drivers: thermal: Add trace events for thermal device update events
drm/msm/sde: add support to attach/detach context banks
ARM: dts: msm: add physical dimensions for panels on SDM845
soc: qcom: glink: Remove magic number logic
soc: qcom: glink: Add new APIs to toggle RX thread priority
soc: qcom: glink: Move get reference to valid location
ARM: dts: msm: Enable GPU DCVS on SDM845
ASoC: wcd: remove unused audio external clock driver
msm: kgsl: Make sure regulators are ON before GPU clocks are forced on
msm: kgsl: Defer issue commands to worker thread
msm: kgsl: convert some workqueues to use kthreads.
msm: kgsl: Reset busy data after soft reset
msm: kgsl: Do not set rate before turning off GMU clock
msm: kgsl: Fix the mmu pagefault tracepoint
msm: kgsl: Remove the A6XX ISDB regwrite
genirq: Use irq_set_affinity_locked to change irq affinity
msm: kgsl: Ignore stale size when allocating pages
Change-Id: Ib02736f2dc5315b82f9620188bf428dbb006ab3a
Signed-off-by: Abhijit Trivedi <abhijitt@codeaurora.org>
diff --git a/Documentation/ABI/testing/sysfs-bus-usb-lvstest b/Documentation/ABI/testing/sysfs-bus-usb-lvstest
index 5151290..ee0046d 100644
--- a/Documentation/ABI/testing/sysfs-bus-usb-lvstest
+++ b/Documentation/ABI/testing/sysfs-bus-usb-lvstest
@@ -45,3 +45,16 @@
Description:
Write to this node to issue "U3 exit" for Link Layer
Validation device. It is needed for TD.7.36.
+
+What: /sys/bus/usb/devices/.../enable_compliance
+Date: July 2017
+Description:
+ Write to this node to set the port to compliance mode to test
+ with Link Layer Validation device. It is needed for TD.7.34.
+
+What: /sys/bus/usb/devices/.../warm_reset
+Date: July 2017
+Description:
+ Write to this node to issue "Warm Reset" for Link Layer Validation
+ device. It may be needed to properly reset an xHCI 1.1 host port if
+ compliance mode needed to be explicitly enabled.
diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt b/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt
index c3c8212..cc4c3cc 100644
--- a/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt
+++ b/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt
@@ -233,8 +233,6 @@
configuration registers for the Performance cluster.
The array must contain exactly three elements.
- corresponding CPRh device.
-
- qcom,perfcl-apcs-mem-acc-threshold-voltage
Usage: optional
Value type: <u32>
@@ -245,6 +243,27 @@
the MEM ACC threshold voltage specified for the
corresponding CPRh device.
+- qcom,l3-memacc-level-vc-binX
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: Array which defines the NOM and TURBO VCs for the L3 clock
+ on that BIN part.
+ The array must contain exactly two elements.
+
+- qcom,pwrcl-memacc-level-vc-binX
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: Array which defines the NOM and TURBO VCs for the Power
+ cluster clock on that BIN part.
+ The array must contain exactly two elements.
+
+- qcom,perfcl-memacc-level-vc-binX
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: Array which defines the NOM and TURBO VCs for the
+ Performance cluster clock on that BIN part.
+ The array must contain exactly two elements.
+
- qcom,apcs-cbc-addr
Usage: required
Value type: <prop-encoded-array>
@@ -483,6 +502,18 @@
< 1881600000 0x404c1462 0x00004e4e 0x2 21 >,
< 1958400000 0x404c1566 0x00005252 0x3 22 >;
+ qcom,l3-memacc-level-vc-bin0 = <7 63>;
+ qcom,l3-memacc-level-vc-bin1 = <7 9>;
+ qcom,l3-memacc-level-vc-bin2 = <7 9>;
+
+ qcom,pwrcl-memacc-level-vc-bin0 = <12 63>;
+ qcom,pwrcl-memacc-level-vc-bin1 = <12 17>;
+ qcom,pwrcl-memacc-level-vc-bin2 = <12 17>;
+
+ qcom,perfcl-memacc-level-vc-bin0 = <12 18>;
+ qcom,perfcl-memacc-level-vc-bin1 = <12 18>;
+ qcom,perfcl-memacc-level-vc-bin2 = <12 18>;
+
qcom,up-timer =
<1000 1000 1000>;
qcom,down-timer =
diff --git a/Documentation/devicetree/bindings/arm/msm/qsee_ipc_irq_bridge.txt b/Documentation/devicetree/bindings/arm/msm/qsee_ipc_irq_bridge.txt
new file mode 100644
index 0000000..442ad52
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/qsee_ipc_irq_bridge.txt
@@ -0,0 +1,30 @@
+Qualcomm Technologies, Inc. Secure Execution Environment IPC Interrupt Bridge
+
+[Root level node]
+Required properties:
+-compatible : should be "qcom,qsee-ipc-irq-bridge";
+
+[Second level nodes]
+qcom,qsee-ipc-irq-subsystem
+Required properties:
+-qcom,dev-name: the bridge device name
+-interrupt: IPC interrupt line from remote subsystem to QSEE
+-label : The name of this subsystem.
+
+Required properties if interrupt type is IRQ_TYPE_LEVEL_HIGH[4]:
+-qcom,rx-irq-clr : the register to clear the level triggered rx interrupt
+-qcom,rx-irq-clr-mask : the bitmask to clear the rx interrupt
+
+Example:
+
+ qcom,qsee_ipc_irq_bridge {
+ compatible = "qcom,qsee-ipc-irq-bridge";
+
+ qcom,qsee-ipc-irq-spss {
+ qcom,rx-irq-clr = <0x1d08008 0x4>;
+ qcom,rx-irq-clr-mask = <0x2>;
+ qcom,dev-name = "qsee_ipc_irq_spss";
+ interrupts = <0 349 4>;
+ label = "spss";
+ };
+ };
diff --git a/Documentation/devicetree/bindings/clock/qcom,aop-qmp.txt b/Documentation/devicetree/bindings/clock/qcom,aop-qmp.txt
index 231b8a3..37c48ad 100644
--- a/Documentation/devicetree/bindings/clock/qcom,aop-qmp.txt
+++ b/Documentation/devicetree/bindings/clock/qcom,aop-qmp.txt
@@ -2,7 +2,7 @@
------------------------------------------------------------------------
Required properties :
-- compatible : must be "qcom,aop-qmp-clk"
+- compatible : must be "qcom,aop-qmp-clk-v1" or "qcom,aop-qmp-clk-v2".
- #clock-cells : must contain 1
- mboxes : list of QMP mailbox phandle and channel identifier tuples.
- mbox-names: List of identifier strings for each mailbox channel.
@@ -10,7 +10,7 @@
Example :
clock_qdss: qcom,aopclk {
- compatible = "qcom,aop-qmp-clk";
+ compatible = "qcom,aop-qmp-clk-v1";
#clock-cells = <1>;
mboxes = <&qmp_aop 0>;
mbox-names = "qdss_clk";
diff --git a/Documentation/devicetree/bindings/clock/qcom,gpucc.txt b/Documentation/devicetree/bindings/clock/qcom,gpucc.txt
index f214c58..12676b7 100644
--- a/Documentation/devicetree/bindings/clock/qcom,gpucc.txt
+++ b/Documentation/devicetree/bindings/clock/qcom,gpucc.txt
@@ -4,7 +4,9 @@
Required properties :
- compatible : shall contain only one of the following:
"qcom,gpucc-sdm845",
- "qcom,gfxcc-sdm845"
+ "qcom,gpucc-sdm845-v2",
+ "qcom,gfxcc-sdm845",
+ "qcom,gfxcc-sdm845-v2"
- reg : shall contain base register offset and size.
- #clock-cells : shall contain 1.
diff --git a/Documentation/devicetree/bindings/crypto/msm/qcedev.txt b/Documentation/devicetree/bindings/crypto/msm/qcedev.txt
index c8077cb..051b315 100644
--- a/Documentation/devicetree/bindings/crypto/msm/qcedev.txt
+++ b/Documentation/devicetree/bindings/crypto/msm/qcedev.txt
@@ -20,6 +20,8 @@
- qcom,ce-hw-key : optional, indicates if the hardware supports use of HW KEY.
- qcom,support-core-clk-only : optional, indicates if the HW supports single crypto core clk.
- qcom,bsm-ee : optional, indicate the BAM EE value, changes from target to target. Default value is 1 if not specified.
+ - qcom,smmu-s1-bypass : Boolean flag to bypass SMMU stage 1 translation.
+ - iommus : A list of phandle and IOMMU specifier pairs that describe the IOMMU master interfaces of the device.
Example:
diff --git a/Documentation/devicetree/bindings/crypto/msm/qcrypto.txt b/Documentation/devicetree/bindings/crypto/msm/qcrypto.txt
index 3c8a79a..fa27198 100644
--- a/Documentation/devicetree/bindings/crypto/msm/qcrypto.txt
+++ b/Documentation/devicetree/bindings/crypto/msm/qcrypto.txt
@@ -40,6 +40,9 @@
required. For other targets such as fsm, they do not perform
bus scaling. It is not required for those targets.
+ - qcom,smmu-s1-bypass : Boolean flag to bypass SMMU stage 1 translation.
+ - iommus : A list of phandle and IOMMU specifier pairs that describe the IOMMU master interfaces of the device.
+
Example:
qcom,qcrypto@fd444000 {
diff --git a/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt
index cbe8378..32c31af 100644
--- a/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt
@@ -401,6 +401,24 @@
String that specifies the ctrl state for reading the panel status.
"dsi_lp_mode" = DSI low power mode
"dsi_hs_mode" = DSI high speed mode
+- qcom,mdss-dsi-lp1-command: An optional byte stream to request low
+ power mode on a panel
+- qcom,mdss-dsi-lp1-command-mode: String that specifies the ctrl state for
+ setting the panel power mode.
+ "dsi_lp_mode" = DSI low power mode
+ "dsi_hs_mode" = DSI high speed mode
+- qcom,mdss-dsi-lp2-command: An optional byte stream to request ultra
+ low power mode on a panel
+- qcom,mdss-dsi-lp2-command-mode: String that specifies the ctrl state for
+ setting the panel power mode.
+ "dsi_lp_mode" = DSI low power mode
+ "dsi_hs_mode" = DSI high speed mode
+- qcom,mdss-dsi-nolp-command: An optional byte stream to disable low
+ power and ultra low power panel modes
+- qcom,mdss-dsi-nolp-command-mode: String that specifies the ctrl state for
+ setting the panel power mode.
+ "dsi_lp_mode" = DSI low power mode
+ "dsi_hs_mode" = DSI high speed mode
- qcom,mdss-dsi-panel-status-check-mode:Specifies the panel status check method for ESD recovery.
"bta_check" = Uses BTA to check the panel status
"reg_read" = Reads panel status register to check the panel status
diff --git a/Documentation/devicetree/bindings/drm/msm/sde-dp.txt b/Documentation/devicetree/bindings/drm/msm/sde-dp.txt
index 790da12..e46fd5c 100644
--- a/Documentation/devicetree/bindings/drm/msm/sde-dp.txt
+++ b/Documentation/devicetree/bindings/drm/msm/sde-dp.txt
@@ -25,7 +25,46 @@
- qcom,aux-en-gpio: Specifies the aux-channel enable gpio.
- qcom,aux-sel-gpio: Specifies the aux-channel select gpio.
- qcom,usbplug-cc-gpio: Specifies the usbplug orientation gpio.
-- qcom,aux-cfg-settings: An array that specifies the DP AUX configuration settings.
+- qcom,aux-cfg0-settings: Specifies the DP AUX configuration 0 settings. The first
+ entry in this array corresponds to the register offset
+ within DP AUX, while the remaining entries indicate the
+ programmable values.
+- qcom,aux-cfg1-settings: Specifies the DP AUX configuration 1 settings. The first
+ entry in this array corresponds to the register offset
+ within DP AUX, while the remaining entries indicate the
+ programmable values.
+- qcom,aux-cfg2-settings: Specifies the DP AUX configuration 2 settings. The first
+ entry in this array corresponds to the register offset
+ within DP AUX, while the remaining entries indicate the
+ programmable values.
+- qcom,aux-cfg3-settings: Specifies the DP AUX configuration 3 settings. The first
+ entry in this array corresponds to the register offset
+ within DP AUX, while the remaining entries indicate the
+ programmable values.
+- qcom,aux-cfg4-settings: Specifies the DP AUX configuration 4 settings. The first
+ entry in this array corresponds to the register offset
+ within DP AUX, while the remaining entries indicate the
+ programmable values.
+- qcom,aux-cfg5-settings: Specifies the DP AUX configuration 5 settings. The first
+ entry in this array corresponds to the register offset
+ within DP AUX, while the remaining entries indicate the
+ programmable values.
+- qcom,aux-cfg6-settings: Specifies the DP AUX configuration 6 settings. The first
+ entry in this array corresponds to the register offset
+ within DP AUX, while the remaining entries indicate the
+ programmable values.
+- qcom,aux-cfg7-settings: Specifies the DP AUX configuration 7 settings. The first
+ entry in this array corresponds to the register offset
+ within DP AUX, while the remaining entries indicate the
+ programmable values.
+- qcom,aux-cfg8-settings: Specifies the DP AUX configuration 8 settings. The first
+ entry in this array corresponds to the register offset
+ within DP AUX, while the remaining entries indicate the
+ programmable values.
+- qcom,aux-cfg9-settings: Specifies the DP AUX configuration 9 settings. The first
+ entry in this array corresponds to the register offset
+ within DP AUX, while the remaining entries indicate the
+ programmable values.
- qcom,max-pclk-frequency-khz: An integer specifying the max. pixel clock in KHz supported by Display Port.
- qcom,dp-usbpd-detection: Phandle for the PMI regulator node for USB PHY PD detection.
- qcom,<type>-supply-entries: A node that lists the elements of the supply used by the a particular "type" of DSI module. The module "types"
@@ -49,7 +88,28 @@
controller. These pin configurations are installed in the pinctrl
device node. Refer to pinctrl-bindings.txt
+msm_ext_disp is a device which manages the interaction between external
+display interfaces, e.g. Display Port, and the audio subsystem.
+
+Optional properties:
+- qcom,ext-disp: phandle for msm-ext-display module
+- compatible: Must be "qcom,msm-ext-disp"
+
+[Optional child nodes]: These nodes are for devices which are
+dependent on msm_ext_disp. If msm_ext_disp is disabled then
+these devices will be disabled as well. Ex. Audio Codec device.
+
+- ext_disp_audio_codec: Node for Audio Codec.
+- compatible : "qcom,msm-ext-disp-audio-codec-rx";
+
Example:
+ ext_disp: qcom,msm-ext-disp {
+ compatible = "qcom,msm-ext-disp";
+ ext_disp_audio_codec: qcom,msm-ext-disp-audio-codec-rx {
+ compatible = "qcom,msm-ext-disp-audio-codec-rx";
+ };
+ };
+
sde_dp: qcom,dp_display@0{
cell-index = <0>;
compatible = "qcom,dp-display";
@@ -92,8 +152,18 @@
"ctrl_pixel_clk", "pixel_clk_rcg", "pixel_parent";
qcom,dp-usbpd-detection = <&pmi8998_pdphy>;
+ qcom,ext-disp = <&ext_disp>;
- qcom,aux-cfg-settings = [00 13 04 00 0a 26 0a 03 bb 03];
+ qcom,aux-cfg0-settings = [1c 00];
+ qcom,aux-cfg1-settings = [20 13 23 1d];
+ qcom,aux-cfg2-settings = [24 00];
+ qcom,aux-cfg3-settings = [28 00];
+ qcom,aux-cfg4-settings = [2c 0a];
+ qcom,aux-cfg5-settings = [30 26];
+ qcom,aux-cfg6-settings = [34 0a];
+ qcom,aux-cfg7-settings = [38 03];
+ qcom,aux-cfg8-settings = [3c bb];
+ qcom,aux-cfg9-settings = [40 03];
qcom,max-pclk-frequency-khz = <593470>;
pinctrl-names = "mdss_dp_active", "mdss_dp_sleep";
pinctrl-0 = <&sde_dp_aux_active &sde_dp_usbplug_cc_active>;
diff --git a/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt b/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt
index 3ad0986..641cc26 100644
--- a/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt
+++ b/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt
@@ -96,3 +96,7 @@
If ping pong split enabled, this time should not be higher
than two times the dsi link rate time.
If the property is not specified, then the default value is 14000 us.
+- qcom,dsi-phy-isolation-enabled: A boolean property enables the phy isolation from dsi
+ controller. This must be enabled for debugging purpose
+ only with simulator panel. It should not be enabled for
+ normal DSI panels.
diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
index 196f6f7..0f8dc27 100644
--- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt
+++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
@@ -96,6 +96,12 @@
retention. No cache invalidation operations involving asid
may be used.
+- qcom,deferred-regulator-disable-delay : The time delay for deferred regulator
+ disable in ms. In case of unmap call, regulator is
+ enabled/disabled. This may introduce additional delay. For
+ clients who do not detach, it's not possible to keep regulator
+ vote while smmu is attached. Type is <u32>.
+
- clocks : List of clocks to be used during SMMU register access. See
Documentation/devicetree/bindings/clock/clock-bindings.txt
for information about the format. For each clock specified
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-flash.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-flash.txt
deleted file mode 100644
index ed1ddf5..0000000
--- a/Documentation/devicetree/bindings/leds/leds-qpnp-flash.txt
+++ /dev/null
@@ -1,180 +0,0 @@
-Qualcomm Technologies PNP Flash LED
-
-QPNP (Qualcomm Technologies Plug N Play) Flash LED (Light
-Emitting Diode) driver is used to provide illumination to
-camera sensor when background light is dim to capture good
-picture. It can also be used for flashlight/torch application.
-It is part of PMIC on Qualcomm Technologies reference platforms.
-The PMIC is connected to the host processor via SPMI bus.
-
-Required properties:
-- compatible : should be "qcom,qpnp-flash-led"
-- reg : base address and size for flash LED modules
-
-Optional properties:
-- qcom,headroom : headroom to use. Values should be 250, 300,
- 400 and 500 in mV.
-- qcom,startup-dly : delay before flashing after flash executed.
- Values should 10, 32, 64, and 128 in us.
-- qcom,clamp-curr : current to clamp at when voltage droop happens.
- Values are in integer from 0 to 1000 inclusive,
- indicating 0 to 1000 mA.
-- qcom,self-check-enabled : boolean type. self fault check enablement
-- qcom,thermal-derate-enabled : boolean type. derate enablement when module
- temperature reaches threshold
-- qcom,thermal-derate-threshold : thermal threshold for derate. Values
- should be 95, 105, 115, 125 in C.
-- qcom,thermal-derate-rate : derate rate when module temperature
- reaches threshold. Values should be
- "1_PERCENT", "1P25_PERCENT", "2_PERCENT",
- "2P5_PERCENT", "5_PERCENT" in string.
-- qcom,current-ramp-enabled : boolean type. stepped current ramp enablement
-- qcom,ramp-up-step : current ramp up rate. Values should be
- "0P2US", "0P4US", "0P8US", "1P6US", "3P3US",
- "6P7US", "13P5US", "27US".
-- qcom,ramp-dn-step : current ramp down rate. Values should be
- "0P2US", "0P4US", "0P8US", "1P6US", "3P3US",
- "6P7US", "13P5US", "27US".
-- qcom,vph-pwr-droop-enabled : boolean type. VPH power droop enablement. Enablement
- allows current clamp when phone power drops below
- pre-determined threshold
-- qcom,vph-pwr-droop-threshold : VPH power threshold for module to clamp current.
- Values are 2500 - 3200 in mV with 100 mV steps.
-- qcom,vph-pwr-droop-debounce-time : debounce time for module to confirm a voltage
- droop is happening. Values are 0, 10, 32, 64
- in us.
-- qcom,pmic-charger-support : Boolean type. This tells if flash utilizes charger boost
- support
-- qcom,headroom-sense-ch0-enabled: Boolean type. This configures headroom sensing enablement
- for LED channel 0
-- qcom,headroom-sense-ch1-enabled: Boolean type. This configures headroom sensing enablement
- for LED channel 1
-- qcom,power-detect-enabled : Boolean type. This enables driver to get maximum flash LED
- current at current battery level to avoid intensity clamp
- when battery voltage is low
-- qcom,otst2-moduled-enabled : Boolean type. This enables driver to enable MASK to support
- OTST2 connection.
-- qcom,follow-otst2-rb-disabled : Boolean type. This allows driver to reset/deset module.
- By default, driver resets module. This entry allows driver to
- bypass reset module sequence.
-- qcom,die-current-derate-enabled: Boolean type. This enables driver to get maximum flash LED
- current, based on PMIC die temperature threshold to
- avoid significant current derate from hardware. This property
- is not needed if PMIC is older than PMI8994v2.0.
-- qcom,die-temp-vadc : VADC channel source for flash LED. This property is not
- needed if PMIC is older than PMI8994v2.0.
-- qcom,die-temp-threshold : Integer type array for PMIC die temperature threshold.
- Array should have at least one value. Values should be in
- celcius. This property is not needed if PMIC is older than
- PMI8994v2.0.
-- qcom,die-temp-derate-current : Integer type arrray for PMIC die temperature derate
- current. Array should have at least one value. Values
- should be in mA. This property is not needed if PMIC is older
- than PMI8994v2.0.
-
-Required properties inside child node. Chile node contains settings for each individual LED.
-Each LED hardware needs a node for itself and a switch node to control brightness.
-For the purpose of turning on/off LED and better regulator control, "led:switch" node
-is introduced. "led:switch" acquires several existing properties from other nodes for
-operational simplification. For backward compatibility purpose, switch node can be optional:
-- label : type of led that will be used, either "flash" or "torch".
-- qcom,led-name : name of the LED. Accepted values are "led:flash_0",
- "led:flash_1", "led:torch_0", "led:torch_1"
-- qcom,default-led-trigger : trigger for the camera flash and torch. Accepted values are
- "flash0_trigger", "flash1_trigger", "torch0_trigger", torch1_trigger"
-- qcom,id : enumerated ID for each physical LED. Accepted values are "0",
- "1", etc..
-- qcom,max-current : maximum current allowed on this LED. Valid values should be
- integer from 0 to 1000 inclusive, indicating 0 to 1000 mA.
-- qcom,pmic-revid : PMIC revision id source. This property is needed for PMI8996
- revision check.
-
-Optional properties inside child node:
-- qcom,current : default current intensity for LED. Accepted values should be
- integer from 0 t 1000 inclusive, indicating 0 to 1000 mA.
-- qcom,duration : Duration for flash LED. When duration time expires, hardware will turn off
- flash LED. Values should be from 10 ms to 1280 ms with 10 ms incremental
- step. Not applicable to torch. It is required for LED:SWITCH node to handle
- LED used as flash.
-- reg<n> : reg<n> (<n> represents number. eg 0,1,2,..) property is to add support for
- multiple power sources. It includes two properties regulator-name and max-voltage.
- Required property inside regulator node:
- - regulator-name : This denotes this node is a regulator node and which
- regulator to use.
- Optional property inside regulator node:
- - max-voltage : This specifies max voltage of regulator. Some switch
- or boost regulator does not need this property.
-
-Example:
- qcom,leds@d300 {
- compatible = "qcom,qpnp-flash-led";
- status = "okay";
- reg = <0xd300 0x100>;
- label = "flash";
- qcom,headroom = <500>;
- qcom,startup-dly = <128>;
- qcom,clamp-curr = <200>;
- qcom,pmic-charger-support;
- qcom,self-check-enabled;
- qcom,thermal-derate-enabled;
- qcom,thermal-derate-threshold = <80>;
- qcom,thermal-derate-rate = "4_PERCENT";
- qcom,current-ramp-enabled;
- qcom,ramp_up_step = "27US";
- qcom,ramp_dn_step = "27US";
- qcom,vph-pwr-droop-enabled;
- qcom,vph-pwr-droop-threshold = <3200>;
- qcom,vph-pwr-droop-debounce-time = <10>;
- qcom,headroom-sense-ch0-enabled;
- qcom,headroom-sense-ch1-enabled;
- qcom,die-current-derate-enabled;
- qcom,die-temp-vadc = <&pmi8994_vadc>;
- qcom,die-temp-threshold = <85 80 75 70 65>;
- qcom,die-temp-derate-current = <400 800 1200 1600 2000>;
- qcom,pmic-revid = <&pmi8994_revid>;
-
- pm8226_flash0: qcom,flash_0 {
- label = "flash";
- qcom,led-name = "led:flash_0";
- qcom,default-led-trigger =
- "flash0_trigger";
- qcom,max-current = <1000>;
- qcom,id = <0>;
- qcom,duration = <1280>;
- qcom,current = <625>;
- };
-
- pm8226_torch: qcom,torch_0 {
- label = "torch";
- qcom,led-name = "led:torch_0";
- qcom,default-led-trigger =
- "torch0_trigger";
- boost-supply = <&pm8226_chg_boost>;
- qcom,max-current = <200>;
- qcom,id = <0>;
- qcom,current = <120>;
- qcom,max-current = <200>;
- reg0 {
- regulator-name =
- "pm8226_chg_boost";
- max-voltage = <3600000>;
- };
- };
-
- pm8226_switch: qcom,switch {
- lable = "switch";
- qcom,led-name = "led:switch";
- qcom,default-led-trigger =
- "switch_trigger";
- qcom,id = <2>;
- qcom,current = <625>;
- qcom,duration = <1280>;
- qcom,max-current = <1000>;
- reg0 {
- regulator-name =
- "pm8226_chg_boost";
- max-voltage = <3600000>;
- };
- };
- };
-
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt
index 1e6aac5..42e97f7 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt
@@ -78,6 +78,8 @@
- qcom,lcd-psm-ctrl : A boolean property to specify if PSM needs to be
controlled dynamically when WLED module is enabled
or disabled.
+- qcom,auto-calibration-enable : A boolean property which enables auto-calibration
+ of the WLED sink configuration.
Optional properties if 'qcom,disp-type-amoled' is mentioned in DT:
- qcom,loop-comp-res-kohm : control to select the compensation resistor in kohm. default is 320.
diff --git a/Documentation/devicetree/bindings/msm_hdcp/msm_hdcp.txt b/Documentation/devicetree/bindings/msm_hdcp/msm_hdcp.txt
new file mode 100644
index 0000000..8d5f55d
--- /dev/null
+++ b/Documentation/devicetree/bindings/msm_hdcp/msm_hdcp.txt
@@ -0,0 +1,14 @@
+MSM HDCP driver
+
+Standalone driver managing HDCP related communications
+between TZ and HLOS for MSM chipset.
+
+Required properties:
+
+compatible = "qcom,msm-hdcp";
+
+Example:
+
+qcom_msmhdcp: qcom,msm_hdcp {
+ compatible = "qcom,msm-hdcp";
+};
diff --git a/Documentation/devicetree/bindings/platform/msm/msm_tspp.txt b/Documentation/devicetree/bindings/platform/msm/msm_tspp.txt
index 072f920..b4ce7cb 100644
--- a/Documentation/devicetree/bindings/platform/msm/msm_tspp.txt
+++ b/Documentation/devicetree/bindings/platform/msm/msm_tspp.txt
@@ -23,6 +23,8 @@
- qcom, msm_bus,num_paths: The paths for source and destination ports
- qcom, msm_bus,vectors: Vectors for bus topology.
- pinctrl-names: Names for the TSIF mode configuration to specify which TSIF interface is active.
+- qcom,smmu-s1-bypass : Boolean flag to bypass SMMU stage 1 translation.
+- iommus : A list of phandle and IOMMU specifier pairs that describe the IOMMU master interfaces of the device.
Example:
@@ -75,4 +77,7 @@
&tsif0_sync_active
&tsif1_signals_active
&tsif1_sync_active>; /* dual-tsif-mode2 */
+
+ qcom,smmu-s1-bypass;
+ iommus = <&apps_smmu 0x20 0x0f>;
};
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt
index 0123682..d0d878b 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt
@@ -385,6 +385,11 @@
property "qcom,slope-limit-temp-threshold" to make dynamic
slope limit adjustment functional.
+- qcom,fg-bmd-en-delay-ms
+ Usage: optional
+ Value type: <u32>
+ Definition: The delay in ms for FG to enable BMD after reading RID.
+
==========================================================
Second Level Nodes - Peripherals managed by FG Gen3 driver
==========================================================
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt
index 441d771..05fa6e4 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt
@@ -85,21 +85,6 @@
maximum charge current in mA for each thermal
level.
-- qcom,step-soc-thresholds
- Usage: optional
- Value type: Array of <u32>
- Definition: Array of SOC threshold values, size of 4. This should be a
- flat array that denotes the percentage ranging from 0 to 100.
- If the array is not present, step charging is disabled.
-
-- qcom,step-current-deltas
- Usage: optional
- Value type: Array of <s32>
- Definition: Array of delta values for charging current, size of 5, with
- FCC as base. This should be a flat array that denotes the
- offset of charging current in uA, from -3100000 to 3200000.
- If the array is not present, step charging is disabled.
-
- io-channels
Usage: optional
Value type: List of <phandle u32>
@@ -182,6 +167,22 @@
Definition: Specifies the deglitch interval for OTG detection.
If the value is not present, 50 msec is used as default.
+- qcom,step-charging-enable
+ Usage: optional
+ Value type: bool
+ Definition: Boolean flag which when present enables step-charging.
+
+- qcom,wd-bark-time-secs
+ Usage: optional
+ Value type: <u32>
+ Definition: WD bark-timeout in seconds. The possible values are
+ 16, 32, 64, 128. If not defined it defaults to 64.
+
+- qcom,sw-jeita-enable
+ Usage: optional
+ Value type: bool
+ Definition: Boolean flag which when present enables sw compensation for jeita
+
=============================================
Second Level Nodes - SMB2 Charger Peripherals
=============================================
@@ -217,9 +218,6 @@
dpdm-supply = <&qusb_phy0>;
- qcom,step-soc-thresholds = <60 70 80 90>;
- qcom,step-current-deltas = <500000 250000 150000 0 (-150000)>;
-
qcom,chgr@1000 {
reg = <0x1000 0x100>;
interrupts = <0x2 0x10 0x0 IRQ_TYPE_NONE>,
diff --git a/Documentation/devicetree/bindings/qdsp/msm-fastrpc.txt b/Documentation/devicetree/bindings/qdsp/msm-fastrpc.txt
index 9b1b9ee..b0db996 100644
--- a/Documentation/devicetree/bindings/qdsp/msm-fastrpc.txt
+++ b/Documentation/devicetree/bindings/qdsp/msm-fastrpc.txt
@@ -12,6 +12,7 @@
Optional properties:
- qcom,fastrpc-glink: Flag to use glink instead of smd for IPC
+- qcom,rpc-latency-us: FastRPC QoS latency vote
Optional subnodes:
- qcom,msm_fastrpc_compute_cb : Child nodes representing the compute context
@@ -26,6 +27,7 @@
qcom,msm_fastrpc {
compatible = "qcom,msm-fastrpc-adsp";
qcom,fastrpc-glink;
+ qcom,rpc-latency-us = <2343>;
qcom,msm_fastrpc_compute_cb_1 {
compatible = "qcom,msm-fastrpc-compute-cb";
diff --git a/Documentation/devicetree/bindings/regulator/qcom,refgen.txt b/Documentation/devicetree/bindings/regulator/qcom,refgen.txt
new file mode 100644
index 0000000..2c54e29
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/qcom,refgen.txt
@@ -0,0 +1,38 @@
+Qualcomm Technologies, Inc. REFGEN Regulator
+
+Some Qualcomm Technologies, Inc. SoCs utilize reference bias generators for
+various internal PHY blocks. These are called REFGENs.
+
+Supported properties:
+- compatible
+ Usage: required
+ Value type: <string>
+ Definition: Must be "qcom,refgen-regulator".
+
+- reg
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: Address and size of the REFGEN registers.
+
+- regulator-name
+ Usage: required
+ Value type: <string>
+ Definition: Specifies the name for this REFGEN regulator.
+
+- regulator-enable-ramp-delay
+ Usage: optional
+ Value type: <u32>
+ Definition: REFGEN enable time in microseconds.
+
+- parent-supply
+ Usage: optional
+ Value type: <phandle>
+ Definition: phandle to the parent supply/regulator node if one exists.
+
+Example:
+
+refgen-regulator@ff1000 {
+ compatible = "qcom,refgen-regulator";
+ reg = <0xff1000 0x60>;
+ regulator-name = "refgen";
+};
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index c116e42..4d05e50 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -329,7 +329,7 @@
- qcom,gpio-connect Gpio that connects to parent
interrupt controller
-* audio-ext-clk
+* audio-ext-clk-up
Required properties:
@@ -2579,3 +2579,256 @@
qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight",
"SpkrLeft", "SpkrRight";
};
+
+* SDM670 ASoC Machine driver
+
+Required properties:
+- compatible : "qcom,sdm670-asoc-snd"
+- qcom,model : The user-visible name of this sound card.
+- qcom,msm-hs-micbias-type : This property is used to recognize the headset
+ micbias type, internal or external.
+- qcom,msm-mbhc-hphl-swh: This property is used to distinguish headset HPHL
+switch type on target typically the switch type will be normally open or
+normally close, value for this property 0 for normally close and 1 for
+normally open.
+- qcom,msm-mbhc-gnd-swh: This property is used to distinguish headset GND
+switch type on target typically the switch type will be normally open or
+normally close, value for this property 0 for normally close and 1 for
+normally open.
+- qcom,audio-routing : A list of the connections between audio components.
+- qcom,msm-gpios : Lists down all the gpio sets that are supported.
+- qcom,pinctrl-names : Lists all the possible combinations of the gpio sets
+mentioned in qcom,msm-gpios.
+- pinctrl-names : The combinations of gpio sets from above that are supported in
+the flavor.
+- pinctrl-# : Pinctrl states as mentioned in pinctrl-names.
+
+Optional properties:
+- qcom,cdc-us-euro-gpios : GPIO on which gnd/mic swap signal is coming.
+- qcom,msm-micbias1-ext-cap : Boolean. Enable micbias1 external
+capacitor mode.
+- qcom,msm-micbias2-ext-cap : Boolean. Enable micbias2 external
+capacitor mode.
+- qcom,wsa-disable : Boolean. Disables WSA speaker dailinks from sound node.
+- qcom,msm-spk-ext-pa : GPIO which enables external speaker pa.
+- qcom,msm-mclk-freq : This property is used to inform machine driver about
+mclk frequency needs to be configured for internal and external PA.
+- asoc-platform: This is phandle list containing the references to platform device
+ nodes that are used as part of the sound card dai-links.
+- asoc-platform-names: This property contains list of platform names. The order of
+ the platform names should match to that of the phandle order
+ given in "asoc-platform".
+- asoc-cpu: This is phandle list containing the references to cpu dai device nodes
+ that are used as part of the sound card dai-links.
+- asoc-cpu-names: This property contains list of cpu dai names. The order of the
+ cpu dai names should match to that of the phandle order given.
+- asoc-codec: This is phandle list containing the references to codec dai device
+ nodes that are used as part of the sound card dai-links.
+- asoc-codec-names: This property contains list of codec dai names. The order of the
+ codec dai names should match to that of the phandle order given
+ in "asoc-codec".
+- qcom,wsa-max-devs : Maximum number of WSA881x devices present in the target
+- qcom,wsa-devs : List of phandles for all possible WSA881x devices supported for the target
+- qcom,wsa-aux-dev-prefix : Name prefix with Left/Right configuration for WSA881x device
+- qcom,cdc-pdm-gpios : phandle for pdm gpios.
+- qcom,cdc-comp-gpios : phandle for compander gpios.
+- qcom,cdc-dmic-gpios : phandle for Digital mic clk and data gpios.
+- qcom,cdc-sdw-gpios : phandle for soundwire clk and data gpios.
+- qcom,msm-mbhc-moist-cfg: This property is used to set moisture detection
+ threshold values for different codecs. First parameter is V(voltage)
+ second one is i(current), third one is r (resistance). Depending on the
+ codec set corresponding element in array and set others to 0.
+
+Example:
+ sound {
+ compatible = "qcom,sdm670-asoc-snd";
+ qcom,model = "sdm670-snd-card";
+ qcom,msm-mclk-freq = <9600000>;
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+ qcom,msm-hs-micbias-type = "internal";
+ qcom,msm-micbias1-ext-cap;
+ qcom,audio-routing =
+ "RX_BIAS", "MCLK",
+ "SPK_RX_BIAS", "MCLK",
+ "INT_LDO_H", "MCLK",
+ "MIC BIAS External", "Handset Mic",
+ "MIC BIAS Internal2", "Headset Mic",
+ "MIC BIAS External", "Secondary Mic",
+ "AMIC1", "MIC BIAS External",
+ "AMIC2", "MIC BIAS Internal2",
+ "AMIC3", "MIC BIAS External";
+ qcom,cdc-us-euro-gpios = <&msm_gpio 63 0>;
+ qcom,cdc-pdm-gpios = <&cdc_pdm_gpios>;
+ qcom,cdc-comp-gpios = <&cdc_comp_gpios>;
+ qcom,cdc-dmic-gpios = <&cdc_dmic_gpios>;
+ qcom,cdc-sdw-gpios = <&cdc_sdw_gpios>;
+ asoc-platform = <&pcm0>, <&pcm1>, <&voip>, <&voice>,
+ <&loopback>, <&compress>, <&hostless>,
+ <&afe>, <&lsm>, <&routing>, <&lpa>;
+ asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
+ "msm-voip-dsp", "msm-pcm-voice", "msm-pcm-loopback",
+ "msm-compress-dsp", "msm-pcm-hostless", "msm-pcm-afe",
+ "msm-lsm-client", "msm-pcm-routing", "msm-pcm-lpa";
+ asoc-cpu = <&dai_pri_auxpcm>, <&dai_hdmi>,
+ <&dai_mi2s0>, <&dai_mi2s1>, <&dai_mi2s2>, <&dai_mi2s3>,
+ <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>,
+ <&sb_3_rx>, <&sb_3_tx>, <&sb_4_rx>, <&sb_4_tx>,
+ <&bt_sco_rx>, <&bt_sco_tx>, <&int_fm_rx>, <&int_fm_tx>,
+ <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, <&afe_proxy_tx>,
+ <&incall_record_rx>, <&incall_record_tx>, <&incall_music_rx>,
+ <&incall_music_2_rx>;
+ asoc-cpu-names = "msm-dai-q6-auxpcm.1", "msm-dai-q6-hdmi.8",
+ "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1",
+ "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
+ "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385",
+ "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387",
+ "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391",
+ "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393",
+ "msm-dai-q6-dev.12288", "msm-dai-q6-dev.12289",
+ "msm-dai-q6-dev.12292", "msm-dai-q6-dev.12293",
+ "msm-dai-q6-dev.224", "msm-dai-q6-dev.225",
+ "msm-dai-q6-dev.241", "msm-dai-q6-dev.240",
+ "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772",
+ "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770";
+ asoc-codec = <&stub_codec>;
+ asoc-codec-names = "msm-stub-codec.1";
+ qcom,wsa-max-devs = <2>;
+ qcom,wsa-devs = <&wsa881x_211>, <&wsa881x_212>,
+ <&wsa881x_213>, <&wsa881x_214>;
+ qcom,wsa-aux-dev-prefix = "SpkrRight", "SpkrLeft",
+ "SpkrRight", "SpkrLeft";
+ };
+
+* SDM670 ASoC Slimbus Machine driver
+
+Required properties:
+- compatible : "qcom,sdm670-asoc-snd-tasha" for tasha codec,
+ "qcom,sdm670-asoc-snd-tavil" for tavil codec.
+- qcom,model : The user-visible name of this sound card.
+- qcom,msm-mclk-freq : MCLK frequency value for external codec
+- qcom,msm-gpios : Lists down all the gpio sets that are supported.
+- qcom,pinctrl-names : Lists all the possible combinations of the gpio sets
+mentioned in qcom,msm-gpios. Say we have 2^N combinations for N GPIOs,
+this would list all the 2^N combinations.
+- pinctrl-names : The combinations of gpio sets from above that are supported in
+the flavor. This can be sometimes same as qcom, pinctrl-names i.e with 2^N
+combinations or will have less incase if some combination is not supported.
+- pinctrl-# : Pinctrl states as mentioned in pinctrl-names.
+- qcom,audio-routing : A list of the connections between audio components.
+- asoc-platform: This is phandle list containing the references to platform device
+ nodes that are used as part of the sound card dai-links.
+- asoc-platform-names: This property contains list of platform names. The order of
+ the platform names should match to that of the phandle order
+ given in "asoc-platform".
+- asoc-cpu: This is phandle list containing the references to cpu dai device nodes
+ that are used as part of the sound card dai-links.
+- asoc-cpu-names: This property contains list of cpu dai names. The order of the
+ cpu dai names should match to that of the phandle order given
+ in "asoc-cpu". The cpu names are in the form of "%s.%d" form,
+ where the id (%d) field represents the back-end AFE port id that
+ this CPU dai is associated with.
+- asoc-codec: This is phandle list containing the references to codec dai device
+ nodes that are used as part of the sound card dai-links.
+- asoc-codec-names: This property contains list of codec dai names. The order of the
+ codec dai names should match to that of the phandle order given
+ in "asoc-codec".
+Optional properties:
+- qcom,cdc-us-euro-gpios : GPIO on which gnd/mic swap signal is coming.
+- clock-names : clock name defined for external clock.
+- clocks : external clock defined for codec clock.
+- qcom,wsa-max-devs : Maximum number of WSA881x devices present in the target
+- qcom,wsa-devs : List of phandles for all possible WSA881x devices supported for the target
+- qcom,wsa-aux-dev-prefix : Name prefix with Left/Right configuration for WSA881x device
+
+Example:
+
+ sound-9335 {
+ compatible = "qcom,sdm670-asoc-snd-tasha";
+ qcom,model = "sdm670-tasha-snd-card";
+
+ qcom,audio-routing =
+ "RX_BIAS", "MCLK",
+ "LDO_H", "MCLK",
+ "AIF4 MAD", "MCLK",
+ "ultrasound amp", "LINEOUT1",
+ "ultrasound amp", "LINEOUT3",
+ "AMIC1", "MIC BIAS1 Internal1",
+ "MIC BIAS1 Internal1", "Handset Mic",
+ "AMIC2", "MIC BIAS2 External",
+ "MIC BIAS2 External", "Headset Mic",
+ "AMIC3", "MIC BIAS2 External",
+ "MIC BIAS2 External", "ANCRight Headset Mic",
+ "AMIC4", "MIC BIAS2 External",
+ "MIC BIAS2 External", "ANCLeft Headset Mic",
+ "DMIC1", "MIC BIAS1 External",
+ "MIC BIAS1 External", "Digital Mic1",
+ "DMIC2", "MIC BIAS1 External",
+ "MIC BIAS1 External", "Digital Mic2",
+ "DMIC3", "MIC BIAS3 External",
+ "MIC BIAS3 External", "Digital Mic3",
+ "DMIC4", "MIC BIAS3 External",
+ "MIC BIAS3 External", "Digital Mic4",
+ "DMIC5", "MIC BIAS4 External",
+ "MIC BIAS4 External", "Digital Mic5",
+ "DMIC6", "MIC BIAS4 External",
+ "MIC BIAS4 External", "Digital Mic6";
+
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+ qcom,msm-mclk-freq = <9600000>;
+ qcom,msm-gpios =
+ "slim",
+ "us_eu_gpio";
+ qcom,pinctrl-names =
+ "all_off",
+ "slim_act",
+ "us_eu_gpio_act",
+ "slim_us_eu_gpio_act";
+ pinctrl-names =
+ "all_off",
+ "slim_act",
+ "us_eu_gpio_act",
+ "slim_us_eu_gpio_act";
+ pinctrl-0 = <&cdc_slim_lines_sus &cross_conn_det_sus>;
+ pinctrl-1 = <&cdc_slim_lines_act &cross_conn_det_sus>;
+ pinctrl-2 = <&cdc_slim_lines_sus &cross_conn_det_act>;
+ pinctrl-3 = <&cdc_slim_lines_act &cross_conn_det_act>;
+ qcom,cdc-us-euro-gpios = <&msm_gpio 63 0>;
+ asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
+ <&loopback>, <&compress>, <&hostless>,
+ <&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>;
+ asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
+ "msm-pcm-dsp.2", "msm-voip-dsp",
+ "msm-pcm-voice", "msm-pcm-loopback",
+ "msm-compress-dsp", "msm-pcm-hostless",
+ "msm-pcm-afe", "msm-lsm-client",
+ "msm-pcm-routing", "msm-cpe-lsm",
+ "msm-compr-dsp";
+ asoc-cpu = <&dai_hdmi>,
+ <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>,
+ <&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>,
+ <&sb_4_rx>, <&sb_4_tx>, <&sb_5_tx>,
+ <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>,
+ <&afe_proxy_tx>, <&incall_record_rx>,
+ <&incall_record_tx>, <&incall_music_rx>,
+ <&incall_music_2_rx>, <&sb_5_rx>;
+ asoc-cpu-names = "msm-dai-q6-hdmi.8",
+ "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385",
+ "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387",
+ "msm-dai-q6-dev.16388", "msm-dai-q6-dev.16389",
+ "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391",
+ "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393",
+ "msm-dai-q6-dev.16395", "msm-dai-q6-dev.224",
+ "msm-dai-q6-dev.225", "msm-dai-q6-dev.241",
+ "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771",
+ "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773",
+ "msm-dai-q6-dev.32770", "msm-dai-q6-dev.16394";
+ asoc-codec = <&stub_codec>;
+ asoc-codec-names = "msm-stub-codec.1";
+ qcom,wsa-max-devs = <2>;
+ qcom,wsa-devs = <&wsa881x_211>, <&wsa881x_212>,
+ <&wsa881x_213>, <&wsa881x_214>;
+ qcom,wsa-aux-dev-prefix = "SpkrRight", "SpkrLeft",
+ "SpkrRight", "SpkrLeft";
+ };
diff --git a/Documentation/devicetree/bindings/sound/wcd_codec.txt b/Documentation/devicetree/bindings/sound/wcd_codec.txt
index 0df9417..c848ab5 100644
--- a/Documentation/devicetree/bindings/sound/wcd_codec.txt
+++ b/Documentation/devicetree/bindings/sound/wcd_codec.txt
@@ -12,7 +12,6 @@
- qcom,wcd-rst-gpio-node: Phandle reference to the DT node having codec reset gpio
configuration. If this property is not defined, it is
expected to atleast define "qcom,cdc-reset-gpio" property.
-
- cdc-vdd-buck-supply: phandle of buck supply's regulator device tree node.
- qcom,cdc-vdd-buck-voltage: buck supply's voltage level min and max in mV.
- qcom,cdc-vdd-buck-current: buck supply's max current in mA.
@@ -142,6 +141,11 @@
- clock-names : clock name defined for external clock.
- clocks : external clock defined for codec clock.
+ - qcom,has-buck-vsel-gpio: Boolean property to select if WCD_BUCK has VSEL
+ controlled by GPIO.
+ - qcom,buck-vsel-gpio-node: Phandle reference to the DT node having wcd buck
+ VSEL gpio configuration.
+
Example:
taiko_codec {
diff --git a/Documentation/devicetree/bindings/thermal/qcom-lmh-dcvs.txt b/Documentation/devicetree/bindings/thermal/qcom-lmh-dcvs.txt
index 8bead0d..be50d45 100644
--- a/Documentation/devicetree/bindings/thermal/qcom-lmh-dcvs.txt
+++ b/Documentation/devicetree/bindings/thermal/qcom-lmh-dcvs.txt
@@ -31,12 +31,29 @@
Definition: Should specify the cluster affinity this hardware
corresponds to.
+- isens_vref-supply:
+ Usage: optional
+ Value type: <phandle>
+ Definition: Should specify the phandle of the vref regulator used by
+ the isens hardware. This active only regulator will be
+ enabled by LMH DCVSh.
+
+- isens-vref-settings:
+ Usage: optional
+ Value type: <u32 array>
+ Definition: Should specify the min voltage(uV), max voltage(uV) and
+ max load(uA) for the isens vref regulator. This
+ property is valid only if there is valid entry for
+ isens_vref-supply.
+
Example:
lmh_dcvs0: qcom,limits-dcvs@0 {
compatible = "qcom,msm-hw-limits";
interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
qcom,affinity = <0>;
+ isens_vref-supply = <&pm8998_l1_ao>;
+ isens-vref-settings = <880000 880000 36000>;
};
CPU0: cpu@0 {
diff --git a/Documentation/devicetree/bindings/thermal/regulator-cdev.txt b/Documentation/devicetree/bindings/thermal/regulator-cdev.txt
new file mode 100644
index 0000000..7c9abe2
--- /dev/null
+++ b/Documentation/devicetree/bindings/thermal/regulator-cdev.txt
@@ -0,0 +1,38 @@
+Regulator cooling device.
+
+The regulator cooling device, will be used to place a voltage floor
+restriction on a rail.
+
+Properties:
+
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: shall be "qcom,regulator-cooling-device"
+
+- cdev-supply:
+ Usage: required
+ Value type: <phandle>
+ Definition: phandle to the regulator to which the cooling device will
+ place a floor mitigation.
+
+- regulator-levels:
+ Usage: required
+ Value type: <U32 array>
+ Definition: Array of regulator voltages the cooling device should
+ use to place a floor restriction. The voltages should
+ be specified in descending order.
+
+- #cooling-cells: Must be 2. Please refer to
+ <devicetree/bindings/thermal/thermal.txt> for more
+ details.
+
+Example:
+
+ mv_cdev: mx-cdev-lvl {
+ compatible = "qcom,regulator-cooling-device";
+ cdev-supply = <®ulator-cdev-supply>;
+ regulator-levels = <RPMH_REGULATOR_LEVEL_NOM
+ RPMH_REGULATOR_LEVEL_OFF>;
+ #cooling-cells = <2>;
+ };
diff --git a/Makefile b/Makefile
index 04b3557..5894331 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
VERSION = 4
PATCHLEVEL = 9
-SUBLEVEL = 38
+SUBLEVEL = 40
EXTRAVERSION =
NAME = Roaring Lionus
@@ -565,7 +565,7 @@
# Objects we will link into vmlinux / subdirs we need to visit
init-y := init/
-drivers-y := drivers/ sound/ firmware/
+drivers-y := drivers/ sound/ firmware/ techpack/
net-y := net/
libs-y := lib/
core-y := usr/
@@ -633,6 +633,9 @@
KBUILD_CFLAGS += $(call cc-option,-fno-delete-null-pointer-checks,)
KBUILD_CFLAGS += $(call cc-disable-warning,frame-address,)
+KBUILD_CFLAGS += $(call cc-disable-warning, format-truncation)
+KBUILD_CFLAGS += $(call cc-disable-warning, format-overflow)
+KBUILD_CFLAGS += $(call cc-disable-warning, int-in-bool-context)
ifdef CONFIG_LD_DEAD_CODE_DATA_ELIMINATION
KBUILD_CFLAGS += $(call cc-option,-ffunction-sections,)
@@ -1152,6 +1155,7 @@
$(error Headers not exportable for the $(SRCARCH) architecture))
$(Q)$(MAKE) $(hdr-inst)=include/uapi
$(Q)$(MAKE) $(hdr-inst)=arch/$(hdr-arch)/include/uapi/asm $(hdr-dst)
+ $(Q)$(MAKE) $(hdr-inst)=techpack
PHONY += headers_check_all
headers_check_all: headers_install_all
@@ -1161,6 +1165,7 @@
headers_check: headers_install
$(Q)$(MAKE) $(hdr-inst)=include/uapi HDRCHECK=1
$(Q)$(MAKE) $(hdr-inst)=arch/$(hdr-arch)/include/uapi/asm $(hdr-dst) HDRCHECK=1
+ $(Q)$(MAKE) $(hdr-inst)=techpack HDRCHECK=1
# ---------------------------------------------------------------------------
# Kernel selftest
diff --git a/arch/Kconfig b/arch/Kconfig
index 659bdd0..babac73 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -218,6 +218,12 @@
config GENERIC_IDLE_POLL_SETUP
bool
+config ARCH_HAS_FORTIFY_SOURCE
+ bool
+ help
+ An architecture should select this when it can successfully
+ build and run with CONFIG_FORTIFY_SOURCE.
+
# Select if arch init_task initializer is different to init/init_task.c
config ARCH_INIT_TASK
bool
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
index f2a4063..e8d8f9a 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
@@ -15,6 +15,7 @@
#include <dt-bindings/clock/qcom,rpmh.h>
#include <dt-bindings/clock/qcom,gcc-sdxpoorwills.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
/ {
model = "Qualcomm Technologies, Inc. SDX POORWILLS";
@@ -294,6 +295,30 @@
};
};
+ qcom,ipa_fws {
+ compatible = "qcom,pil-tz-generic";
+ qcom,pas-id = <0xf>;
+ qcom,firmware-name = "ipa_fws";
+ };
+
+ spmi_bus: qcom,spmi@c440000 {
+ compatible = "qcom,spmi-pmic-arb";
+ reg = <0xc440000 0x1100>,
+ <0xc600000 0x2000000>,
+ <0xe600000 0x100000>,
+ <0xe700000 0xa0000>,
+ <0xc40a000 0x26000>;
+ reg-names = "core", "chnls", "obsrvr", "intr", "cnfg";
+ interrupt-names = "periph_irq";
+ interrupts = <GIC_SPI 148 IRQ_TYPE_NONE>;
+ qcom,ee = <0>;
+ qcom,channel = <0>;
+ #address-cells = <2>;
+ #size-cells = <0>;
+ interrupt-controller;
+ #interrupt-cells = <4>;
+ cell-index = <0>;
+ };
};
#include "sdxpoorwills-regulator.dtsi"
diff --git a/arch/arm/configs/sdxpoorwills_defconfig b/arch/arm/configs/sdxpoorwills_defconfig
index 88bd16c..23d4056 100644
--- a/arch/arm/configs/sdxpoorwills_defconfig
+++ b/arch/arm/configs/sdxpoorwills_defconfig
@@ -189,7 +189,6 @@
# CONFIG_LEGACY_PTYS is not set
CONFIG_SERIAL_MSM=y
CONFIG_SERIAL_MSM_CONSOLE=y
-CONFIG_HVC_DCC=y
CONFIG_HW_RANDOM=y
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
index ee4a723..8e349ce 100644
--- a/arch/arm/include/asm/cacheflush.h
+++ b/arch/arm/include/asm/cacheflush.h
@@ -178,6 +178,8 @@
* is visible to DMA, or data written by DMA to system memory is
* visible to the CPU.
*/
+extern void __dma_map_area(const void *addr, size_t size, int dir);
+extern void __dma_unmap_area(const void *addr, size_t size, int dir);
extern void dmac_inv_range(const void *, const void *);
extern void dmac_clean_range(const void *, const void *);
extern void dmac_flush_range(const void *, const void *);
diff --git a/arch/arm/include/asm/dma-iommu.h b/arch/arm/include/asm/dma-iommu.h
index b4e74af..74643f5 100644
--- a/arch/arm/include/asm/dma-iommu.h
+++ b/arch/arm/include/asm/dma-iommu.h
@@ -8,6 +8,7 @@
#include <linux/dma-debug.h>
#include <linux/kmemcheck.h>
#include <linux/kref.h>
+#include <linux/dma-mapping-fast.h>
struct dma_iommu_mapping {
/* iommu specific data */
@@ -22,6 +23,8 @@
spinlock_t lock;
struct kref kref;
+
+ struct dma_fast_smmu_mapping *fast;
};
#ifdef CONFIG_ARM_DMA_USE_IOMMU
diff --git a/arch/arm/include/asm/elf.h b/arch/arm/include/asm/elf.h
index d2315ff..f13ae15 100644
--- a/arch/arm/include/asm/elf.h
+++ b/arch/arm/include/asm/elf.h
@@ -112,12 +112,8 @@
#define CORE_DUMP_USE_REGSET
#define ELF_EXEC_PAGESIZE 4096
-/* This is the location that an ET_DYN program is loaded if exec'ed. Typical
- use of this is to invoke "./ld.so someprog" to test out a new version of
- the loader. We need to make sure that it is out of the way of the program
- that it will "exec", and that there is sufficient room for the brk. */
-
-#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2)
+/* This is the base location for PIE (ET_DYN with INTERP) loads. */
+#define ELF_ET_DYN_BASE 0x400000UL
/* When the program starts, a1 contains a pointer to a function to be
registered with atexit, as per the SVR4 ABI. A value of 0 means we
diff --git a/arch/arm/include/asm/glue-cache.h b/arch/arm/include/asm/glue-cache.h
index d14f310..f7c75dc 100644
--- a/arch/arm/include/asm/glue-cache.h
+++ b/arch/arm/include/asm/glue-cache.h
@@ -157,6 +157,11 @@
#define dmac_flush_range __glue(_CACHE,_dma_flush_range)
#define dmac_inv_range __glue(_CACHE, _dma_inv_range)
#define dmac_clean_range __glue(_CACHE, _dma_clean_range)
+#define dmac_map_area __glue(_CACHE, _dma_map_area)
+#define dmac_unmap_area __glue(_CACHE, _dma_unmap_area)
+
+#define __dma_map_area dmac_map_area
+#define __dma_unmap_area dmac_unmap_area
#endif
#endif
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 441063f..cb2c9f4 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -29,6 +29,7 @@
#include <linux/sizes.h>
#include <linux/cma.h>
#include <linux/msm_dma_iommu_mapping.h>
+#include <linux/dma-mapping-fast.h>
#include <asm/memory.h>
#include <asm/highmem.h>
@@ -50,6 +51,8 @@
pgprot_t prot;
const void *caller;
bool want_vaddr;
+ bool skip_cpu_sync;
+ bool skip_zeroing;
int coherent_flag;
};
@@ -113,6 +116,21 @@
static void __dma_page_dev_to_cpu(struct page *, unsigned long,
size_t, enum dma_data_direction);
+static void *
+__dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot,
+ const void *caller);
+
+static void __dma_free_remap(void *cpu_addr, size_t size, bool no_warn);
+
+static inline pgprot_t __get_dma_pgprot(unsigned long attrs, pgprot_t prot);
+
+static void *arm_dma_remap(struct device *dev, void *cpu_addr,
+ dma_addr_t handle, size_t size,
+ unsigned long attrs);
+
+static void arm_dma_unremap(struct device *dev, void *remapped_addr,
+ size_t size);
+
/**
* arm_dma_map_page - map a portion of a page for streaming DMA
* @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
@@ -194,6 +212,8 @@
.sync_single_for_device = arm_dma_sync_single_for_device,
.sync_sg_for_cpu = arm_dma_sync_sg_for_cpu,
.sync_sg_for_device = arm_dma_sync_sg_for_device,
+ .remap = arm_dma_remap,
+ .unremap = arm_dma_unremap,
};
EXPORT_SYMBOL(arm_dma_ops);
@@ -276,7 +296,8 @@
return mask;
}
-static void __dma_clear_buffer(struct page *page, size_t size, int coherent_flag)
+static void __dma_clear_buffer(struct page *page, size_t size,
+ bool skip_zeroing, int coherent_flag)
{
/*
* Ensure that the allocated pages are zeroed, and that any data
@@ -287,7 +308,8 @@
phys_addr_t end = base + size;
while (size > 0) {
void *ptr = kmap_atomic(page);
- memset(ptr, 0, PAGE_SIZE);
+ if (!skip_zeroing)
+ memset(ptr, 0, PAGE_SIZE);
if (coherent_flag != COHERENT)
dmac_flush_range(ptr, ptr + PAGE_SIZE);
kunmap_atomic(ptr);
@@ -298,7 +320,8 @@
outer_flush_range(base, end);
} else {
void *ptr = page_address(page);
- memset(ptr, 0, size);
+ if (!skip_zeroing)
+ memset(ptr, 0, size);
if (coherent_flag != COHERENT) {
dmac_flush_range(ptr, ptr + size);
outer_flush_range(__pa(ptr), __pa(ptr) + size);
@@ -327,7 +350,7 @@
for (p = page + (size >> PAGE_SHIFT), e = page + (1 << order); p < e; p++)
__free_page(p);
- __dma_clear_buffer(page, size, coherent_flag);
+ __dma_clear_buffer(page, size, false, coherent_flag);
return page;
}
@@ -350,6 +373,7 @@
static void *__alloc_from_contiguous(struct device *dev, size_t size,
pgprot_t prot, struct page **ret_page,
const void *caller, bool want_vaddr,
+ bool skip_cpu_sync, bool skip_zeroing,
int coherent_flag);
static void *__alloc_remap_buffer(struct device *dev, size_t size, gfp_t gfp,
@@ -369,10 +393,10 @@
prot, caller);
}
-static void __dma_free_remap(void *cpu_addr, size_t size)
+static void __dma_free_remap(void *cpu_addr, size_t size, bool no_warn)
{
dma_common_free_remap(cpu_addr, size,
- VM_ARM_DMA_CONSISTENT | VM_USERMAP, false);
+ VM_ARM_DMA_CONSISTENT | VM_USERMAP, no_warn);
}
#define DEFAULT_DMA_COHERENT_POOL_SIZE SZ_256K
@@ -421,7 +445,8 @@
*/
if (dev_get_cma_area(NULL))
ptr = __alloc_from_contiguous(NULL, atomic_pool_size, prot,
- &page, atomic_pool_init, true, NORMAL);
+ &page, atomic_pool_init, true, false,
+ false, NORMAL);
else
ptr = __alloc_remap_buffer(NULL, atomic_pool_size, gfp, prot,
&page, atomic_pool_init, true);
@@ -520,21 +545,39 @@
return 0;
}
-static void __dma_remap(struct page *page, size_t size, pgprot_t prot)
+static int __dma_clear_pte(pte_t *pte, pgtable_t token, unsigned long addr,
+ void *data)
+{
+ pte_clear(&init_mm, addr, pte);
+ return 0;
+}
+
+static void __dma_remap(struct page *page, size_t size, pgprot_t prot,
+ bool want_vaddr)
{
unsigned long start = (unsigned long) page_address(page);
unsigned end = start + size;
+ int (*func)(pte_t *pte, pgtable_t token, unsigned long addr,
+ void *data);
- apply_to_page_range(&init_mm, start, size, __dma_update_pte, &prot);
+ if (!want_vaddr)
+ func = __dma_clear_pte;
+ else
+ func = __dma_update_pte;
+
+ apply_to_page_range(&init_mm, start, size, func, &prot);
+ mb(); /*Ensure pte's are updated */
flush_tlb_kernel_range(start, end);
}
+
+#define NO_KERNEL_MAPPING_DUMMY 0x2222
static void *__alloc_remap_buffer(struct device *dev, size_t size, gfp_t gfp,
pgprot_t prot, struct page **ret_page,
const void *caller, bool want_vaddr)
{
struct page *page;
- void *ptr = NULL;
+ void *ptr = (void *)NO_KERNEL_MAPPING_DUMMY;
/*
* __alloc_remap_buffer is only called when the device is
* non-coherent
@@ -595,6 +638,7 @@
static void *__alloc_from_contiguous(struct device *dev, size_t size,
pgprot_t prot, struct page **ret_page,
const void *caller, bool want_vaddr,
+ bool skip_cpu_sync, bool skip_zeroing,
int coherent_flag)
{
unsigned long order = get_order(size);
@@ -606,23 +650,37 @@
if (!page)
return NULL;
- __dma_clear_buffer(page, size, coherent_flag);
-
- if (!want_vaddr)
- goto out;
+ /*
+ * skip completely if we neither need to zero nor sync.
+ */
+ if (!(skip_cpu_sync && skip_zeroing))
+ __dma_clear_buffer(page, size, skip_zeroing, coherent_flag);
if (PageHighMem(page)) {
- ptr = __dma_alloc_remap(page, size, GFP_KERNEL, prot, caller);
- if (!ptr) {
- dma_release_from_contiguous(dev, page, count);
- return NULL;
+ if (!want_vaddr) {
+ /*
+ * Something non-NULL needs to be returned here. Give
+ * back a dummy address that is unmapped to catch
+ * clients trying to use the address incorrectly
+ */
+ ptr = (void *)NO_KERNEL_MAPPING_DUMMY;
+
+ /* also flush out the stale highmem mappings */
+ kmap_flush_unused();
+ kmap_atomic_flush_unused();
+ } else {
+ ptr = __dma_alloc_remap(page, size, GFP_KERNEL, prot,
+ caller);
+ if (!ptr) {
+ dma_release_from_contiguous(dev, page, count);
+ return NULL;
+ }
}
} else {
- __dma_remap(page, size, prot);
+ __dma_remap(page, size, prot, want_vaddr);
ptr = page_address(page);
}
- out:
*ret_page = page;
return ptr;
}
@@ -630,12 +688,10 @@
static void __free_from_contiguous(struct device *dev, struct page *page,
void *cpu_addr, size_t size, bool want_vaddr)
{
- if (want_vaddr) {
- if (PageHighMem(page))
- __dma_free_remap(cpu_addr, size);
- else
- __dma_remap(page, size, PAGE_KERNEL);
- }
+ if (PageHighMem(page))
+ __dma_free_remap(cpu_addr, size, true);
+ else
+ __dma_remap(page, size, PAGE_KERNEL, true);
dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT);
}
@@ -656,10 +712,11 @@
#define __get_dma_pgprot(attrs, prot) __pgprot(0)
#define __alloc_remap_buffer(dev, size, gfp, prot, ret, c, wv) NULL
#define __alloc_from_pool(size, ret_page) NULL
-#define __alloc_from_contiguous(dev, size, prot, ret, c, wv, coherent_flag) NULL
+#define __alloc_from_contiguous(dev, size, prot, ret, c, \
+ wv, scs, sz, coherent_flag) NULL
#define __free_from_pool(cpu_addr, size) do { } while (0)
#define __free_from_contiguous(dev, page, cpu_addr, size, wv) do { } while (0)
-#define __dma_free_remap(cpu_addr, size) do { } while (0)
+#define __dma_free_remap(cpu_addr, size, w) do { } while (0)
#endif /* CONFIG_MMU */
@@ -698,7 +755,8 @@
{
return __alloc_from_contiguous(args->dev, args->size, args->prot,
ret_page, args->caller,
- args->want_vaddr, args->coherent_flag);
+ args->want_vaddr, args->skip_cpu_sync,
+ args->skip_zeroing, args->coherent_flag);
}
static void cma_allocator_free(struct arm_dma_free_args *args)
@@ -739,7 +797,7 @@
static void remap_allocator_free(struct arm_dma_free_args *args)
{
if (args->want_vaddr)
- __dma_free_remap(args->cpu_addr, args->size);
+ __dma_free_remap(args->cpu_addr, args->size, false);
__dma_free_buffer(args->page, args->size);
}
@@ -765,6 +823,8 @@
.prot = prot,
.caller = caller,
.want_vaddr = ((attrs & DMA_ATTR_NO_KERNEL_MAPPING) == 0),
+ .skip_cpu_sync = (attrs & DMA_ATTR_SKIP_CPU_SYNC),
+ .skip_zeroing = (attrs & DMA_ATTR_SKIP_ZEROING),
.coherent_flag = is_coherent ? COHERENT : NORMAL,
};
@@ -826,7 +886,7 @@
kfree(buf);
}
- return args.want_vaddr ? addr : page;
+ return addr;
}
/*
@@ -874,6 +934,38 @@
return ret;
}
+static void *arm_dma_remap(struct device *dev, void *cpu_addr,
+ dma_addr_t handle, size_t size,
+ unsigned long attrs)
+{
+ void *ptr;
+ struct page *page = pfn_to_page(dma_to_pfn(dev, handle));
+ pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL);
+ unsigned long offset = handle & ~PAGE_MASK;
+
+ size = PAGE_ALIGN(size + offset);
+ ptr = __dma_alloc_remap(page, size, GFP_KERNEL, prot,
+ __builtin_return_address(0));
+ return ptr ? ptr + offset : ptr;
+}
+
+static void arm_dma_unremap(struct device *dev, void *remapped_addr,
+ size_t size)
+{
+ unsigned int flags = VM_ARM_DMA_CONSISTENT | VM_USERMAP;
+ struct vm_struct *area;
+
+ remapped_addr = (void *)((unsigned long)remapped_addr & PAGE_MASK);
+
+ area = find_vm_area(remapped_addr);
+ if (!area || (area->flags & flags) != flags) {
+ WARN(1, "trying to free invalid coherent area: %p\n",
+ remapped_addr);
+ return;
+ }
+
+ vunmap(remapped_addr);
+}
/*
* Create userspace mapping for the DMA-coherent memory.
*/
@@ -1298,7 +1390,7 @@
if (!page)
goto error;
- __dma_clear_buffer(page, size, coherent_flag);
+ __dma_clear_buffer(page, size, false, coherent_flag);
for (i = 0; i < count; i++)
pages[i] = page + i;
@@ -1348,7 +1440,8 @@
pages[i + j] = pages[i] + j;
}
- __dma_clear_buffer(pages[i], PAGE_SIZE << order, coherent_flag);
+ __dma_clear_buffer(pages[i], PAGE_SIZE << order,
+ false, coherent_flag);
i += 1 << order;
count -= 1 << order;
}
@@ -2287,12 +2380,21 @@
struct dma_iommu_mapping *mapping)
{
int err;
+ int s1_bypass = 0;
+ int is_fast = 0;
+
+ iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_FAST, &is_fast);
+ if (is_fast)
+ return fast_smmu_attach_device(dev, mapping);
err = __arm_iommu_attach_device(dev, mapping);
if (err)
return err;
- set_dma_ops(dev, &iommu_ops);
+ iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_S1_BYPASS,
+ &s1_bypass);
+ if (!s1_bypass)
+ set_dma_ops(dev, &iommu_ops);
return 0;
}
EXPORT_SYMBOL_GPL(arm_iommu_attach_device);
@@ -2300,6 +2402,7 @@
static void __arm_iommu_detach_device(struct device *dev)
{
struct dma_iommu_mapping *mapping;
+ int is_fast;
mapping = to_dma_iommu_mapping(dev);
if (!mapping) {
@@ -2309,6 +2412,9 @@
if (msm_dma_unmap_all_for_dev(dev))
dev_warn(dev, "IOMMU detach with outstanding mappings\n");
+ iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_FAST, &is_fast);
+ if (is_fast)
+ return fast_smmu_detach_device(dev, mapping);
iommu_detach_device(mapping->domain, dev);
kref_put(&mapping->kref, release_iommu_mapping);
@@ -2326,8 +2432,21 @@
*/
void arm_iommu_detach_device(struct device *dev)
{
+ struct dma_iommu_mapping *mapping;
+ int s1_bypass = 0;
+
+ mapping = to_dma_iommu_mapping(dev);
+ if (!mapping) {
+ dev_warn(dev, "Not attached\n");
+ return;
+ }
+
__arm_iommu_detach_device(dev);
- set_dma_ops(dev, NULL);
+
+ iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_S1_BYPASS,
+ &s1_bypass);
+ if (!s1_bypass)
+ set_dma_ops(dev, NULL);
}
EXPORT_SYMBOL_GPL(arm_iommu_detach_device);
diff --git a/arch/arm/mm/dma.h b/arch/arm/mm/dma.h
index 70ea6852..29c54f7 100644
--- a/arch/arm/mm/dma.h
+++ b/arch/arm/mm/dma.h
@@ -4,9 +4,6 @@
#include <asm/glue-cache.h>
#ifndef MULTI_CACHE
-#define dmac_map_area __glue(_CACHE,_dma_map_area)
-#define dmac_unmap_area __glue(_CACHE,_dma_unmap_area)
-
/*
* These are private to the dma-mapping API. Do not use directly.
* Their sole purpose is to ensure that data held in the cache
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 842c38a..6468b58 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -9,6 +9,7 @@
select ARCH_HAS_DEVMEM_IS_ALLOWED
select ARCH_HAS_ACPI_TABLE_UPGRADE if ACPI
select ARCH_HAS_ELF_RANDOMIZE
+ select ARCH_HAS_FORTIFY_SOURCE
select ARCH_HAS_GCOV_PROFILE_ALL
select ARCH_HAS_GIGANTIC_PAGE
select ARCH_HAS_KCOV
@@ -595,7 +596,7 @@
# selected platforms.
config ARCH_NR_GPIO
int
- default 1024 if ARCH_QCOM
+ default 1280 if ARCH_QCOM
default 256
help
Maximum number of GPIOs in the system.
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index dae2f9f..f96fba6 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -116,6 +116,8 @@
select PINCTRL
select SOC_BUS
select PM_OPP
+ select MFD_CORE
+ select SND_SOC_COMPRESS
help
This enables support for the ARMv8 based Qualcomm chipsets.
diff --git a/arch/arm64/boot/Makefile b/arch/arm64/boot/Makefile
index 92dc1e6..b97f1de 100644
--- a/arch/arm64/boot/Makefile
+++ b/arch/arm64/boot/Makefile
@@ -28,6 +28,17 @@
DTB_OBJS := $(shell find $(obj)/dts/ -name \*.dtb)
endif
+# Add RTIC DTB to the DTB list if RTIC MPGen is enabled
+ifdef RTIC_MPGEN
+DTB_OBJS += rtic_mp.dtb
+endif
+
+rtic_mp.dtb: vmlinux FORCE
+ $(RTIC_MPGEN) --objcopy="${OBJCOPY}" --objdump="${OBJDUMP}" \
+ --binpath="" --vmlinux="vmlinux" --config=${KCONFIG_CONFIG} \
+ --cc="${CC}" --dts=rtic_mp.dts && \
+ $(DTC) -O dtb -o rtic_mp.dtb -b 0 $(DTC_FLAGS) rtic_mp.dts
+
$(obj)/Image: vmlinux FORCE
$(call if_changed,objcopy)
diff --git a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
index e9bd587..49a5d8c 100644
--- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
@@ -75,14 +75,10 @@
timer {
compatible = "arm,armv8-timer";
- interrupts = <GIC_PPI 13
- (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>,
- <GIC_PPI 14
- (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>,
- <GIC_PPI 11
- (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>,
- <GIC_PPI 10
- (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>;
+ interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_PPI 14 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_PPI 11 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_PPI 10 IRQ_TYPE_LEVEL_HIGH>;
};
soc {
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index 20288fe..ee7f735 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -12,7 +12,9 @@
sdm845-v2-qrd-overlay.dtbo \
sdm845-4k-panel-mtp-overlay.dtbo \
sdm845-4k-panel-cdp-overlay.dtbo \
- sdm845-4k-panel-qrd-overlay.dtbo
+ sdm845-4k-panel-qrd-overlay.dtbo \
+ sdm845-interposer-sdm670-cdp-overlay.dtbo \
+ sdm845-interposer-sdm670-mtp-overlay.dtbo
sdm845-cdp-overlay.dtbo-base := sdm845.dtb
sdm845-mtp-overlay.dtbo-base := sdm845.dtb
@@ -23,6 +25,8 @@
sdm845-4k-panel-mtp-overlay.dtbo-base := sdm845.dtb
sdm845-4k-panel-cdp-overlay.dtbo-base := sdm845.dtb
sdm845-4k-panel-qrd-overlay.dtbo-base := sdm845.dtb
+sdm845-interposer-sdm670-cdp-overlay.dtbo-base := sdm845-interposer-sdm670.dtb
+sdm845-interposer-sdm670-mtp-overlay.dtbo-base := sdm845-interposer-sdm670.dtb
else
dtb-$(CONFIG_ARCH_SDM845) += sdm845-sim.dtb \
sdm845-rumi.dtb \
@@ -35,7 +39,9 @@
sdm845-v2-qrd.dtb \
sdm845-4k-panel-mtp.dtb \
sdm845-4k-panel-cdp.dtb \
- sdm845-4k-panel-qrd.dtb
+ sdm845-4k-panel-qrd.dtb \
+ sdm845-interposer-sdm670-mtp.dtb \
+ sdm845-interposer-sdm670-cdp.dtb
endif
dtb-$(CONFIG_ARCH_SDM670) += sdm670-rumi.dtb \
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi
index 44b817e..0ca1175 100644
--- a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi
@@ -15,22 +15,10 @@
qcom,mdss-dsi-panel-name =
"nt35597 cmd mode dsi truly panel with DSC";
qcom,mdss-dsi-panel-type = "dsi_cmd_mode";
- qcom,mdss-dsi-panel-framerate = <60>;
qcom,mdss-dsi-virtual-channel-id = <0>;
qcom,mdss-dsi-stream = <0>;
- qcom,mdss-dsi-panel-width = <1440>;
- qcom,mdss-dsi-panel-height = <2560>;
- qcom,mdss-dsi-h-front-porch = <100>;
- qcom,mdss-dsi-h-back-porch = <32>;
- qcom,mdss-dsi-h-pulse-width = <16>;
- qcom,mdss-dsi-h-sync-skew = <0>;
- qcom,mdss-dsi-v-back-porch = <8>;
- qcom,mdss-dsi-v-front-porch = <10>;
- qcom,mdss-dsi-v-pulse-width = <2>;
- qcom,mdss-dsi-h-left-border = <0>;
- qcom,mdss-dsi-h-right-border = <0>;
- qcom,mdss-dsi-v-top-border = <0>;
- qcom,mdss-dsi-v-bottom-border = <0>;
+ qcom,mdss-pan-physical-width-dimension = <74>;
+ qcom,mdss-pan-physical-height-dimension = <131>;
qcom,mdss-dsi-bpp = <24>;
qcom,mdss-dsi-color-order = "rgb_swap_rgb";
qcom,mdss-dsi-underflow-color = <0xff>;
@@ -40,171 +28,6 @@
17000 15500 30000 8000 3000>;
qcom,mdss-dsi-panel-peak-brightness = <4200000>;
qcom,mdss-dsi-panel-blackness-level = <3230>;
- qcom,mdss-dsi-on-command = [
- /* CMD2_P0 */
- 15 01 00 00 00 00 02 ff 20
- 15 01 00 00 00 00 02 fb 01
- 15 01 00 00 00 00 02 00 01
- 15 01 00 00 00 00 02 01 55
- 15 01 00 00 00 00 02 02 45
- 15 01 00 00 00 00 02 05 40
- 15 01 00 00 00 00 02 06 19
- 15 01 00 00 00 00 02 07 1e
- 15 01 00 00 00 00 02 0b 73
- 15 01 00 00 00 00 02 0c 73
- 15 01 00 00 00 00 02 0e b0
- 15 01 00 00 00 00 02 0f ae
- 15 01 00 00 00 00 02 11 b8
- 15 01 00 00 00 00 02 13 00
- 15 01 00 00 00 00 02 58 80
- 15 01 00 00 00 00 02 59 01
- 15 01 00 00 00 00 02 5a 00
- 15 01 00 00 00 00 02 5b 01
- 15 01 00 00 00 00 02 5c 80
- 15 01 00 00 00 00 02 5d 81
- 15 01 00 00 00 00 02 5e 00
- 15 01 00 00 00 00 02 5f 01
- 15 01 00 00 00 00 02 72 31
- 15 01 00 00 00 00 02 68 03
- /* CMD2_P4 */
- 15 01 00 00 00 00 02 ff 24
- 15 01 00 00 00 00 02 fb 01
- 15 01 00 00 00 00 02 00 1c
- 15 01 00 00 00 00 02 01 0b
- 15 01 00 00 00 00 02 02 0c
- 15 01 00 00 00 00 02 03 01
- 15 01 00 00 00 00 02 04 0f
- 15 01 00 00 00 00 02 05 10
- 15 01 00 00 00 00 02 06 10
- 15 01 00 00 00 00 02 07 10
- 15 01 00 00 00 00 02 08 89
- 15 01 00 00 00 00 02 09 8a
- 15 01 00 00 00 00 02 0a 13
- 15 01 00 00 00 00 02 0b 13
- 15 01 00 00 00 00 02 0c 15
- 15 01 00 00 00 00 02 0d 15
- 15 01 00 00 00 00 02 0e 17
- 15 01 00 00 00 00 02 0f 17
- 15 01 00 00 00 00 02 10 1c
- 15 01 00 00 00 00 02 11 0b
- 15 01 00 00 00 00 02 12 0c
- 15 01 00 00 00 00 02 13 01
- 15 01 00 00 00 00 02 14 0f
- 15 01 00 00 00 00 02 15 10
- 15 01 00 00 00 00 02 16 10
- 15 01 00 00 00 00 02 17 10
- 15 01 00 00 00 00 02 18 89
- 15 01 00 00 00 00 02 19 8a
- 15 01 00 00 00 00 02 1a 13
- 15 01 00 00 00 00 02 1b 13
- 15 01 00 00 00 00 02 1c 15
- 15 01 00 00 00 00 02 1d 15
- 15 01 00 00 00 00 02 1e 17
- 15 01 00 00 00 00 02 1f 17
- /* STV */
- 15 01 00 00 00 00 02 20 40
- 15 01 00 00 00 00 02 21 01
- 15 01 00 00 00 00 02 22 00
- 15 01 00 00 00 00 02 23 40
- 15 01 00 00 00 00 02 24 40
- 15 01 00 00 00 00 02 25 6d
- 15 01 00 00 00 00 02 26 40
- 15 01 00 00 00 00 02 27 40
- /* Vend */
- 15 01 00 00 00 00 02 e0 00
- 15 01 00 00 00 00 02 dc 21
- 15 01 00 00 00 00 02 dd 22
- 15 01 00 00 00 00 02 de 07
- 15 01 00 00 00 00 02 df 07
- 15 01 00 00 00 00 02 e3 6D
- 15 01 00 00 00 00 02 e1 07
- 15 01 00 00 00 00 02 e2 07
- /* UD */
- 15 01 00 00 00 00 02 29 d8
- 15 01 00 00 00 00 02 2a 2a
- /* CLK */
- 15 01 00 00 00 00 02 4b 03
- 15 01 00 00 00 00 02 4c 11
- 15 01 00 00 00 00 02 4d 10
- 15 01 00 00 00 00 02 4e 01
- 15 01 00 00 00 00 02 4f 01
- 15 01 00 00 00 00 02 50 10
- 15 01 00 00 00 00 02 51 00
- 15 01 00 00 00 00 02 52 80
- 15 01 00 00 00 00 02 53 00
- 15 01 00 00 00 00 02 56 00
- 15 01 00 00 00 00 02 54 07
- 15 01 00 00 00 00 02 58 07
- 15 01 00 00 00 00 02 55 25
- /* Reset XDONB */
- 15 01 00 00 00 00 02 5b 43
- 15 01 00 00 00 00 02 5c 00
- 15 01 00 00 00 00 02 5f 73
- 15 01 00 00 00 00 02 60 73
- 15 01 00 00 00 00 02 63 22
- 15 01 00 00 00 00 02 64 00
- 15 01 00 00 00 00 02 67 08
- 15 01 00 00 00 00 02 68 04
- /* Resolution:1440x2560*/
- 15 01 00 00 00 00 02 72 02
- /* mux */
- 15 01 00 00 00 00 02 7a 80
- 15 01 00 00 00 00 02 7b 91
- 15 01 00 00 00 00 02 7c D8
- 15 01 00 00 00 00 02 7d 60
- 15 01 00 00 00 00 02 7f 15
- 15 01 00 00 00 00 02 75 15
- /* ABOFF */
- 15 01 00 00 00 00 02 b3 C0
- 15 01 00 00 00 00 02 b4 00
- 15 01 00 00 00 00 02 b5 00
- /* Source EQ */
- 15 01 00 00 00 00 02 78 00
- 15 01 00 00 00 00 02 79 00
- 15 01 00 00 00 00 02 80 00
- 15 01 00 00 00 00 02 83 00
- /* FP BP */
- 15 01 00 00 00 00 02 93 0a
- 15 01 00 00 00 00 02 94 0a
- /* Inversion Type */
- 15 01 00 00 00 00 02 8a 00
- 15 01 00 00 00 00 02 9b ff
- /* IMGSWAP =1 @PortSwap=1 */
- 15 01 00 00 00 00 02 9d b0
- 15 01 00 00 00 00 02 9f 63
- 15 01 00 00 00 00 02 98 10
- /* FRM */
- 15 01 00 00 00 00 02 ec 00
- /* CMD1 */
- 15 01 00 00 00 00 02 ff 10
- /* VESA DSC PPS settings(1440x2560 slide 16H) */
- 39 01 00 00 00 00 11 c1 09 20 00 10 02 00 02 68
- 01 bb 00 0a 06 67 04 c5
- 39 01 00 00 00 00 03 c2 10 f0
- /* C0h = 0x0(2 Port SDC)0x01(1 PortA FBC)
- * 0x02(MTK) 0x03(1 PortA VESA)
- */
- 15 01 00 00 00 00 02 c0 03
- /* VBP+VSA=,VFP = 10H */
- 15 01 00 00 00 00 04 3b 03 0a 0a
- /* FTE on */
- 15 01 00 00 00 00 02 35 00
- /* EN_BK =1(auto black) */
- 15 01 00 00 00 00 02 e5 01
- /* CMD mode(10) VDO mode(03) */
- 15 01 00 00 00 00 02 bb 10
- /* Non Reload MTP */
- 15 01 00 00 00 00 02 fb 01
- /* SlpOut + DispOn */
- 05 01 00 00 78 00 02 11 00
- 05 01 00 00 78 00 02 29 00
- ];
- qcom,mdss-dsi-off-command = [05 01 00 00 78 00 02 28 00
- 05 01 00 00 78 00 02 10 00];
-
- qcom,mdss-dsi-on-command-state = "dsi_hs_mode";
- qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
- qcom,mdss-dsi-h-sync-pulse = <0>;
qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
qcom,mdss-dsi-bllp-eof-power-mode;
qcom,mdss-dsi-bllp-power-mode;
@@ -215,7 +38,6 @@
qcom,mdss-dsi-dma-trigger = "trigger_sw";
qcom,mdss-dsi-mdp-trigger = "none";
qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>;
-
qcom,mdss-dsi-bl-max-level = <4095>;
qcom,adjust-timer-wakeup-ms = <1>;
qcom,mdss-dsi-te-pin-select = <1>;
@@ -225,13 +47,201 @@
qcom,mdss-dsi-te-check-enable;
qcom,mdss-dsi-te-using-te-pin;
- qcom,compression-mode = "dsc";
- qcom,mdss-dsc-slice-height = <16>;
- qcom,mdss-dsc-slice-width = <720>;
- qcom,mdss-dsc-slice-per-pkt = <2>;
- qcom,mdss-dsc-bit-per-component = <8>;
- qcom,mdss-dsc-bit-per-pixel = <8>;
- qcom,mdss-dsc-block-prediction-enable;
+ qcom,mdss-dsi-display-timings {
+ timing@0{
+ qcom,mdss-dsi-panel-framerate = <60>;
+ qcom,mdss-dsi-panel-width = <1440>;
+ qcom,mdss-dsi-panel-height = <2560>;
+ qcom,mdss-dsi-h-front-porch = <100>;
+ qcom,mdss-dsi-h-back-porch = <32>;
+ qcom,mdss-dsi-h-pulse-width = <16>;
+ qcom,mdss-dsi-h-sync-skew = <0>;
+ qcom,mdss-dsi-v-back-porch = <8>;
+ qcom,mdss-dsi-v-front-porch = <10>;
+ qcom,mdss-dsi-v-pulse-width = <2>;
+ qcom,mdss-dsi-h-left-border = <0>;
+ qcom,mdss-dsi-h-right-border = <0>;
+ qcom,mdss-dsi-v-top-border = <0>;
+ qcom,mdss-dsi-v-bottom-border = <0>;
+ qcom,mdss-dsi-panel-jitter = <0x1 0x1>;
+ qcom,mdss-dsi-on-command = [
+ /* CMD2_P0 */
+ 15 01 00 00 00 00 02 ff 20
+ 15 01 00 00 00 00 02 fb 01
+ 15 01 00 00 00 00 02 00 01
+ 15 01 00 00 00 00 02 01 55
+ 15 01 00 00 00 00 02 02 45
+ 15 01 00 00 00 00 02 05 40
+ 15 01 00 00 00 00 02 06 19
+ 15 01 00 00 00 00 02 07 1e
+ 15 01 00 00 00 00 02 0b 73
+ 15 01 00 00 00 00 02 0c 73
+ 15 01 00 00 00 00 02 0e b0
+ 15 01 00 00 00 00 02 0f ae
+ 15 01 00 00 00 00 02 11 b8
+ 15 01 00 00 00 00 02 13 00
+ 15 01 00 00 00 00 02 58 80
+ 15 01 00 00 00 00 02 59 01
+ 15 01 00 00 00 00 02 5a 00
+ 15 01 00 00 00 00 02 5b 01
+ 15 01 00 00 00 00 02 5c 80
+ 15 01 00 00 00 00 02 5d 81
+ 15 01 00 00 00 00 02 5e 00
+ 15 01 00 00 00 00 02 5f 01
+ 15 01 00 00 00 00 02 72 31
+ 15 01 00 00 00 00 02 68 03
+ /* CMD2_P4 */
+ 15 01 00 00 00 00 02 ff 24
+ 15 01 00 00 00 00 02 fb 01
+ 15 01 00 00 00 00 02 00 1c
+ 15 01 00 00 00 00 02 01 0b
+ 15 01 00 00 00 00 02 02 0c
+ 15 01 00 00 00 00 02 03 01
+ 15 01 00 00 00 00 02 04 0f
+ 15 01 00 00 00 00 02 05 10
+ 15 01 00 00 00 00 02 06 10
+ 15 01 00 00 00 00 02 07 10
+ 15 01 00 00 00 00 02 08 89
+ 15 01 00 00 00 00 02 09 8a
+ 15 01 00 00 00 00 02 0a 13
+ 15 01 00 00 00 00 02 0b 13
+ 15 01 00 00 00 00 02 0c 15
+ 15 01 00 00 00 00 02 0d 15
+ 15 01 00 00 00 00 02 0e 17
+ 15 01 00 00 00 00 02 0f 17
+ 15 01 00 00 00 00 02 10 1c
+ 15 01 00 00 00 00 02 11 0b
+ 15 01 00 00 00 00 02 12 0c
+ 15 01 00 00 00 00 02 13 01
+ 15 01 00 00 00 00 02 14 0f
+ 15 01 00 00 00 00 02 15 10
+ 15 01 00 00 00 00 02 16 10
+ 15 01 00 00 00 00 02 17 10
+ 15 01 00 00 00 00 02 18 89
+ 15 01 00 00 00 00 02 19 8a
+ 15 01 00 00 00 00 02 1a 13
+ 15 01 00 00 00 00 02 1b 13
+ 15 01 00 00 00 00 02 1c 15
+ 15 01 00 00 00 00 02 1d 15
+ 15 01 00 00 00 00 02 1e 17
+ 15 01 00 00 00 00 02 1f 17
+ /* STV */
+ 15 01 00 00 00 00 02 20 40
+ 15 01 00 00 00 00 02 21 01
+ 15 01 00 00 00 00 02 22 00
+ 15 01 00 00 00 00 02 23 40
+ 15 01 00 00 00 00 02 24 40
+ 15 01 00 00 00 00 02 25 6d
+ 15 01 00 00 00 00 02 26 40
+ 15 01 00 00 00 00 02 27 40
+ /* Vend */
+ 15 01 00 00 00 00 02 e0 00
+ 15 01 00 00 00 00 02 dc 21
+ 15 01 00 00 00 00 02 dd 22
+ 15 01 00 00 00 00 02 de 07
+ 15 01 00 00 00 00 02 df 07
+ 15 01 00 00 00 00 02 e3 6D
+ 15 01 00 00 00 00 02 e1 07
+ 15 01 00 00 00 00 02 e2 07
+ /* UD */
+ 15 01 00 00 00 00 02 29 d8
+ 15 01 00 00 00 00 02 2a 2a
+ /* CLK */
+ 15 01 00 00 00 00 02 4b 03
+ 15 01 00 00 00 00 02 4c 11
+ 15 01 00 00 00 00 02 4d 10
+ 15 01 00 00 00 00 02 4e 01
+ 15 01 00 00 00 00 02 4f 01
+ 15 01 00 00 00 00 02 50 10
+ 15 01 00 00 00 00 02 51 00
+ 15 01 00 00 00 00 02 52 80
+ 15 01 00 00 00 00 02 53 00
+ 15 01 00 00 00 00 02 56 00
+ 15 01 00 00 00 00 02 54 07
+ 15 01 00 00 00 00 02 58 07
+ 15 01 00 00 00 00 02 55 25
+ /* Reset XDONB */
+ 15 01 00 00 00 00 02 5b 43
+ 15 01 00 00 00 00 02 5c 00
+ 15 01 00 00 00 00 02 5f 73
+ 15 01 00 00 00 00 02 60 73
+ 15 01 00 00 00 00 02 63 22
+ 15 01 00 00 00 00 02 64 00
+ 15 01 00 00 00 00 02 67 08
+ 15 01 00 00 00 00 02 68 04
+ /* Resolution:1440x2560*/
+ 15 01 00 00 00 00 02 72 02
+ /* mux */
+ 15 01 00 00 00 00 02 7a 80
+ 15 01 00 00 00 00 02 7b 91
+ 15 01 00 00 00 00 02 7c D8
+ 15 01 00 00 00 00 02 7d 60
+ 15 01 00 00 00 00 02 7f 15
+ 15 01 00 00 00 00 02 75 15
+ /* ABOFF */
+ 15 01 00 00 00 00 02 b3 C0
+ 15 01 00 00 00 00 02 b4 00
+ 15 01 00 00 00 00 02 b5 00
+ /* Source EQ */
+ 15 01 00 00 00 00 02 78 00
+ 15 01 00 00 00 00 02 79 00
+ 15 01 00 00 00 00 02 80 00
+ 15 01 00 00 00 00 02 83 00
+ /* FP BP */
+ 15 01 00 00 00 00 02 93 0a
+ 15 01 00 00 00 00 02 94 0a
+ /* Inversion Type */
+ 15 01 00 00 00 00 02 8a 00
+ 15 01 00 00 00 00 02 9b ff
+ /* IMGSWAP =1 @PortSwap=1 */
+ 15 01 00 00 00 00 02 9d b0
+ 15 01 00 00 00 00 02 9f 63
+ 15 01 00 00 00 00 02 98 10
+ /* FRM */
+ 15 01 00 00 00 00 02 ec 00
+ /* CMD1 */
+ 15 01 00 00 00 00 02 ff 10
+ /* VESA DSC PPS settings
+ * (1440x2560 slide 16H)
+ */
+ 39 01 00 00 00 00 11 c1 09
+ 20 00 10 02 00 02 68 01 bb
+ 00 0a 06 67 04 c5
+ 39 01 00 00 00 00 03 c2 10 f0
+ /* C0h = 0x0(2 Port SDC)
+ * 0x01(1 PortA FBC)
+ * 0x02(MTK) 0x03(1 PortA VESA)
+ */
+ 15 01 00 00 00 00 02 c0 03
+ /* VBP+VSA=,VFP = 10H */
+ 15 01 00 00 00 00 04 3b 03 0a 0a
+ /* FTE on */
+ 15 01 00 00 00 00 02 35 00
+ /* EN_BK =1(auto black) */
+ 15 01 00 00 00 00 02 e5 01
+ /* CMD mode(10) VDO mode(03) */
+ 15 01 00 00 00 00 02 bb 10
+ /* Non Reload MTP */
+ 15 01 00 00 00 00 02 fb 01
+ /* SlpOut + DispOn */
+ 05 01 00 00 78 00 02 11 00
+ 05 01 00 00 78 00 02 29 00
+ ];
+ qcom,mdss-dsi-off-command = [05 01 00 00 78 00
+ 02 28 00 05 01 00 00 78 00 02 10 00];
+
+ qcom,mdss-dsi-on-command-state = "dsi_hs_mode";
+ qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+ qcom,mdss-dsi-h-sync-pulse = <0>;
+ qcom,compression-mode = "dsc";
+ qcom,mdss-dsc-slice-height = <16>;
+ qcom,mdss-dsc-slice-width = <720>;
+ qcom,mdss-dsc-slice-per-pkt = <2>;
+ qcom,mdss-dsc-bit-per-component = <8>;
+ qcom,mdss-dsc-bit-per-pixel = <8>;
+ qcom,mdss-dsc-block-prediction-enable;
+ };
+ };
};
};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi
index 515949e..ac8a956 100644
--- a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi
@@ -15,18 +15,8 @@
qcom,mdss-dsi-panel-name =
"nt35597 video mode dsi truly panel with DSC";
qcom,mdss-dsi-panel-type = "dsi_video_mode";
- qcom,mdss-dsi-panel-framerate = <60>;
qcom,mdss-dsi-virtual-channel-id = <0>;
qcom,mdss-dsi-stream = <0>;
- qcom,mdss-dsi-panel-width = <1440>;
- qcom,mdss-dsi-panel-height = <2560>;
- qcom,mdss-dsi-h-front-porch = <100>;
- qcom,mdss-dsi-h-back-porch = <32>;
- qcom,mdss-dsi-h-pulse-width = <16>;
- qcom,mdss-dsi-h-sync-skew = <0>;
- qcom,mdss-dsi-v-back-porch = <8>;
- qcom,mdss-dsi-v-front-porch = <10>;
- qcom,mdss-dsi-v-pulse-width = <2>;
qcom,mdss-dsi-bpp = <24>;
qcom,mdss-dsi-underflow-color = <0xff>;
qcom,mdss-dsi-border-color = <0>;
@@ -35,170 +25,6 @@
17000 15500 30000 8000 3000>;
qcom,mdss-dsi-panel-peak-brightness = <4200000>;
qcom,mdss-dsi-panel-blackness-level = <3230>;
- qcom,mdss-dsi-on-command = [
- /* CMD2_P0 */
- 15 01 00 00 00 00 02 ff 20
- 15 01 00 00 00 00 02 fb 01
- 15 01 00 00 00 00 02 00 01
- 15 01 00 00 00 00 02 01 55
- 15 01 00 00 00 00 02 02 45
- 15 01 00 00 00 00 02 05 40
- 15 01 00 00 00 00 02 06 19
- 15 01 00 00 00 00 02 07 1e
- 15 01 00 00 00 00 02 0b 73
- 15 01 00 00 00 00 02 0c 73
- 15 01 00 00 00 00 02 0e b0
- 15 01 00 00 00 00 02 0f aE
- 15 01 00 00 00 00 02 11 b8
- 15 01 00 00 00 00 02 13 00
- 15 01 00 00 00 00 02 58 80
- 15 01 00 00 00 00 02 59 01
- 15 01 00 00 00 00 02 5a 00
- 15 01 00 00 00 00 02 5b 01
- 15 01 00 00 00 00 02 5c 80
- 15 01 00 00 00 00 02 5d 81
- 15 01 00 00 00 00 02 5e 00
- 15 01 00 00 00 00 02 5f 01
- 15 01 00 00 00 00 02 72 31
- 15 01 00 00 00 00 02 68 03
- /* CMD2_P4 */
- 15 01 00 00 00 00 02 ff 24
- 15 01 00 00 00 00 02 fb 01
- 15 01 00 00 00 00 02 00 1c
- 15 01 00 00 00 00 02 01 0b
- 15 01 00 00 00 00 02 02 0c
- 15 01 00 00 00 00 02 03 01
- 15 01 00 00 00 00 02 04 0f
- 15 01 00 00 00 00 02 05 10
- 15 01 00 00 00 00 02 06 10
- 15 01 00 00 00 00 02 07 10
- 15 01 00 00 00 00 02 08 89
- 15 01 00 00 00 00 02 09 8a
- 15 01 00 00 00 00 02 0a 13
- 15 01 00 00 00 00 02 0b 13
- 15 01 00 00 00 00 02 0c 15
- 15 01 00 00 00 00 02 0d 15
- 15 01 00 00 00 00 02 0e 17
- 15 01 00 00 00 00 02 0f 17
- 15 01 00 00 00 00 02 10 1c
- 15 01 00 00 00 00 02 11 0b
- 15 01 00 00 00 00 02 12 0c
- 15 01 00 00 00 00 02 13 01
- 15 01 00 00 00 00 02 14 0f
- 15 01 00 00 00 00 02 15 10
- 15 01 00 00 00 00 02 16 10
- 15 01 00 00 00 00 02 17 10
- 15 01 00 00 00 00 02 18 89
- 15 01 00 00 00 00 02 19 8a
- 15 01 00 00 00 00 02 1a 13
- 15 01 00 00 00 00 02 1b 13
- 15 01 00 00 00 00 02 1c 15
- 15 01 00 00 00 00 02 1d 15
- 15 01 00 00 00 00 02 1e 17
- 15 01 00 00 00 00 02 1f 17
- /* STV */
- 15 01 00 00 00 00 02 20 40
- 15 01 00 00 00 00 02 21 01
- 15 01 00 00 00 00 02 22 00
- 15 01 00 00 00 00 02 23 40
- 15 01 00 00 00 00 02 24 40
- 15 01 00 00 00 00 02 25 6d
- 15 01 00 00 00 00 02 26 40
- 15 01 00 00 00 00 02 27 40
- /* Vend */
- 15 01 00 00 00 00 02 e0 00
- 15 01 00 00 00 00 02 dc 21
- 15 01 00 00 00 00 02 dd 22
- 15 01 00 00 00 00 02 de 07
- 15 01 00 00 00 00 02 df 07
- 15 01 00 00 00 00 02 e3 6d
- 15 01 00 00 00 00 02 e1 07
- 15 01 00 00 00 00 02 e2 07
- /* UD */
- 15 01 00 00 00 00 02 29 d8
- 15 01 00 00 00 00 02 2a 2a
- /* CLK */
- 15 01 00 00 00 00 02 4b 03
- 15 01 00 00 00 00 02 4c 11
- 15 01 00 00 00 00 02 4d 10
- 15 01 00 00 00 00 02 4e 01
- 15 01 00 00 00 00 02 4f 01
- 15 01 00 00 00 00 02 50 10
- 15 01 00 00 00 00 02 51 00
- 15 01 00 00 00 00 02 52 80
- 15 01 00 00 00 00 02 53 00
- 15 01 00 00 00 00 02 56 00
- 15 01 00 00 00 00 02 54 07
- 15 01 00 00 00 00 02 58 07
- 15 01 00 00 00 00 02 55 25
- /* Reset XDONB */
- 15 01 00 00 00 00 02 5b 43
- 15 01 00 00 00 00 02 5c 00
- 15 01 00 00 00 00 02 5f 73
- 15 01 00 00 00 00 02 60 73
- 15 01 00 00 00 00 02 63 22
- 15 01 00 00 00 00 02 64 00
- 15 01 00 00 00 00 02 67 08
- 15 01 00 00 00 00 02 68 04
- /* Resolution:1440x2560*/
- 15 01 00 00 00 00 02 72 02
- /* mux */
- 15 01 00 00 00 00 02 7a 80
- 15 01 00 00 00 00 02 7b 91
- 15 01 00 00 00 00 02 7c d8
- 15 01 00 00 00 00 02 7d 60
- 15 01 00 00 00 00 02 7f 15
- 15 01 00 00 00 00 02 75 15
- /* ABOFF */
- 15 01 00 00 00 00 02 b3 c0
- 15 01 00 00 00 00 02 b4 00
- 15 01 00 00 00 00 02 b5 00
- /* Source EQ */
- 15 01 00 00 00 00 02 78 00
- 15 01 00 00 00 00 02 79 00
- 15 01 00 00 00 00 02 80 00
- 15 01 00 00 00 00 02 83 00
- /* FP BP */
- 15 01 00 00 00 00 02 93 0a
- 15 01 00 00 00 00 02 94 0a
- /* Inversion Type */
- 15 01 00 00 00 00 02 8a 00
- 15 01 00 00 00 00 02 9b ff
- /* IMGSWAP =1 @PortSwap=1 */
- 15 01 00 00 00 00 02 9d b0
- 15 01 00 00 00 00 02 9f 63
- 15 01 00 00 00 00 02 98 10
- /* FRM */
- 15 01 00 00 00 00 02 ec 00
- /* CMD1 */
- 15 01 00 00 00 00 02 ff 10
- /* VESA DSC PPS settings(1440x2560 slide 16H) */
- 39 01 00 00 00 00 11 c1 09 20 00 10 02 00 02 68 01
- bb 00 0a 06 67 04 c5
- 39 01 00 00 00 00 03 c2 10 f0
- /* C0h = 0x00(2 Port SDC); 0x01(1 PortA FBC);
- * 0x02(MTK); 0x03(1 PortA VESA)
- */
- 15 01 00 00 00 00 02 c0 03
- /* VBP+VSA=,VFP = 10H */
- 39 01 00 00 00 00 04 3b 03 0a 0a
- /* FTE on */
- 15 01 00 00 00 00 02 35 00
- /* EN_BK =1(auto black) */
- 15 01 00 00 00 00 02 e5 01
- /* CMD mode(10) VDO mode(03) */
- 15 01 00 00 00 00 02 bb 03
- /* Non Reload MTP */
- 15 01 00 00 00 00 02 fb 01
- /* SlpOut + DispOn */
- 05 01 00 00 78 00 02 11 00
- 05 01 00 00 78 00 02 29 00
- ];
- qcom,mdss-dsi-off-command = [05 01 00 00 78 00 02 28 00
- 05 01 00 00 78 00 02 10 00];
- qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
- qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
- qcom,mdss-dsi-h-sync-pulse = <0>;
qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
qcom,mdss-dsi-bllp-eof-power-mode;
qcom,mdss-dsi-bllp-power-mode;
@@ -212,12 +38,195 @@
qcom,mdss-pan-physical-width-dimension = <74>;
qcom,mdss-pan-physical-height-dimension = <131>;
- qcom,compression-mode = "dsc";
- qcom,mdss-dsc-slice-height = <16>;
- qcom,mdss-dsc-slice-width = <720>;
- qcom,mdss-dsc-slice-per-pkt = <2>;
- qcom,mdss-dsc-bit-per-component = <8>;
- qcom,mdss-dsc-bit-per-pixel = <8>;
- qcom,mdss-dsc-block-prediction-enable;
+ qcom,mdss-dsi-display-timings {
+ timing@0{
+ qcom,mdss-dsi-panel-width = <1440>;
+ qcom,mdss-dsi-panel-height = <2560>;
+ qcom,mdss-dsi-h-front-porch = <100>;
+ qcom,mdss-dsi-h-back-porch = <32>;
+ qcom,mdss-dsi-h-pulse-width = <16>;
+ qcom,mdss-dsi-h-sync-skew = <0>;
+ qcom,mdss-dsi-v-back-porch = <8>;
+ qcom,mdss-dsi-v-front-porch = <10>;
+ qcom,mdss-dsi-v-pulse-width = <2>;
+ qcom,mdss-dsi-panel-framerate = <60>;
+ qcom,mdss-dsi-on-command = [
+ /* CMD2_P0 */
+ 15 01 00 00 00 00 02 ff 20
+ 15 01 00 00 00 00 02 fb 01
+ 15 01 00 00 00 00 02 00 01
+ 15 01 00 00 00 00 02 01 55
+ 15 01 00 00 00 00 02 02 45
+ 15 01 00 00 00 00 02 05 40
+ 15 01 00 00 00 00 02 06 19
+ 15 01 00 00 00 00 02 07 1e
+ 15 01 00 00 00 00 02 0b 73
+ 15 01 00 00 00 00 02 0c 73
+ 15 01 00 00 00 00 02 0e b0
+ 15 01 00 00 00 00 02 0f aE
+ 15 01 00 00 00 00 02 11 b8
+ 15 01 00 00 00 00 02 13 00
+ 15 01 00 00 00 00 02 58 80
+ 15 01 00 00 00 00 02 59 01
+ 15 01 00 00 00 00 02 5a 00
+ 15 01 00 00 00 00 02 5b 01
+ 15 01 00 00 00 00 02 5c 80
+ 15 01 00 00 00 00 02 5d 81
+ 15 01 00 00 00 00 02 5e 00
+ 15 01 00 00 00 00 02 5f 01
+ 15 01 00 00 00 00 02 72 31
+ 15 01 00 00 00 00 02 68 03
+ /* CMD2_P4 */
+ 15 01 00 00 00 00 02 ff 24
+ 15 01 00 00 00 00 02 fb 01
+ 15 01 00 00 00 00 02 00 1c
+ 15 01 00 00 00 00 02 01 0b
+ 15 01 00 00 00 00 02 02 0c
+ 15 01 00 00 00 00 02 03 01
+ 15 01 00 00 00 00 02 04 0f
+ 15 01 00 00 00 00 02 05 10
+ 15 01 00 00 00 00 02 06 10
+ 15 01 00 00 00 00 02 07 10
+ 15 01 00 00 00 00 02 08 89
+ 15 01 00 00 00 00 02 09 8a
+ 15 01 00 00 00 00 02 0a 13
+ 15 01 00 00 00 00 02 0b 13
+ 15 01 00 00 00 00 02 0c 15
+ 15 01 00 00 00 00 02 0d 15
+ 15 01 00 00 00 00 02 0e 17
+ 15 01 00 00 00 00 02 0f 17
+ 15 01 00 00 00 00 02 10 1c
+ 15 01 00 00 00 00 02 11 0b
+ 15 01 00 00 00 00 02 12 0c
+ 15 01 00 00 00 00 02 13 01
+ 15 01 00 00 00 00 02 14 0f
+ 15 01 00 00 00 00 02 15 10
+ 15 01 00 00 00 00 02 16 10
+ 15 01 00 00 00 00 02 17 10
+ 15 01 00 00 00 00 02 18 89
+ 15 01 00 00 00 00 02 19 8a
+ 15 01 00 00 00 00 02 1a 13
+ 15 01 00 00 00 00 02 1b 13
+ 15 01 00 00 00 00 02 1c 15
+ 15 01 00 00 00 00 02 1d 15
+ 15 01 00 00 00 00 02 1e 17
+ 15 01 00 00 00 00 02 1f 17
+ /* STV */
+ 15 01 00 00 00 00 02 20 40
+ 15 01 00 00 00 00 02 21 01
+ 15 01 00 00 00 00 02 22 00
+ 15 01 00 00 00 00 02 23 40
+ 15 01 00 00 00 00 02 24 40
+ 15 01 00 00 00 00 02 25 6d
+ 15 01 00 00 00 00 02 26 40
+ 15 01 00 00 00 00 02 27 40
+ /* Vend */
+ 15 01 00 00 00 00 02 e0 00
+ 15 01 00 00 00 00 02 dc 21
+ 15 01 00 00 00 00 02 dd 22
+ 15 01 00 00 00 00 02 de 07
+ 15 01 00 00 00 00 02 df 07
+ 15 01 00 00 00 00 02 e3 6d
+ 15 01 00 00 00 00 02 e1 07
+ 15 01 00 00 00 00 02 e2 07
+ /* UD */
+ 15 01 00 00 00 00 02 29 d8
+ 15 01 00 00 00 00 02 2a 2a
+ /* CLK */
+ 15 01 00 00 00 00 02 4b 03
+ 15 01 00 00 00 00 02 4c 11
+ 15 01 00 00 00 00 02 4d 10
+ 15 01 00 00 00 00 02 4e 01
+ 15 01 00 00 00 00 02 4f 01
+ 15 01 00 00 00 00 02 50 10
+ 15 01 00 00 00 00 02 51 00
+ 15 01 00 00 00 00 02 52 80
+ 15 01 00 00 00 00 02 53 00
+ 15 01 00 00 00 00 02 56 00
+ 15 01 00 00 00 00 02 54 07
+ 15 01 00 00 00 00 02 58 07
+ 15 01 00 00 00 00 02 55 25
+ /* Reset XDONB */
+ 15 01 00 00 00 00 02 5b 43
+ 15 01 00 00 00 00 02 5c 00
+ 15 01 00 00 00 00 02 5f 73
+ 15 01 00 00 00 00 02 60 73
+ 15 01 00 00 00 00 02 63 22
+ 15 01 00 00 00 00 02 64 00
+ 15 01 00 00 00 00 02 67 08
+ 15 01 00 00 00 00 02 68 04
+ /* Resolution:1440x2560*/
+ 15 01 00 00 00 00 02 72 02
+ /* mux */
+ 15 01 00 00 00 00 02 7a 80
+ 15 01 00 00 00 00 02 7b 91
+ 15 01 00 00 00 00 02 7c d8
+ 15 01 00 00 00 00 02 7d 60
+ 15 01 00 00 00 00 02 7f 15
+ 15 01 00 00 00 00 02 75 15
+ /* ABOFF */
+ 15 01 00 00 00 00 02 b3 c0
+ 15 01 00 00 00 00 02 b4 00
+ 15 01 00 00 00 00 02 b5 00
+ /* Source EQ */
+ 15 01 00 00 00 00 02 78 00
+ 15 01 00 00 00 00 02 79 00
+ 15 01 00 00 00 00 02 80 00
+ 15 01 00 00 00 00 02 83 00
+ /* FP BP */
+ 15 01 00 00 00 00 02 93 0a
+ 15 01 00 00 00 00 02 94 0a
+ /* Inversion Type */
+ 15 01 00 00 00 00 02 8a 00
+ 15 01 00 00 00 00 02 9b ff
+ /* IMGSWAP =1 @PortSwap=1 */
+ 15 01 00 00 00 00 02 9d b0
+ 15 01 00 00 00 00 02 9f 63
+ 15 01 00 00 00 00 02 98 10
+ /* FRM */
+ 15 01 00 00 00 00 02 ec 00
+ /* CMD1 */
+ 15 01 00 00 00 00 02 ff 10
+ /* VESA DSC PPS settings
+ * (1440x2560 slide 16H)
+ */
+ 39 01 00 00 00 00 11 c1 09
+ 20 00 10 02 00 02 68 01 bb
+ 00 0a 06 67 04 c5
+
+ 39 01 00 00 00 00 03 c2 10 f0
+ /* C0h = 0x00(2 Port SDC);
+ * 0x01(1 PortA FBC);
+ * 0x02(MTK); 0x03(1 PortA VESA)
+ */
+ 15 01 00 00 00 00 02 c0 03
+ /* VBP+VSA=,VFP = 10H */
+ 39 01 00 00 00 00 04 3b 03 0a 0a
+ /* FTE on */
+ 15 01 00 00 00 00 02 35 00
+ /* EN_BK =1(auto black) */
+ 15 01 00 00 00 00 02 e5 01
+ /* CMD mode(10) VDO mode(03) */
+ 15 01 00 00 00 00 02 bb 03
+ /* Non Reload MTP */
+ 15 01 00 00 00 00 02 fb 01
+ /* SlpOut + DispOn */
+ 05 01 00 00 78 00 02 11 00
+ 05 01 00 00 78 00 02 29 00
+ ];
+ qcom,mdss-dsi-off-command = [05 01 00 00 78 00
+ 02 28 00 05 01 00 00 78 00 02 10 00];
+ qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+ qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+ qcom,mdss-dsi-h-sync-pulse = <0>;
+ qcom,compression-mode = "dsc";
+ qcom,mdss-dsc-slice-height = <16>;
+ qcom,mdss-dsc-slice-width = <720>;
+ qcom,mdss-dsc-slice-per-pkt = <2>;
+ qcom,mdss-dsc-bit-per-component = <8>;
+ qcom,mdss-dsc-bit-per-pixel = <8>;
+ qcom,mdss-dsc-block-prediction-enable;
+ };
+ };
};
};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi
index 647ea4e..87cabae 100644
--- a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi
@@ -15,27 +15,12 @@
qcom,mdss-dsi-panel-name =
"Dual nt35597 cmd mode dsi truly panel without DSC";
qcom,mdss-dsi-panel-type = "dsi_cmd_mode";
- qcom,mdss-dsi-panel-framerate = <60>;
qcom,mdss-dsi-virtual-channel-id = <0>;
qcom,mdss-dsi-stream = <0>;
- qcom,mdss-dsi-panel-width = <720>;
- qcom,mdss-dsi-panel-height = <2560>;
- qcom,mdss-dsi-h-front-porch = <100>;
- qcom,mdss-dsi-h-back-porch = <32>;
- qcom,mdss-dsi-h-pulse-width = <16>;
- qcom,mdss-dsi-h-sync-skew = <0>;
- qcom,mdss-dsi-v-back-porch = <7>;
- qcom,mdss-dsi-v-front-porch = <8>;
- qcom,mdss-dsi-v-pulse-width = <1>;
- qcom,mdss-dsi-h-left-border = <0>;
- qcom,mdss-dsi-h-right-border = <0>;
- qcom,mdss-dsi-v-top-border = <0>;
- qcom,mdss-dsi-v-bottom-border = <0>;
qcom,mdss-dsi-bpp = <24>;
qcom,mdss-dsi-color-order = "rgb_swap_rgb";
qcom,mdss-dsi-underflow-color = <0xff>;
qcom,mdss-dsi-border-color = <0>;
- qcom,mdss-dsi-h-sync-pulse = <0>;
qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
qcom,mdss-dsi-bllp-eof-power-mode;
qcom,mdss-dsi-bllp-power-mode;
@@ -45,6 +30,8 @@
qcom,mdss-dsi-lane-3-state;
qcom,adjust-timer-wakeup-ms = <1>;
qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>;
+ qcom,mdss-pan-physical-width-dimension = <74>;
+ qcom,mdss-pan-physical-height-dimension = <131>;
qcom,mdss-dsi-bl-max-level = <4095>;
qcom,mdss-dsi-dma-trigger = "trigger_sw";
qcom,mdss-dsi-mdp-trigger = "none";
@@ -59,167 +46,181 @@
17000 15500 30000 8000 3000>;
qcom,mdss-dsi-panel-peak-brightness = <4200000>;
qcom,mdss-dsi-panel-blackness-level = <3230>;
- qcom,mdss-dsi-on-command = [
- /* CMD2_P0 */
- 15 01 00 00 00 00 02 FF 20
- 15 01 00 00 00 00 02 fb 01
- 15 01 00 00 00 00 02 00 01
- 15 01 00 00 00 00 02 01 55
- 15 01 00 00 00 00 02 02 45
- 15 01 00 00 00 00 02 05 40
- 15 01 00 00 00 00 02 06 19
- 15 01 00 00 00 00 02 07 1E
- 15 01 00 00 00 00 02 0B 73
- 15 01 00 00 00 00 02 0C 73
- 15 01 00 00 00 00 02 0E B0
- 15 01 00 00 00 00 02 0F AE
- 15 01 00 00 00 00 02 11 B8
- 15 01 00 00 00 00 02 13 00
- 15 01 00 00 00 00 02 58 80
- 15 01 00 00 00 00 02 59 01
- 15 01 00 00 00 00 02 5A 00
- 15 01 00 00 00 00 02 5B 01
- 15 01 00 00 00 00 02 5C 80
- 15 01 00 00 00 00 02 5D 81
- 15 01 00 00 00 00 02 5E 00
- 15 01 00 00 00 00 02 5F 01
- 15 01 00 00 00 00 02 72 31
- 15 01 00 00 00 00 02 68 03
- /* CMD2_P4 */
- 15 01 00 00 00 00 02 ff 24
- 15 01 00 00 00 00 02 fb 01
- 15 01 00 00 00 00 02 00 1C
- 15 01 00 00 00 00 02 01 0B
- 15 01 00 00 00 00 02 02 0C
- 15 01 00 00 00 00 02 03 01
- 15 01 00 00 00 00 02 04 0F
- 15 01 00 00 00 00 02 05 10
- 15 01 00 00 00 00 02 06 10
- 15 01 00 00 00 00 02 07 10
- 15 01 00 00 00 00 02 08 89
- 15 01 00 00 00 00 02 09 8A
- 15 01 00 00 00 00 02 0A 13
- 15 01 00 00 00 00 02 0B 13
- 15 01 00 00 00 00 02 0C 15
- 15 01 00 00 00 00 02 0D 15
- 15 01 00 00 00 00 02 0E 17
- 15 01 00 00 00 00 02 0F 17
- 15 01 00 00 00 00 02 10 1C
- 15 01 00 00 00 00 02 11 0B
- 15 01 00 00 00 00 02 12 0C
- 15 01 00 00 00 00 02 13 01
- 15 01 00 00 00 00 02 14 0F
- 15 01 00 00 00 00 02 15 10
- 15 01 00 00 00 00 02 16 10
- 15 01 00 00 00 00 02 17 10
- 15 01 00 00 00 00 02 18 89
- 15 01 00 00 00 00 02 19 8A
- 15 01 00 00 00 00 02 1A 13
- 15 01 00 00 00 00 02 1B 13
- 15 01 00 00 00 00 02 1C 15
- 15 01 00 00 00 00 02 1D 15
- 15 01 00 00 00 00 02 1E 17
- 15 01 00 00 00 00 02 1F 17
- /* STV */
- 15 01 00 00 00 00 02 20 40
- 15 01 00 00 00 00 02 21 01
- 15 01 00 00 00 00 02 22 00
- 15 01 00 00 00 00 02 23 40
- 15 01 00 00 00 00 02 24 40
- 15 01 00 00 00 00 02 25 6D
- 15 01 00 00 00 00 02 26 40
- 15 01 00 00 00 00 02 27 40
- /* Vend */
- 15 01 00 00 00 00 02 E0 00
- 15 01 00 00 00 00 02 DC 21
- 15 01 00 00 00 00 02 DD 22
- 15 01 00 00 00 00 02 DE 07
- 15 01 00 00 00 00 02 DF 07
- 15 01 00 00 00 00 02 E3 6D
- 15 01 00 00 00 00 02 E1 07
- 15 01 00 00 00 00 02 E2 07
- /* UD */
- 15 01 00 00 00 00 02 29 D8
- 15 01 00 00 00 00 02 2A 2A
- /* CLK */
- 15 01 00 00 00 00 02 4B 03
- 15 01 00 00 00 00 02 4C 11
- 15 01 00 00 00 00 02 4D 10
- 15 01 00 00 00 00 02 4E 01
- 15 01 00 00 00 00 02 4F 01
- 15 01 00 00 00 00 02 50 10
- 15 01 00 00 00 00 02 51 00
- 15 01 00 00 00 00 02 52 80
- 15 01 00 00 00 00 02 53 00
- 15 01 00 00 00 00 02 56 00
- 15 01 00 00 00 00 02 54 07
- 15 01 00 00 00 00 02 58 07
- 15 01 00 00 00 00 02 55 25
- /* Reset XDONB */
- 15 01 00 00 00 00 02 5B 43
- 15 01 00 00 00 00 02 5C 00
- 15 01 00 00 00 00 02 5F 73
- 15 01 00 00 00 00 02 60 73
- 15 01 00 00 00 00 02 63 22
- 15 01 00 00 00 00 02 64 00
- 15 01 00 00 00 00 02 67 08
- 15 01 00 00 00 00 02 68 04
- /* Resolution:1440x2560*/
- 15 01 00 00 00 00 02 72 02
- /* mux */
- 15 01 00 00 00 00 02 7A 80
- 15 01 00 00 00 00 02 7B 91
- 15 01 00 00 00 00 02 7C D8
- 15 01 00 00 00 00 02 7D 60
- 15 01 00 00 00 00 02 7F 15
- 15 01 00 00 00 00 02 75 15
- /* ABOFF */
- 15 01 00 00 00 00 02 B3 C0
- 15 01 00 00 00 00 02 B4 00
- 15 01 00 00 00 00 02 B5 00
- /* Source EQ */
- 15 01 00 00 00 00 02 78 00
- 15 01 00 00 00 00 02 79 00
- 15 01 00 00 00 00 02 80 00
- 15 01 00 00 00 00 02 83 00
- /* FP BP */
- 15 01 00 00 00 00 02 93 0A
- 15 01 00 00 00 00 02 94 0A
- /* Inversion Type */
- 15 01 00 00 00 00 02 8A 00
- 15 01 00 00 00 00 02 9B FF
- /* IMGSWAP =1 @PortSwap=1 */
- 15 01 00 00 00 00 02 9D B0
- 15 01 00 00 00 00 02 9F 63
- 15 01 00 00 00 00 02 98 10
- /* FRM */
- 15 01 00 00 00 00 02 EC 00
- /* CMD1 */
- 15 01 00 00 00 00 02 ff 10
- /* VBP+VSA=,VFP = 10H */
- 15 01 00 00 00 00 04 3B 03 0A 0A
- /* FTE on */
- 15 01 00 00 00 00 02 35 00
- /* EN_BK =1(auto black) */
- 15 01 00 00 00 00 02 E5 01
- /* CMD mode(10) VDO mode(03) */
- 15 01 00 00 00 00 02 BB 10
- /* Non Reload MTP */
- 15 01 00 00 00 00 02 FB 01
- /* SlpOut + DispOn */
- 05 01 00 00 78 00 02 11 00
- 05 01 00 00 78 00 02 29 00
- ];
- qcom,mdss-dsi-off-command = [05 01 00 00 78 00 02 28 00
- 05 01 00 00 78 00 02 10 00];
- qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
- qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
-
- qcom,config-select = <&dsi_dual_nt35597_truly_cmd_config0>;
-
- dsi_dual_nt35597_truly_cmd_config0: config0 {
- qcom,split-mode = "dualctl-split";
+ qcom,mdss-dsi-display-timings {
+ timing@0{
+ qcom,mdss-dsi-panel-framerate = <60>;
+ qcom,mdss-dsi-panel-width = <720>;
+ qcom,mdss-dsi-panel-height = <2560>;
+ qcom,mdss-dsi-h-front-porch = <100>;
+ qcom,mdss-dsi-h-back-porch = <32>;
+ qcom,mdss-dsi-h-pulse-width = <16>;
+ qcom,mdss-dsi-h-sync-skew = <0>;
+ qcom,mdss-dsi-v-back-porch = <7>;
+ qcom,mdss-dsi-v-front-porch = <8>;
+ qcom,mdss-dsi-v-pulse-width = <1>;
+ qcom,mdss-dsi-h-left-border = <0>;
+ qcom,mdss-dsi-h-right-border = <0>;
+ qcom,mdss-dsi-v-top-border = <0>;
+ qcom,mdss-dsi-v-bottom-border = <0>;
+ qcom,mdss-dsi-h-sync-pulse = <0>;
+ qcom,mdss-dsi-panel-jitter = <0x1 0x1>;
+ qcom,mdss-dsi-on-command = [
+ /* CMD2_P0 */
+ 15 01 00 00 00 00 02 FF 20
+ 15 01 00 00 00 00 02 fb 01
+ 15 01 00 00 00 00 02 00 01
+ 15 01 00 00 00 00 02 01 55
+ 15 01 00 00 00 00 02 02 45
+ 15 01 00 00 00 00 02 05 40
+ 15 01 00 00 00 00 02 06 19
+ 15 01 00 00 00 00 02 07 1E
+ 15 01 00 00 00 00 02 0B 73
+ 15 01 00 00 00 00 02 0C 73
+ 15 01 00 00 00 00 02 0E B0
+ 15 01 00 00 00 00 02 0F AE
+ 15 01 00 00 00 00 02 11 B8
+ 15 01 00 00 00 00 02 13 00
+ 15 01 00 00 00 00 02 58 80
+ 15 01 00 00 00 00 02 59 01
+ 15 01 00 00 00 00 02 5A 00
+ 15 01 00 00 00 00 02 5B 01
+ 15 01 00 00 00 00 02 5C 80
+ 15 01 00 00 00 00 02 5D 81
+ 15 01 00 00 00 00 02 5E 00
+ 15 01 00 00 00 00 02 5F 01
+ 15 01 00 00 00 00 02 72 31
+ 15 01 00 00 00 00 02 68 03
+ /* CMD2_P4 */
+ 15 01 00 00 00 00 02 ff 24
+ 15 01 00 00 00 00 02 fb 01
+ 15 01 00 00 00 00 02 00 1C
+ 15 01 00 00 00 00 02 01 0B
+ 15 01 00 00 00 00 02 02 0C
+ 15 01 00 00 00 00 02 03 01
+ 15 01 00 00 00 00 02 04 0F
+ 15 01 00 00 00 00 02 05 10
+ 15 01 00 00 00 00 02 06 10
+ 15 01 00 00 00 00 02 07 10
+ 15 01 00 00 00 00 02 08 89
+ 15 01 00 00 00 00 02 09 8A
+ 15 01 00 00 00 00 02 0A 13
+ 15 01 00 00 00 00 02 0B 13
+ 15 01 00 00 00 00 02 0C 15
+ 15 01 00 00 00 00 02 0D 15
+ 15 01 00 00 00 00 02 0E 17
+ 15 01 00 00 00 00 02 0F 17
+ 15 01 00 00 00 00 02 10 1C
+ 15 01 00 00 00 00 02 11 0B
+ 15 01 00 00 00 00 02 12 0C
+ 15 01 00 00 00 00 02 13 01
+ 15 01 00 00 00 00 02 14 0F
+ 15 01 00 00 00 00 02 15 10
+ 15 01 00 00 00 00 02 16 10
+ 15 01 00 00 00 00 02 17 10
+ 15 01 00 00 00 00 02 18 89
+ 15 01 00 00 00 00 02 19 8A
+ 15 01 00 00 00 00 02 1A 13
+ 15 01 00 00 00 00 02 1B 13
+ 15 01 00 00 00 00 02 1C 15
+ 15 01 00 00 00 00 02 1D 15
+ 15 01 00 00 00 00 02 1E 17
+ 15 01 00 00 00 00 02 1F 17
+ /* STV */
+ 15 01 00 00 00 00 02 20 40
+ 15 01 00 00 00 00 02 21 01
+ 15 01 00 00 00 00 02 22 00
+ 15 01 00 00 00 00 02 23 40
+ 15 01 00 00 00 00 02 24 40
+ 15 01 00 00 00 00 02 25 6D
+ 15 01 00 00 00 00 02 26 40
+ 15 01 00 00 00 00 02 27 40
+ /* Vend */
+ 15 01 00 00 00 00 02 E0 00
+ 15 01 00 00 00 00 02 DC 21
+ 15 01 00 00 00 00 02 DD 22
+ 15 01 00 00 00 00 02 DE 07
+ 15 01 00 00 00 00 02 DF 07
+ 15 01 00 00 00 00 02 E3 6D
+ 15 01 00 00 00 00 02 E1 07
+ 15 01 00 00 00 00 02 E2 07
+ /* UD */
+ 15 01 00 00 00 00 02 29 D8
+ 15 01 00 00 00 00 02 2A 2A
+ /* CLK */
+ 15 01 00 00 00 00 02 4B 03
+ 15 01 00 00 00 00 02 4C 11
+ 15 01 00 00 00 00 02 4D 10
+ 15 01 00 00 00 00 02 4E 01
+ 15 01 00 00 00 00 02 4F 01
+ 15 01 00 00 00 00 02 50 10
+ 15 01 00 00 00 00 02 51 00
+ 15 01 00 00 00 00 02 52 80
+ 15 01 00 00 00 00 02 53 00
+ 15 01 00 00 00 00 02 56 00
+ 15 01 00 00 00 00 02 54 07
+ 15 01 00 00 00 00 02 58 07
+ 15 01 00 00 00 00 02 55 25
+ /* Reset XDONB */
+ 15 01 00 00 00 00 02 5B 43
+ 15 01 00 00 00 00 02 5C 00
+ 15 01 00 00 00 00 02 5F 73
+ 15 01 00 00 00 00 02 60 73
+ 15 01 00 00 00 00 02 63 22
+ 15 01 00 00 00 00 02 64 00
+ 15 01 00 00 00 00 02 67 08
+ 15 01 00 00 00 00 02 68 04
+ /* Resolution:1440x2560*/
+ 15 01 00 00 00 00 02 72 02
+ /* mux */
+ 15 01 00 00 00 00 02 7A 80
+ 15 01 00 00 00 00 02 7B 91
+ 15 01 00 00 00 00 02 7C D8
+ 15 01 00 00 00 00 02 7D 60
+ 15 01 00 00 00 00 02 7F 15
+ 15 01 00 00 00 00 02 75 15
+ /* ABOFF */
+ 15 01 00 00 00 00 02 B3 C0
+ 15 01 00 00 00 00 02 B4 00
+ 15 01 00 00 00 00 02 B5 00
+ /* Source EQ */
+ 15 01 00 00 00 00 02 78 00
+ 15 01 00 00 00 00 02 79 00
+ 15 01 00 00 00 00 02 80 00
+ 15 01 00 00 00 00 02 83 00
+ /* FP BP */
+ 15 01 00 00 00 00 02 93 0A
+ 15 01 00 00 00 00 02 94 0A
+ /* Inversion Type */
+ 15 01 00 00 00 00 02 8A 00
+ 15 01 00 00 00 00 02 9B FF
+ /* IMGSWAP =1 @PortSwap=1 */
+ 15 01 00 00 00 00 02 9D B0
+ 15 01 00 00 00 00 02 9F 63
+ 15 01 00 00 00 00 02 98 10
+ /* FRM */
+ 15 01 00 00 00 00 02 EC 00
+ /* CMD1 */
+ 15 01 00 00 00 00 02 ff 10
+ /* VBP+VSA=,VFP = 10H */
+ 15 01 00 00 00 00 04 3B 03 0A 0A
+ /* FTE on */
+ 15 01 00 00 00 00 02 35 00
+ /* EN_BK =1(auto black) */
+ 15 01 00 00 00 00 02 E5 01
+ /* CMD mode(10) VDO mode(03) */
+ 15 01 00 00 00 00 02 BB 10
+ /* Non Reload MTP */
+ 15 01 00 00 00 00 02 FB 01
+ /* SlpOut + DispOn */
+ 05 01 00 00 78 00 02 11 00
+ 05 01 00 00 78 00 02 29 00
+ ];
+ qcom,mdss-dsi-off-command = [05 01 00 00 78 00
+ 02 28 00 05 01 00 00 78 00 02 10 00];
+ qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+ qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+ };
};
};
};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi
index 346a8b4..0d0e7f7 100644
--- a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi
@@ -15,182 +15,13 @@
qcom,mdss-dsi-panel-name =
"Dual nt35597 video mode dsi truly panel without DSC";
qcom,mdss-dsi-panel-type = "dsi_video_mode";
- qcom,mdss-dsi-panel-framerate = <60>;
qcom,mdss-dsi-virtual-channel-id = <0>;
qcom,mdss-dsi-stream = <0>;
- qcom,mdss-dsi-panel-width = <720>;
- qcom,mdss-dsi-panel-height = <2560>;
- qcom,mdss-dsi-h-front-porch = <100>;
- qcom,mdss-dsi-h-back-porch = <32>;
- qcom,mdss-dsi-h-pulse-width = <16>;
- qcom,mdss-dsi-h-sync-skew = <0>;
- qcom,mdss-dsi-v-back-porch = <7>;
- qcom,mdss-dsi-v-front-porch = <8>;
- qcom,mdss-dsi-v-pulse-width = <1>;
- qcom,mdss-dsi-bpp = <24>;
- qcom,mdss-dsi-underflow-color = <0x3ff>;
- qcom,mdss-dsi-border-color = <0>;
qcom,mdss-dsi-panel-hdr-enabled;
qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000
17000 15500 30000 8000 3000>;
qcom,mdss-dsi-panel-peak-brightness = <4200000>;
qcom,mdss-dsi-panel-blackness-level = <3230>;
- qcom,mdss-dsi-on-command = [
- /* CMD2_P0 */
- 15 01 00 00 00 00 02 FF 20
- 15 01 00 00 00 00 02 FB 01
- 15 01 00 00 00 00 02 00 01
- 15 01 00 00 00 00 02 01 55
- 15 01 00 00 00 00 02 02 45
- 15 01 00 00 00 00 02 05 40
- 15 01 00 00 00 00 02 06 19
- 15 01 00 00 00 00 02 07 1E
- 15 01 00 00 00 00 02 0B 73
- 15 01 00 00 00 00 02 0C 73
- 15 01 00 00 00 00 02 0E B0
- 15 01 00 00 00 00 02 0F AE
- 15 01 00 00 00 00 02 11 B8
- 15 01 00 00 00 00 02 13 00
- 15 01 00 00 00 00 02 58 80
- 15 01 00 00 00 00 02 59 01
- 15 01 00 00 00 00 02 5A 00
- 15 01 00 00 00 00 02 5B 01
- 15 01 00 00 00 00 02 5C 80
- 15 01 00 00 00 00 02 5D 81
- 15 01 00 00 00 00 02 5E 00
- 15 01 00 00 00 00 02 5F 01
- 15 01 00 00 00 00 02 72 31
- 15 01 00 00 00 00 02 68 03
- /* CMD2_P4 */
- 15 01 00 00 00 00 02 FF 24
- 15 01 00 00 00 00 02 FB 01
- 15 01 00 00 00 00 02 00 1C
- 15 01 00 00 00 00 02 01 0B
- 15 01 00 00 00 00 02 02 0C
- 15 01 00 00 00 00 02 03 01
- 15 01 00 00 00 00 02 04 0F
- 15 01 00 00 00 00 02 05 10
- 15 01 00 00 00 00 02 06 10
- 15 01 00 00 00 00 02 07 10
- 15 01 00 00 00 00 02 08 89
- 15 01 00 00 00 00 02 09 8A
- 15 01 00 00 00 00 02 0A 13
- 15 01 00 00 00 00 02 0B 13
- 15 01 00 00 00 00 02 0C 15
- 15 01 00 00 00 00 02 0D 15
- 15 01 00 00 00 00 02 0E 17
- 15 01 00 00 00 00 02 0F 17
- 15 01 00 00 00 00 02 10 1C
- 15 01 00 00 00 00 02 11 0B
- 15 01 00 00 00 00 02 12 0C
- 15 01 00 00 00 00 02 13 01
- 15 01 00 00 00 00 02 14 0F
- 15 01 00 00 00 00 02 15 10
- 15 01 00 00 00 00 02 16 10
- 15 01 00 00 00 00 02 17 10
- 15 01 00 00 00 00 02 18 89
- 15 01 00 00 00 00 02 19 8A
- 15 01 00 00 00 00 02 1A 13
- 15 01 00 00 00 00 02 1B 13
- 15 01 00 00 00 00 02 1C 15
- 15 01 00 00 00 00 02 1D 15
- 15 01 00 00 00 00 02 1E 17
- 15 01 00 00 00 00 02 1F 17
- /* STV */
- 15 01 00 00 00 00 02 20 40
- 15 01 00 00 00 00 02 21 01
- 15 01 00 00 00 00 02 22 00
- 15 01 00 00 00 00 02 23 40
- 15 01 00 00 00 00 02 24 40
- 15 01 00 00 00 00 02 25 6D
- 15 01 00 00 00 00 02 26 40
- 15 01 00 00 00 00 02 27 40
- /* Vend */
- 15 01 00 00 00 00 02 E0 00
- 15 01 00 00 00 00 02 DC 21
- 15 01 00 00 00 00 02 DD 22
- 15 01 00 00 00 00 02 DE 07
- 15 01 00 00 00 00 02 DF 07
- 15 01 00 00 00 00 02 E3 6D
- 15 01 00 00 00 00 02 E1 07
- 15 01 00 00 00 00 02 E2 07
- /* UD */
- 15 01 00 00 00 00 02 29 D8
- 15 01 00 00 00 00 02 2A 2A
- /* CLK */
- 15 01 00 00 00 00 02 4B 03
- 15 01 00 00 00 00 02 4C 11
- 15 01 00 00 00 00 02 4D 10
- 15 01 00 00 00 00 02 4E 01
- 15 01 00 00 00 00 02 4F 01
- 15 01 00 00 00 00 02 50 10
- 15 01 00 00 00 00 02 51 00
- 15 01 00 00 00 00 02 52 80
- 15 01 00 00 00 00 02 53 00
- 15 01 00 00 00 00 02 56 00
- 15 01 00 00 00 00 02 54 07
- 15 01 00 00 00 00 02 58 07
- 15 01 00 00 00 00 02 55 25
- /* Reset XDONB */
- 15 01 00 00 00 00 02 5B 43
- 15 01 00 00 00 00 02 5C 00
- 15 01 00 00 00 00 02 5F 73
- 15 01 00 00 00 00 02 60 73
- 15 01 00 00 00 00 02 63 22
- 15 01 00 00 00 00 02 64 00
- 15 01 00 00 00 00 02 67 08
- 15 01 00 00 00 00 02 68 04
- /* Resolution:1440x2560*/
- 15 01 00 00 00 00 02 72 02
- /* mux */
- 15 01 00 00 00 00 02 7A 80
- 15 01 00 00 00 00 02 7B 91
- 15 01 00 00 00 00 02 7C D8
- 15 01 00 00 00 00 02 7D 60
- 15 01 00 00 00 00 02 7F 15
- 15 01 00 00 00 00 02 75 15
- /* ABOFF */
- 15 01 00 00 00 00 02 B3 C0
- 15 01 00 00 00 00 02 B4 00
- 15 01 00 00 00 00 02 B5 00
- /* Source EQ */
- 15 01 00 00 00 00 02 78 00
- 15 01 00 00 00 00 02 79 00
- 15 01 00 00 00 00 02 80 00
- 15 01 00 00 00 00 02 83 00
- /* FP BP */
- 15 01 00 00 00 00 02 93 0A
- 15 01 00 00 00 00 02 94 0A
- /* Inversion Type */
- 15 01 00 00 00 00 02 8A 00
- 15 01 00 00 00 00 02 9B FF
- /* IMGSWAP =1 @PortSwap=1 */
- 15 01 00 00 00 00 02 9D B0
- 15 01 00 00 00 00 02 9F 63
- 15 01 00 00 00 00 02 98 10
- /* FRM */
- 15 01 00 00 00 00 02 EC 00
- /* CMD1 */
- 15 01 00 00 00 00 02 FF 10
- /* VBP+VSA=,VFP = 10H */
- 15 01 00 00 00 00 04 3B 03 0A 0A
- /* FTE on */
- 15 01 00 00 00 00 02 35 00
- /* EN_BK =1(auto black) */
- 15 01 00 00 00 00 02 E5 01
- /* CMD mode(10) VDO mode(03) */
- 15 01 00 00 00 00 02 BB 03
- /* Non Reload MTP */
- 15 01 00 00 00 00 02 FB 01
- /* SlpOut + DispOn */
- 05 01 00 00 78 00 02 11 00
- 05 01 00 00 78 00 02 29 00
- ];
- qcom,mdss-dsi-off-command = [05 01 00 00 78 00 02 28 00
- 05 01 00 00 78 00 02 10 00];
- qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
- qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
- qcom,mdss-dsi-h-sync-pulse = <0>;
qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
qcom,mdss-dsi-bllp-eof-power-mode;
qcom,mdss-dsi-bllp-power-mode;
@@ -202,14 +33,182 @@
qcom,mdss-dsi-dma-trigger = "trigger_sw";
qcom,mdss-dsi-mdp-trigger = "none";
qcom,mdss-dsi-reset-sequence = <1 20>, <0 20>, <1 50>;
+ qcom,mdss-pan-physical-width-dimension = <74>;
+ qcom,mdss-pan-physical-height-dimension = <131>;
qcom,mdss-dsi-tx-eot-append;
+ qcom,mdss-dsi-underflow-color = <0x3ff>;
+ qcom,mdss-dsi-border-color = <0>;
+ qcom,mdss-dsi-bpp = <24>;
- qcom,config-select = <&dsi_dual_nt35597_truly_video_config0>;
-
- dsi_dual_nt35597_truly_video_config0: config0 {
- qcom,split-mode = "dualctl-split";
+ qcom,mdss-dsi-display-timings {
+ timing@0{
+ qcom,mdss-dsi-panel-width = <720>;
+ qcom,mdss-dsi-panel-height = <2560>;
+ qcom,mdss-dsi-h-front-porch = <100>;
+ qcom,mdss-dsi-h-back-porch = <32>;
+ qcom,mdss-dsi-h-pulse-width = <16>;
+ qcom,mdss-dsi-h-sync-skew = <0>;
+ qcom,mdss-dsi-v-back-porch = <7>;
+ qcom,mdss-dsi-v-front-porch = <8>;
+ qcom,mdss-dsi-v-pulse-width = <1>;
+ qcom,mdss-dsi-panel-framerate = <60>;
+ qcom,mdss-dsi-on-command = [
+ /* CMD2_P0 */
+ 15 01 00 00 00 00 02 FF 20
+ 15 01 00 00 00 00 02 FB 01
+ 15 01 00 00 00 00 02 00 01
+ 15 01 00 00 00 00 02 01 55
+ 15 01 00 00 00 00 02 02 45
+ 15 01 00 00 00 00 02 05 40
+ 15 01 00 00 00 00 02 06 19
+ 15 01 00 00 00 00 02 07 1E
+ 15 01 00 00 00 00 02 0B 73
+ 15 01 00 00 00 00 02 0C 73
+ 15 01 00 00 00 00 02 0E B0
+ 15 01 00 00 00 00 02 0F AE
+ 15 01 00 00 00 00 02 11 B8
+ 15 01 00 00 00 00 02 13 00
+ 15 01 00 00 00 00 02 58 80
+ 15 01 00 00 00 00 02 59 01
+ 15 01 00 00 00 00 02 5A 00
+ 15 01 00 00 00 00 02 5B 01
+ 15 01 00 00 00 00 02 5C 80
+ 15 01 00 00 00 00 02 5D 81
+ 15 01 00 00 00 00 02 5E 00
+ 15 01 00 00 00 00 02 5F 01
+ 15 01 00 00 00 00 02 72 31
+ 15 01 00 00 00 00 02 68 03
+ /* CMD2_P4 */
+ 15 01 00 00 00 00 02 FF 24
+ 15 01 00 00 00 00 02 FB 01
+ 15 01 00 00 00 00 02 00 1C
+ 15 01 00 00 00 00 02 01 0B
+ 15 01 00 00 00 00 02 02 0C
+ 15 01 00 00 00 00 02 03 01
+ 15 01 00 00 00 00 02 04 0F
+ 15 01 00 00 00 00 02 05 10
+ 15 01 00 00 00 00 02 06 10
+ 15 01 00 00 00 00 02 07 10
+ 15 01 00 00 00 00 02 08 89
+ 15 01 00 00 00 00 02 09 8A
+ 15 01 00 00 00 00 02 0A 13
+ 15 01 00 00 00 00 02 0B 13
+ 15 01 00 00 00 00 02 0C 15
+ 15 01 00 00 00 00 02 0D 15
+ 15 01 00 00 00 00 02 0E 17
+ 15 01 00 00 00 00 02 0F 17
+ 15 01 00 00 00 00 02 10 1C
+ 15 01 00 00 00 00 02 11 0B
+ 15 01 00 00 00 00 02 12 0C
+ 15 01 00 00 00 00 02 13 01
+ 15 01 00 00 00 00 02 14 0F
+ 15 01 00 00 00 00 02 15 10
+ 15 01 00 00 00 00 02 16 10
+ 15 01 00 00 00 00 02 17 10
+ 15 01 00 00 00 00 02 18 89
+ 15 01 00 00 00 00 02 19 8A
+ 15 01 00 00 00 00 02 1A 13
+ 15 01 00 00 00 00 02 1B 13
+ 15 01 00 00 00 00 02 1C 15
+ 15 01 00 00 00 00 02 1D 15
+ 15 01 00 00 00 00 02 1E 17
+ 15 01 00 00 00 00 02 1F 17
+ /* STV */
+ 15 01 00 00 00 00 02 20 40
+ 15 01 00 00 00 00 02 21 01
+ 15 01 00 00 00 00 02 22 00
+ 15 01 00 00 00 00 02 23 40
+ 15 01 00 00 00 00 02 24 40
+ 15 01 00 00 00 00 02 25 6D
+ 15 01 00 00 00 00 02 26 40
+ 15 01 00 00 00 00 02 27 40
+ /* Vend */
+ 15 01 00 00 00 00 02 E0 00
+ 15 01 00 00 00 00 02 DC 21
+ 15 01 00 00 00 00 02 DD 22
+ 15 01 00 00 00 00 02 DE 07
+ 15 01 00 00 00 00 02 DF 07
+ 15 01 00 00 00 00 02 E3 6D
+ 15 01 00 00 00 00 02 E1 07
+ 15 01 00 00 00 00 02 E2 07
+ /* UD */
+ 15 01 00 00 00 00 02 29 D8
+ 15 01 00 00 00 00 02 2A 2A
+ /* CLK */
+ 15 01 00 00 00 00 02 4B 03
+ 15 01 00 00 00 00 02 4C 11
+ 15 01 00 00 00 00 02 4D 10
+ 15 01 00 00 00 00 02 4E 01
+ 15 01 00 00 00 00 02 4F 01
+ 15 01 00 00 00 00 02 50 10
+ 15 01 00 00 00 00 02 51 00
+ 15 01 00 00 00 00 02 52 80
+ 15 01 00 00 00 00 02 53 00
+ 15 01 00 00 00 00 02 56 00
+ 15 01 00 00 00 00 02 54 07
+ 15 01 00 00 00 00 02 58 07
+ 15 01 00 00 00 00 02 55 25
+ /* Reset XDONB */
+ 15 01 00 00 00 00 02 5B 43
+ 15 01 00 00 00 00 02 5C 00
+ 15 01 00 00 00 00 02 5F 73
+ 15 01 00 00 00 00 02 60 73
+ 15 01 00 00 00 00 02 63 22
+ 15 01 00 00 00 00 02 64 00
+ 15 01 00 00 00 00 02 67 08
+ 15 01 00 00 00 00 02 68 04
+ /* Resolution:1440x2560*/
+ 15 01 00 00 00 00 02 72 02
+ /* mux */
+ 15 01 00 00 00 00 02 7A 80
+ 15 01 00 00 00 00 02 7B 91
+ 15 01 00 00 00 00 02 7C D8
+ 15 01 00 00 00 00 02 7D 60
+ 15 01 00 00 00 00 02 7F 15
+ 15 01 00 00 00 00 02 75 15
+ /* ABOFF */
+ 15 01 00 00 00 00 02 B3 C0
+ 15 01 00 00 00 00 02 B4 00
+ 15 01 00 00 00 00 02 B5 00
+ /* Source EQ */
+ 15 01 00 00 00 00 02 78 00
+ 15 01 00 00 00 00 02 79 00
+ 15 01 00 00 00 00 02 80 00
+ 15 01 00 00 00 00 02 83 00
+ /* FP BP */
+ 15 01 00 00 00 00 02 93 0A
+ 15 01 00 00 00 00 02 94 0A
+ /* Inversion Type */
+ 15 01 00 00 00 00 02 8A 00
+ 15 01 00 00 00 00 02 9B FF
+ /* IMGSWAP =1 @PortSwap=1 */
+ 15 01 00 00 00 00 02 9D B0
+ 15 01 00 00 00 00 02 9F 63
+ 15 01 00 00 00 00 02 98 10
+ /* FRM */
+ 15 01 00 00 00 00 02 EC 00
+ /* CMD1 */
+ 15 01 00 00 00 00 02 FF 10
+ /* VBP+VSA=,VFP = 10H */
+ 15 01 00 00 00 00 04 3B 03 0A 0A
+ /* FTE on */
+ 15 01 00 00 00 00 02 35 00
+ /* EN_BK =1(auto black) */
+ 15 01 00 00 00 00 02 E5 01
+ /* CMD mode(10) VDO mode(03) */
+ 15 01 00 00 00 00 02 BB 03
+ /* Non Reload MTP */
+ 15 01 00 00 00 00 02 FB 01
+ /* SlpOut + DispOn */
+ 05 01 00 00 78 00 02 11 00
+ 05 01 00 00 78 00 02 29 00
+ ];
+ qcom,mdss-dsi-off-command = [05 01 00 00 78 00
+ 02 28 00 05 01 00 00 78 00 02 10 00];
+ qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+ qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+ qcom,mdss-dsi-h-sync-pulse = <0>;
+ };
};
-
-
};
};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sharp-1080p-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-1080p-cmd.dtsi
index c2b054a..aebc8b9 100644
--- a/arch/arm64/boot/dts/qcom/dsi-panel-sharp-1080p-cmd.dtsi
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-1080p-cmd.dtsi
@@ -16,48 +16,15 @@
qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
qcom,mdss-dsi-panel-type = "dsi_cmd_mode";
qcom,mdss-dsi-panel-destination = "display_1";
- qcom,mdss-dsi-panel-framerate = <60>;
qcom,mdss-dsi-panel-clockrate = <850000000>;
qcom,mdss-dsi-virtual-channel-id = <0>;
qcom,mdss-dsi-stream = <0>;
- qcom,mdss-dsi-panel-width = <1080>;
- qcom,mdss-dsi-panel-height = <1920>;
- qcom,mdss-dsi-h-front-porch = <0>;
- qcom,mdss-dsi-h-back-porch = <0>;
- qcom,mdss-dsi-h-pulse-width = <0>;
- qcom,mdss-dsi-h-sync-skew = <0>;
- qcom,mdss-dsi-v-back-porch = <0>;
- qcom,mdss-dsi-v-front-porch = <0>;
- qcom,mdss-dsi-v-pulse-width = <0>;
- qcom,mdss-dsi-h-left-border = <0>;
- qcom,mdss-dsi-h-right-border = <0>;
- qcom,mdss-dsi-v-top-border = <0>;
- qcom,mdss-dsi-v-bottom-border = <0>;
qcom,mdss-dsi-bpp = <24>;
qcom,mdss-dsi-underflow-color = <0xff>;
qcom,mdss-dsi-border-color = <0>;
qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>;
- qcom,mdss-dsi-on-command = [
- 15 01 00 00 00 00 02 bb 10
- 15 01 00 00 00 00 02 b0 03
- 05 01 00 00 78 00 01 11
- 15 01 00 00 00 00 02 51 ff
- 15 01 00 00 00 00 02 53 24
- 15 01 00 00 00 00 02 ff 23
- 15 01 00 00 00 00 02 08 05
- 15 01 00 00 00 00 02 46 90
- 15 01 00 00 00 00 02 ff 10
- 15 01 00 00 00 00 02 ff f0
- 15 01 00 00 00 00 02 92 01
- 15 01 00 00 00 00 02 ff 10
- 15 01 00 00 00 00 02 35 00 /* enable TE generation */
- 05 01 00 00 28 00 01 29];
- qcom,mdss-dsi-off-command = [
- 05 01 00 00 10 00 01 28
- 05 01 00 00 40 00 01 10];
- qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
- qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
- qcom,mdss-dsi-h-sync-pulse = <0>;
+ qcom,mdss-pan-physical-width-dimension = <64>;
+ qcom,mdss-pan-physical-height-dimension = <117>;
qcom,mdss-dsi-traffic-mode = "burst_mode";
qcom,mdss-dsi-bllp-eof-power-mode;
qcom,mdss-dsi-bllp-power-mode;
@@ -74,5 +41,46 @@
qcom,mdss-dsi-te-dcs-command = <1>;
qcom,mdss-dsi-te-check-enable;
qcom,mdss-dsi-te-using-te-pin;
+
+ qcom,mdss-dsi-display-timings {
+ timing@0{
+ qcom,mdss-dsi-panel-width = <1080>;
+ qcom,mdss-dsi-panel-height = <1920>;
+ qcom,mdss-dsi-h-front-porch = <0>;
+ qcom,mdss-dsi-h-back-porch = <0>;
+ qcom,mdss-dsi-h-pulse-width = <0>;
+ qcom,mdss-dsi-h-sync-skew = <0>;
+ qcom,mdss-dsi-v-back-porch = <0>;
+ qcom,mdss-dsi-v-front-porch = <0>;
+ qcom,mdss-dsi-v-pulse-width = <0>;
+ qcom,mdss-dsi-h-left-border = <0>;
+ qcom,mdss-dsi-h-right-border = <0>;
+ qcom,mdss-dsi-v-top-border = <0>;
+ qcom,mdss-dsi-v-bottom-border = <0>;
+ qcom,mdss-dsi-panel-framerate = <60>;
+ qcom,mdss-dsi-on-command = [
+ 15 01 00 00 00 00 02 bb 10
+ 15 01 00 00 00 00 02 b0 03
+ 05 01 00 00 78 00 01 11
+ 15 01 00 00 00 00 02 51 ff
+ 15 01 00 00 00 00 02 53 24
+ 15 01 00 00 00 00 02 ff 23
+ 15 01 00 00 00 00 02 08 05
+ 15 01 00 00 00 00 02 46 90
+ 15 01 00 00 00 00 02 ff 10
+ 15 01 00 00 00 00 02 ff f0
+ 15 01 00 00 00 00 02 92 01
+ 15 01 00 00 00 00 02 ff 10
+ /* enable TE generation */
+ 15 01 00 00 00 00 02 35 00
+ 05 01 00 00 28 00 01 29];
+ qcom,mdss-dsi-off-command = [
+ 05 01 00 00 10 00 01 28
+ 05 01 00 00 40 00 01 10];
+ qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+ qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+ qcom,mdss-dsi-h-sync-pulse = <0>;
+ };
+ };
};
};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-cmd.dtsi
index 6534cdc..ce849c6 100644
--- a/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-cmd.dtsi
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-cmd.dtsi
@@ -14,23 +14,10 @@
dsi_sharp_4k_dsc_cmd: qcom,mdss_dsi_sharp_4k_dsc_cmd {
qcom,mdss-dsi-panel-name = "Sharp 4k cmd mode dsc dsi panel";
qcom,mdss-dsi-panel-type = "dsi_cmd_mode";
- qcom,mdss-dsi-panel-framerate = <60>;
qcom,mdss-dsi-virtual-channel-id = <0>;
qcom,mdss-dsi-stream = <0>;
- qcom,mdss-dsi-panel-width = <1080>;
- qcom,mdss-dsi-panel-height = <3840>;
- qcom,mdss-dsi-h-front-porch = <30>;
- qcom,mdss-dsi-h-back-porch = <100>;
- qcom,mdss-dsi-h-pulse-width = <4>;
- qcom,mdss-dsi-h-sync-skew = <0>;
- qcom,mdss-dsi-v-back-porch = <7>;
- qcom,mdss-dsi-v-front-porch = <8>;
- qcom,mdss-dsi-v-pulse-width = <1>;
qcom,mdss-dsi-bpp = <24>;
qcom,mdss-dsi-border-color = <0>;
- qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
- qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
- qcom,mdss-dsi-h-sync-pulse = <0>;
qcom,mdss-dsi-traffic-mode = "burst_mode";
qcom,mdss-dsi-bllp-eof-power-mode;
qcom,mdss-dsi-bllp-power-mode;
@@ -41,6 +28,8 @@
qcom,mdss-dsi-dma-trigger = "trigger_sw";
qcom,mdss-dsi-mdp-trigger = "none";
qcom,mdss-dsi-reset-sequence = <1 100>, <0 100>, <1 100>;
+ qcom,mdss-pan-physical-width-dimension = <71>;
+ qcom,mdss-pan-physical-height-dimension = <129>;
qcom,mdss-dsi-te-pin-select = <1>;
qcom,mdss-dsi-wr-mem-start = <0x2c>;
qcom,mdss-dsi-wr-mem-continue = <0x3c>;
@@ -49,39 +38,61 @@
qcom,mdss-dsi-te-using-te-pin;
qcom,dcs-cmd-by-left;
qcom,mdss-dsi-tx-eot-append;
-
qcom,adjust-timer-wakeup-ms = <1>;
- qcom,mdss-dsi-on-command = [
- 39 01 00 00 00 00 11 91 09 20 00 20 02 00 03 1c 04 21 00
- 0f 03 19 01 97
- 39 01 00 00 00 00 03 92 10 f0
- 15 01 00 00 00 00 02 90 03
- 15 01 00 00 00 00 02 03 01
- 39 01 00 00 00 00 06 f0 55 aa 52 08 04
- 15 01 00 00 00 00 02 c0 03
- 39 01 00 00 00 00 06 f0 55 aa 52 08 07
- 15 01 00 00 00 00 02 ef 01
- 39 01 00 00 00 00 06 f0 55 aa 52 08 00
- 15 01 00 00 00 00 02 b4 01
- 15 01 00 00 00 00 02 35 00
- 39 01 00 00 00 00 06 f0 55 aa 52 08 01
- 39 01 00 00 00 00 05 ff aa 55 a5 80
- 15 01 00 00 00 00 02 6f 01
- 15 01 00 00 00 00 02 f3 10
- 39 01 00 00 00 00 05 ff aa 55 a5 00
- 05 01 00 00 78 00 01 11 /* sleep out + delay 120ms */
- 05 01 00 00 78 00 01 29 /* display on + delay 120ms */
- ];
- qcom,mdss-dsi-off-command = [05 01 00 00 78 00 02 28 00
- 05 01 00 00 78 00 02 10 00];
+ qcom,mdss-dsi-display-timings {
+ timing@0{
+ qcom,mdss-dsi-panel-width = <1080>;
+ qcom,mdss-dsi-panel-height = <3840>;
+ qcom,mdss-dsi-h-front-porch = <30>;
+ qcom,mdss-dsi-h-back-porch = <100>;
+ qcom,mdss-dsi-h-pulse-width = <4>;
+ qcom,mdss-dsi-h-sync-skew = <0>;
+ qcom,mdss-dsi-v-back-porch = <7>;
+ qcom,mdss-dsi-v-front-porch = <8>;
+ qcom,mdss-dsi-v-pulse-width = <1>;
+ qcom,mdss-dsi-h-sync-pulse = <0>;
+ qcom,mdss-dsi-panel-framerate = <60>;
+ qcom,mdss-dsi-panel-jitter = <0x8 0xa>;
- qcom,compression-mode = "dsc";
- qcom,mdss-dsc-slice-height = <32>;
- qcom,mdss-dsc-slice-width = <1080>;
- qcom,mdss-dsc-slice-per-pkt = <1>;
- qcom,mdss-dsc-bit-per-component = <8>;
- qcom,mdss-dsc-bit-per-pixel = <8>;
- qcom,mdss-dsc-block-prediction-enable;
+ qcom,mdss-dsi-on-command = [
+ 39 01 00 00 00 00 11 91 09 20 00 20 02
+ 00 03 1c 04 21 00
+ 0f 03 19 01 97
+ 39 01 00 00 00 00 03 92 10 f0
+ 15 01 00 00 00 00 02 90 03
+ 15 01 00 00 00 00 02 03 01
+ 39 01 00 00 00 00 06 f0 55 aa 52 08 04
+ 15 01 00 00 00 00 02 c0 03
+ 39 01 00 00 00 00 06 f0 55 aa 52 08 07
+ 15 01 00 00 00 00 02 ef 01
+ 39 01 00 00 00 00 06 f0 55 aa 52 08 00
+ 15 01 00 00 00 00 02 b4 01
+ 15 01 00 00 00 00 02 35 00
+ 39 01 00 00 00 00 06 f0 55 aa 52 08 01
+ 39 01 00 00 00 00 05 ff aa 55 a5 80
+ 15 01 00 00 00 00 02 6f 01
+ 15 01 00 00 00 00 02 f3 10
+ 39 01 00 00 00 00 05 ff aa 55 a5 00
+ /* sleep out + delay 120ms */
+ 05 01 00 00 78 00 01 11
+ /* display on + delay 120ms */
+ 05 01 00 00 78 00 01 29
+ ];
+ qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+ qcom,mdss-dsi-off-command =
+ [05 01 00 00 78 00 02 28 00
+ 05 01 00 00 78 00 02 10 00];
+ qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+
+ qcom,compression-mode = "dsc";
+ qcom,mdss-dsc-slice-height = <32>;
+ qcom,mdss-dsc-slice-width = <1080>;
+ qcom,mdss-dsc-slice-per-pkt = <1>;
+ qcom,mdss-dsc-bit-per-component = <8>;
+ qcom,mdss-dsc-bit-per-pixel = <8>;
+ qcom,mdss-dsc-block-prediction-enable;
+ };
+ };
};
};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-video.dtsi
index b314e99..d3411c8 100644
--- a/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-video.dtsi
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-video.dtsi
@@ -14,23 +14,10 @@
dsi_sharp_4k_dsc_video: qcom,mdss_dsi_sharp_4k_dsc_video {
qcom,mdss-dsi-panel-name = "Sharp 4k video mode dsc dsi panel";
qcom,mdss-dsi-panel-type = "dsi_video_mode";
- qcom,mdss-dsi-panel-framerate = <60>;
qcom,mdss-dsi-virtual-channel-id = <0>;
qcom,mdss-dsi-stream = <0>;
- qcom,mdss-dsi-panel-width = <1080>;
- qcom,mdss-dsi-panel-height = <3840>;
- qcom,mdss-dsi-h-front-porch = <30>;
- qcom,mdss-dsi-h-back-porch = <100>;
- qcom,mdss-dsi-h-pulse-width = <4>;
- qcom,mdss-dsi-h-sync-skew = <0>;
- qcom,mdss-dsi-v-back-porch = <7>;
- qcom,mdss-dsi-v-front-porch = <8>;
- qcom,mdss-dsi-v-pulse-width = <1>;
qcom,mdss-dsi-bpp = <24>;
qcom,mdss-dsi-border-color = <0>;
- qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
- qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
- qcom,mdss-dsi-h-sync-pulse = <0>;
qcom,mdss-dsi-traffic-mode = "burst_mode";
qcom,mdss-dsi-bllp-eof-power-mode;
qcom,mdss-dsi-bllp-power-mode;
@@ -41,40 +28,64 @@
qcom,mdss-dsi-dma-trigger = "trigger_sw";
qcom,mdss-dsi-mdp-trigger = "none";
qcom,mdss-dsi-reset-sequence = <1 100>, <0 100>, <1 100>;
+ qcom,mdss-pan-physical-width-dimension = <71>;
+ qcom,mdss-pan-physical-height-dimension = <129>;
qcom,mdss-dsi-tx-eot-append;
qcom,adjust-timer-wakeup-ms = <1>;
- qcom,mdss-dsi-on-command = [
- 39 01 00 00 00 00 11 91 09 20 00 20 02 00 03 1c 04 21 00
- 0f 03 19 01 97
- 39 01 00 00 00 00 03 92 10 f0
- 15 01 00 00 00 00 02 90 03
- 15 01 00 00 00 00 02 03 01
- 39 01 00 00 00 00 06 f0 55 aa 52 08 04
- 15 01 00 00 00 00 02 c0 03
- 39 01 00 00 00 00 06 f0 55 aa 52 08 07
- 15 01 00 00 00 00 02 ef 01
- 39 01 00 00 00 00 06 f0 55 aa 52 08 00
- 15 01 00 00 00 00 02 b4 10
- 15 01 00 00 00 00 02 35 00
- 39 01 00 00 00 00 06 f0 55 aa 52 08 01
- 39 01 00 00 00 00 05 ff aa 55 a5 80
- 15 01 00 00 00 00 02 6f 01
- 15 01 00 00 00 00 02 f3 10
- 39 01 00 00 00 00 05 ff aa 55 a5 00
- 05 01 00 00 78 00 01 11 /* sleep out + delay 120ms */
- 05 01 00 00 78 00 01 29 /* display on + delay 120ms */
- ];
- qcom,mdss-dsi-off-command = [05 01 00 00 78 00 02 28 00
- 05 01 00 00 78 00 02 10 00];
+ qcom,mdss-dsi-display-timings {
+ timing@0{
+ qcom,mdss-dsi-panel-width = <1080>;
+ qcom,mdss-dsi-panel-height = <3840>;
+ qcom,mdss-dsi-h-front-porch = <30>;
+ qcom,mdss-dsi-h-back-porch = <100>;
+ qcom,mdss-dsi-h-pulse-width = <4>;
+ qcom,mdss-dsi-h-sync-skew = <0>;
+ qcom,mdss-dsi-v-back-porch = <7>;
+ qcom,mdss-dsi-v-front-porch = <8>;
+ qcom,mdss-dsi-v-pulse-width = <1>;
+ qcom,mdss-dsi-h-sync-pulse = <0>;
+ qcom,mdss-dsi-panel-framerate = <60>;
- qcom,compression-mode = "dsc";
- qcom,mdss-dsc-slice-height = <32>;
- qcom,mdss-dsc-slice-width = <1080>;
- qcom,mdss-dsc-slice-per-pkt = <1>;
- qcom,mdss-dsc-bit-per-component = <8>;
- qcom,mdss-dsc-bit-per-pixel = <8>;
- qcom,mdss-dsc-block-prediction-enable;
+ qcom,mdss-dsi-on-command = [
+ 39 01 00 00 00 00 11 91 09 20 00 20 02
+ 00 03 1c 04 21 00
+ 0f 03 19 01 97
+ 39 01 00 00 00 00 03 92 10 f0
+ 15 01 00 00 00 00 02 90 03
+ 15 01 00 00 00 00 02 03 01
+ 39 01 00 00 00 00 06 f0 55 aa 52 08 04
+ 15 01 00 00 00 00 02 c0 03
+ 39 01 00 00 00 00 06 f0 55 aa 52 08 07
+ 15 01 00 00 00 00 02 ef 01
+ 39 01 00 00 00 00 06 f0 55 aa 52 08 00
+ 15 01 00 00 00 00 02 b4 10
+ 15 01 00 00 00 00 02 35 00
+ 39 01 00 00 00 00 06 f0 55 aa 52 08 01
+ 39 01 00 00 00 00 05 ff aa 55 a5 80
+ 15 01 00 00 00 00 02 6f 01
+ 15 01 00 00 00 00 02 f3 10
+ 39 01 00 00 00 00 05 ff aa 55 a5 00
+ /* sleep out + delay 120ms */
+ 05 01 00 00 78 00 01 11
+ /* display on + delay 120ms */
+ 05 01 00 00 78 00 01 29
+ ];
+ qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+ qcom,mdss-dsi-off-command =
+ [05 01 00 00 78 00 02 28 00
+ 05 01 00 00 78 00 02 10 00];
+ qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+
+ qcom,compression-mode = "dsc";
+ qcom,mdss-dsc-slice-height = <32>;
+ qcom,mdss-dsc-slice-width = <1080>;
+ qcom,mdss-dsc-slice-per-pkt = <1>;
+ qcom,mdss-dsc-bit-per-component = <8>;
+ qcom,mdss-dsc-bit-per-pixel = <8>;
+ qcom,mdss-dsc-block-prediction-enable;
+ };
+ };
};
};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dualmipi-1080p-120hz.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dualmipi-1080p-120hz.dtsi
index 2071649..6dc621e 100644
--- a/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dualmipi-1080p-120hz.dtsi
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dualmipi-1080p-120hz.dtsi
@@ -15,595 +15,12 @@
qcom,mdss-dsi-panel-name =
"sharp 1080p 120hz dual dsi cmd mode panel";
qcom,mdss-dsi-panel-type = "dsi_cmd_mode";
- qcom,mdss-dsi-panel-framerate = <120>;
qcom,mdss-dsi-virtual-channel-id = <0>;
qcom,mdss-dsi-stream = <0>;
- qcom,mdss-dsi-panel-width = <540>;
- qcom,mdss-dsi-panel-height = <1920>;
- qcom,mdss-dsi-h-front-porch = <28>;
- qcom,mdss-dsi-h-back-porch = <4>;
- qcom,mdss-dsi-h-pulse-width = <4>;
- qcom,mdss-dsi-h-sync-skew = <0>;
- qcom,mdss-dsi-v-back-porch = <12>;
- qcom,mdss-dsi-v-front-porch = <12>;
- qcom,mdss-dsi-v-pulse-width = <2>;
- qcom,mdss-dsi-h-left-border = <0>;
- qcom,mdss-dsi-h-right-border = <0>;
- qcom,mdss-dsi-v-top-border = <0>;
- qcom,mdss-dsi-v-bottom-border = <0>;
qcom,mdss-dsi-bpp = <24>;
qcom,mdss-dsi-underflow-color = <0xff>;
qcom,mdss-dsi-border-color = <0>;
qcom,mdss-dsi-reset-sequence = <1 20>, <0 1>, <1 10>;
- qcom,mdss-dsi-on-command = [15 01 00 00 00 00 02 ff 10
- 15 01 00 00 00 00 02 fb 01
- 15 01 00 00 00 00 02 ba 07
- 15 01 00 00 00 00 02 c0 00
- 15 01 00 00 00 00 02 bb 10
- 15 01 00 00 00 00 02 d9 00
- 15 01 00 00 00 00 02 ef 70
- 15 01 00 00 00 00 02 f7 80
- 39 01 00 00 00 00 06 3b 03 0e 0c 08 1c
- 15 01 00 00 00 00 02 e9 0e
- 15 01 00 00 00 00 02 ea 0c
- 15 01 00 00 00 00 02 35 00
- 15 01 00 00 00 00 02 c0 00
- 15 01 00 00 00 00 02 ff 20
- 15 01 00 00 00 00 02 fb 01
- 15 01 00 00 00 00 02 59 6a
- 15 01 00 00 00 00 02 0b 1b
- 15 01 00 00 00 00 02 61 f7
- 15 01 00 00 00 00 02 62 6c
- 15 01 00 00 00 00 02 00 01
- 15 01 00 00 00 00 02 01 55
- 15 01 00 00 00 00 02 04 c8
- 15 01 00 00 00 00 02 05 1a
- 15 01 00 00 00 00 02 0d 93
- 15 01 00 00 00 00 02 0e 93
- 15 01 00 00 00 00 02 0f 7e
- 15 01 00 00 00 00 02 06 69
- 15 01 00 00 00 00 02 07 bc
- 15 01 00 00 00 00 02 10 03
- 15 01 00 00 00 00 02 11 64
- 15 01 00 00 00 00 02 12 5a
- 15 01 00 00 00 00 02 13 40
- 15 01 00 00 00 00 02 14 40
- 15 01 00 00 00 00 02 15 00
- 15 01 00 00 00 00 02 33 13
- 15 01 00 00 00 00 02 5a 40
- 15 01 00 00 00 00 02 5b 40
- 15 01 00 00 00 00 02 5e 80
- 15 01 00 00 00 00 02 ff 24
- 15 01 00 00 00 00 02 fb 01
- 15 01 00 00 00 00 02 00 80
- 15 01 00 00 00 00 02 14 80
- 15 01 00 00 00 00 02 01 80
- 15 01 00 00 00 00 02 15 80
- 15 01 00 00 00 00 02 02 80
- 15 01 00 00 00 00 02 16 80
- 15 01 00 00 00 00 02 03 0a
- 15 01 00 00 00 00 02 17 0c
- 15 01 00 00 00 00 02 04 06
- 15 01 00 00 00 00 02 18 08
- 15 01 00 00 00 00 02 05 80
- 15 01 00 00 00 00 02 19 80
- 15 01 00 00 00 00 02 06 80
- 15 01 00 00 00 00 02 1a 80
- 15 01 00 00 00 00 02 07 80
- 15 01 00 00 00 00 02 1b 80
- 15 01 00 00 00 00 02 08 80
- 15 01 00 00 00 00 02 1c 80
- 15 01 00 00 00 00 02 09 80
- 15 01 00 00 00 00 02 1d 80
- 15 01 00 00 00 00 02 0a 80
- 15 01 00 00 00 00 02 1e 80
- 15 01 00 00 00 00 02 0b 1a
- 15 01 00 00 00 00 02 1f 1b
- 15 01 00 00 00 00 02 0c 16
- 15 01 00 00 00 00 02 20 17
- 15 01 00 00 00 00 02 0d 1c
- 15 01 00 00 00 00 02 21 1d
- 15 01 00 00 00 00 02 0e 18
- 15 01 00 00 00 00 02 22 19
- 15 01 00 00 00 00 02 0f 0e
- 15 01 00 00 00 00 02 23 10
- 15 01 00 00 00 00 02 10 80
- 15 01 00 00 00 00 02 24 80
- 15 01 00 00 00 00 02 11 80
- 15 01 00 00 00 00 02 25 80
- 15 01 00 00 00 00 02 12 80
- 15 01 00 00 00 00 02 26 80
- 15 01 00 00 00 00 02 13 80
- 15 01 00 00 00 00 02 27 80
- 15 01 00 00 00 00 02 74 ff
- 15 01 00 00 00 00 02 75 ff
- 15 01 00 00 00 00 02 8d 00
- 15 01 00 00 00 00 02 8e 00
- 15 01 00 00 00 00 02 8f 9c
- 15 01 00 00 00 00 02 90 0c
- 15 01 00 00 00 00 02 91 0e
- 15 01 00 00 00 00 02 d6 00
- 15 01 00 00 00 00 02 d7 20
- 15 01 00 00 00 00 02 d8 00
- 15 01 00 00 00 00 02 d9 88
- 15 01 00 00 00 00 02 e5 05
- 15 01 00 00 00 00 02 e6 10
- 15 01 00 00 00 00 02 54 06
- 15 01 00 00 00 00 02 55 05
- 15 01 00 00 00 00 02 56 04
- 15 01 00 00 00 00 02 58 03
- 15 01 00 00 00 00 02 59 33
- 15 01 00 00 00 00 02 5a 33
- 15 01 00 00 00 00 02 5b 01
- 15 01 00 00 00 00 02 5c 00
- 15 01 00 00 00 00 02 5d 01
- 15 01 00 00 00 00 02 5e 0a
- 15 01 00 00 00 00 02 5f 0a
- 15 01 00 00 00 00 02 60 0a
- 15 01 00 00 00 00 02 61 0a
- 15 01 00 00 00 00 02 62 10
- 15 01 00 00 00 00 02 63 01
- 15 01 00 00 00 00 02 64 00
- 15 01 00 00 00 00 02 65 00
- 15 01 00 00 00 00 02 ef 00
- 15 01 00 00 00 00 02 f0 00
- 15 01 00 00 00 00 02 6d 20
- 15 01 00 00 00 00 02 66 44
- 15 01 00 00 00 00 02 68 01
- 15 01 00 00 00 00 02 69 00
- 15 01 00 00 00 00 02 67 11
- 15 01 00 00 00 00 02 6a 06
- 15 01 00 00 00 00 02 6b 31
- 15 01 00 00 00 00 02 6c 90
- 15 01 00 00 00 00 02 ab c3
- 15 01 00 00 00 00 02 b1 49
- 15 01 00 00 00 00 02 aa 80
- 15 01 00 00 00 00 02 b0 90
- 15 01 00 00 00 00 02 b2 a4
- 15 01 00 00 00 00 02 b3 00
- 15 01 00 00 00 00 02 b4 23
- 15 01 00 00 00 00 02 b5 00
- 15 01 00 00 00 00 02 b6 00
- 15 01 00 00 00 00 02 b7 00
- 15 01 00 00 00 00 02 b8 00
- 15 01 00 00 00 00 02 b9 00
- 15 01 00 00 00 00 02 ba 00
- 15 01 00 00 00 00 02 bb 00
- 15 01 00 00 00 00 02 bc 00
- 15 01 00 00 00 00 02 bd 00
- 15 01 00 00 00 00 02 be 00
- 15 01 00 00 00 00 02 bf 00
- 15 01 00 00 00 00 02 c0 00
- 15 01 00 00 00 00 02 c7 40
- 15 01 00 00 00 00 02 c9 00
- 15 01 00 00 00 00 02 c1 2a
- 15 01 00 00 00 00 02 c2 2a
- 15 01 00 00 00 00 02 c3 00
- 15 01 00 00 00 00 02 c4 00
- 15 01 00 00 00 00 02 c5 00
- 15 01 00 00 00 00 02 c6 00
- 15 01 00 00 00 00 02 c8 ab
- 15 01 00 00 00 00 02 ca 00
- 15 01 00 00 00 00 02 cb 00
- 15 01 00 00 00 00 02 cc 20
- 15 01 00 00 00 00 02 cd 40
- 15 01 00 00 00 00 02 ce a8
- 15 01 00 00 00 00 02 cf a8
- 15 01 00 00 00 00 02 d0 00
- 15 01 00 00 00 00 02 d1 00
- 15 01 00 00 00 00 02 d2 00
- 15 01 00 00 00 00 02 d3 00
- 15 01 00 00 00 00 02 af 01
- 15 01 00 00 00 00 02 a4 1e
- 15 01 00 00 00 00 02 95 41
- 15 01 00 00 00 00 02 96 03
- 15 01 00 00 00 00 02 98 00
- 15 01 00 00 00 00 02 9a 9a
- 15 01 00 00 00 00 02 9b 03
- 15 01 00 00 00 00 02 9d 80
- 15 01 00 00 00 00 02 ff 26
- 15 01 00 00 00 00 02 fb 01
- 15 01 00 00 00 00 02 fa d0
- 15 01 00 00 00 00 02 6b 80
- 15 01 00 00 00 00 02 6c 5c
- 15 01 00 00 00 00 02 6d 0c
- 15 01 00 00 00 00 02 6e 0e
- 15 01 00 00 00 00 02 58 01
- 15 01 00 00 00 00 02 59 15
- 15 01 00 00 00 00 02 5a 01
- 15 01 00 00 00 00 02 5b 00
- 15 01 00 00 00 00 02 5c 01
- 15 01 00 00 00 00 02 5d 2b
- 15 01 00 00 00 00 02 74 00
- 15 01 00 00 00 00 02 75 ba
- 15 01 00 00 00 00 02 81 0a
- 15 01 00 00 00 00 02 4e 81
- 15 01 00 00 00 00 02 4f 83
- 15 01 00 00 00 00 02 51 00
- 15 01 00 00 00 00 02 53 4d
- 15 01 00 00 00 00 02 54 03
- 15 01 00 00 00 00 02 ff e0
- 15 01 00 00 00 00 02 fb 01
- 15 01 00 00 00 00 02 b2 81
- 15 01 00 00 00 00 02 62 28
- 15 01 00 00 00 00 02 a2 09
- 15 01 00 00 00 00 02 b3 01
- 15 01 00 00 00 00 02 ed 00
- 15 01 00 00 00 00 02 ff 10
- 05 01 00 00 78 00 01 11
- 15 01 00 00 00 00 02 ff 20
- 15 01 00 00 00 00 02 75 00
- 15 01 00 00 00 00 02 76 71
- 15 01 00 00 00 00 02 77 00
- 15 01 00 00 00 00 02 78 84
- 15 01 00 00 00 00 02 79 00
- 15 01 00 00 00 00 02 7a a5
- 15 01 00 00 00 00 02 7b 00
- 15 01 00 00 00 00 02 7c bb
- 15 01 00 00 00 00 02 7d 00
- 15 01 00 00 00 00 02 7e ce
- 15 01 00 00 00 00 02 7f 00
- 15 01 00 00 00 00 02 80 e0
- 15 01 00 00 00 00 02 81 00
- 15 01 00 00 00 00 02 82 ef
- 15 01 00 00 00 00 02 83 00
- 15 01 00 00 00 00 02 84 ff
- 15 01 00 00 00 00 02 85 01
- 15 01 00 00 00 00 02 86 0b
- 15 01 00 00 00 00 02 87 01
- 15 01 00 00 00 00 02 88 38
- 15 01 00 00 00 00 02 89 01
- 15 01 00 00 00 00 02 8a 5b
- 15 01 00 00 00 00 02 8b 01
- 15 01 00 00 00 00 02 8c 95
- 15 01 00 00 00 00 02 8d 01
- 15 01 00 00 00 00 02 8e c4
- 15 01 00 00 00 00 02 8f 02
- 15 01 00 00 00 00 02 90 0d
- 15 01 00 00 00 00 02 91 02
- 15 01 00 00 00 00 02 92 4a
- 15 01 00 00 00 00 02 93 02
- 15 01 00 00 00 00 02 94 4c
- 15 01 00 00 00 00 02 95 02
- 15 01 00 00 00 00 02 96 85
- 15 01 00 00 00 00 02 97 02
- 15 01 00 00 00 00 02 98 c3
- 15 01 00 00 00 00 02 99 02
- 15 01 00 00 00 00 02 9a e9
- 15 01 00 00 00 00 02 9b 03
- 15 01 00 00 00 00 02 9c 16
- 15 01 00 00 00 00 02 9d 03
- 15 01 00 00 00 00 02 9e 34
- 15 01 00 00 00 00 02 9f 03
- 15 01 00 00 00 00 02 a0 56
- 15 01 00 00 00 00 02 a2 03
- 15 01 00 00 00 00 02 a3 62
- 15 01 00 00 00 00 02 a4 03
- 15 01 00 00 00 00 02 a5 6c
- 15 01 00 00 00 00 02 a6 03
- 15 01 00 00 00 00 02 a7 74
- 15 01 00 00 00 00 02 a9 03
- 15 01 00 00 00 00 02 aa 80
- 15 01 00 00 00 00 02 ab 03
- 15 01 00 00 00 00 02 ac 89
- 15 01 00 00 00 00 02 ad 03
- 15 01 00 00 00 00 02 ae 8b
- 15 01 00 00 00 00 02 af 03
- 15 01 00 00 00 00 02 b0 8d
- 15 01 00 00 00 00 02 b1 03
- 15 01 00 00 00 00 02 b2 8e
- 15 01 00 00 00 00 02 b3 00
- 15 01 00 00 00 00 02 b4 71
- 15 01 00 00 00 00 02 b5 00
- 15 01 00 00 00 00 02 b6 84
- 15 01 00 00 00 00 02 b7 00
- 15 01 00 00 00 00 02 b8 a5
- 15 01 00 00 00 00 02 b9 00
- 15 01 00 00 00 00 02 ba bb
- 15 01 00 00 00 00 02 bb 00
- 15 01 00 00 00 00 02 bc ce
- 15 01 00 00 00 00 02 bd 00
- 15 01 00 00 00 00 02 be e0
- 15 01 00 00 00 00 02 bf 00
- 15 01 00 00 00 00 02 c0 ef
- 15 01 00 00 00 00 02 c1 00
- 15 01 00 00 00 00 02 c2 ff
- 15 01 00 00 00 00 02 c3 01
- 15 01 00 00 00 00 02 c4 0b
- 15 01 00 00 00 00 02 c5 01
- 15 01 00 00 00 00 02 c6 38
- 15 01 00 00 00 00 02 c7 01
- 15 01 00 00 00 00 02 c8 5b
- 15 01 00 00 00 00 02 c9 01
- 15 01 00 00 00 00 02 ca 95
- 15 01 00 00 00 00 02 cb 01
- 15 01 00 00 00 00 02 cc c4
- 15 01 00 00 00 00 02 cd 02
- 15 01 00 00 00 00 02 ce 0d
- 15 01 00 00 00 00 02 cf 02
- 15 01 00 00 00 00 02 d0 4a
- 15 01 00 00 00 00 02 d1 02
- 15 01 00 00 00 00 02 d2 4c
- 15 01 00 00 00 00 02 d3 02
- 15 01 00 00 00 00 02 d4 85
- 15 01 00 00 00 00 02 d5 02
- 15 01 00 00 00 00 02 d6 c3
- 15 01 00 00 00 00 02 d7 02
- 15 01 00 00 00 00 02 d8 e9
- 15 01 00 00 00 00 02 d9 03
- 15 01 00 00 00 00 02 da 16
- 15 01 00 00 00 00 02 db 03
- 15 01 00 00 00 00 02 dc 34
- 15 01 00 00 00 00 02 dd 03
- 15 01 00 00 00 00 02 de 56
- 15 01 00 00 00 00 02 df 03
- 15 01 00 00 00 00 02 e0 62
- 15 01 00 00 00 00 02 e1 03
- 15 01 00 00 00 00 02 e2 6c
- 15 01 00 00 00 00 02 e3 03
- 15 01 00 00 00 00 02 e4 74
- 15 01 00 00 00 00 02 e5 03
- 15 01 00 00 00 00 02 e6 80
- 15 01 00 00 00 00 02 e7 03
- 15 01 00 00 00 00 02 e8 89
- 15 01 00 00 00 00 02 e9 03
- 15 01 00 00 00 00 02 ea 8b
- 15 01 00 00 00 00 02 eb 03
- 15 01 00 00 00 00 02 ec 8d
- 15 01 00 00 00 00 02 ed 03
- 15 01 00 00 00 00 02 ee 8e
- 15 01 00 00 00 00 02 ef 00
- 15 01 00 00 00 00 02 f0 71
- 15 01 00 00 00 00 02 f1 00
- 15 01 00 00 00 00 02 f2 84
- 15 01 00 00 00 00 02 f3 00
- 15 01 00 00 00 00 02 f4 a5
- 15 01 00 00 00 00 02 f5 00
- 15 01 00 00 00 00 02 f6 bb
- 15 01 00 00 00 00 02 f7 00
- 15 01 00 00 00 00 02 f8 ce
- 15 01 00 00 00 00 02 f9 00
- 15 01 00 00 00 00 02 fa e0
- 15 01 00 00 00 00 02 ff 21
- 15 01 00 00 00 00 02 fb 01
- 15 01 00 00 00 00 02 00 00
- 15 01 00 00 00 00 02 01 ef
- 15 01 00 00 00 00 02 02 00
- 15 01 00 00 00 00 02 03 ff
- 15 01 00 00 00 00 02 04 01
- 15 01 00 00 00 00 02 05 0b
- 15 01 00 00 00 00 02 06 01
- 15 01 00 00 00 00 02 07 38
- 15 01 00 00 00 00 02 08 01
- 15 01 00 00 00 00 02 09 5b
- 15 01 00 00 00 00 02 0a 01
- 15 01 00 00 00 00 02 0b 95
- 15 01 00 00 00 00 02 0c 01
- 15 01 00 00 00 00 02 0d c4
- 15 01 00 00 00 00 02 0e 02
- 15 01 00 00 00 00 02 0f 0d
- 15 01 00 00 00 00 02 10 02
- 15 01 00 00 00 00 02 11 4a
- 15 01 00 00 00 00 02 12 02
- 15 01 00 00 00 00 02 13 4c
- 15 01 00 00 00 00 02 14 02
- 15 01 00 00 00 00 02 15 85
- 15 01 00 00 00 00 02 16 02
- 15 01 00 00 00 00 02 17 c3
- 15 01 00 00 00 00 02 18 02
- 15 01 00 00 00 00 02 19 e9
- 15 01 00 00 00 00 02 1a 03
- 15 01 00 00 00 00 02 1b 16
- 15 01 00 00 00 00 02 1c 03
- 15 01 00 00 00 00 02 1d 34
- 15 01 00 00 00 00 02 1e 03
- 15 01 00 00 00 00 02 1f 56
- 15 01 00 00 00 00 02 20 03
- 15 01 00 00 00 00 02 21 62
- 15 01 00 00 00 00 02 22 03
- 15 01 00 00 00 00 02 23 6c
- 15 01 00 00 00 00 02 24 03
- 15 01 00 00 00 00 02 25 74
- 15 01 00 00 00 00 02 26 03
- 15 01 00 00 00 00 02 27 80
- 15 01 00 00 00 00 02 28 03
- 15 01 00 00 00 00 02 29 89
- 15 01 00 00 00 00 02 2a 03
- 15 01 00 00 00 00 02 2b 8b
- 15 01 00 00 00 00 02 2d 03
- 15 01 00 00 00 00 02 2f 8d
- 15 01 00 00 00 00 02 30 03
- 15 01 00 00 00 00 02 31 8e
- 15 01 00 00 00 00 02 32 00
- 15 01 00 00 00 00 02 33 71
- 15 01 00 00 00 00 02 34 00
- 15 01 00 00 00 00 02 35 84
- 15 01 00 00 00 00 02 36 00
- 15 01 00 00 00 00 02 37 a5
- 15 01 00 00 00 00 02 38 00
- 15 01 00 00 00 00 02 39 bb
- 15 01 00 00 00 00 02 3a 00
- 15 01 00 00 00 00 02 3b ce
- 15 01 00 00 00 00 02 3d 00
- 15 01 00 00 00 00 02 3f e0
- 15 01 00 00 00 00 02 40 00
- 15 01 00 00 00 00 02 41 ef
- 15 01 00 00 00 00 02 42 00
- 15 01 00 00 00 00 02 43 ff
- 15 01 00 00 00 00 02 44 01
- 15 01 00 00 00 00 02 45 0b
- 15 01 00 00 00 00 02 46 01
- 15 01 00 00 00 00 02 47 38
- 15 01 00 00 00 00 02 48 01
- 15 01 00 00 00 00 02 49 5b
- 15 01 00 00 00 00 02 4a 01
- 15 01 00 00 00 00 02 4b 95
- 15 01 00 00 00 00 02 4c 01
- 15 01 00 00 00 00 02 4d c4
- 15 01 00 00 00 00 02 4e 02
- 15 01 00 00 00 00 02 4f 0d
- 15 01 00 00 00 00 02 50 02
- 15 01 00 00 00 00 02 51 4a
- 15 01 00 00 00 00 02 52 02
- 15 01 00 00 00 00 02 53 4c
- 15 01 00 00 00 00 02 54 02
- 15 01 00 00 00 00 02 55 85
- 15 01 00 00 00 00 02 56 02
- 15 01 00 00 00 00 02 58 c3
- 15 01 00 00 00 00 02 59 02
- 15 01 00 00 00 00 02 5a e9
- 15 01 00 00 00 00 02 5b 03
- 15 01 00 00 00 00 02 5c 16
- 15 01 00 00 00 00 02 5d 03
- 15 01 00 00 00 00 02 5e 34
- 15 01 00 00 00 00 02 5f 03
- 15 01 00 00 00 00 02 60 56
- 15 01 00 00 00 00 02 61 03
- 15 01 00 00 00 00 02 62 62
- 15 01 00 00 00 00 02 63 03
- 15 01 00 00 00 00 02 64 6c
- 15 01 00 00 00 00 02 65 03
- 15 01 00 00 00 00 02 66 74
- 15 01 00 00 00 00 02 67 03
- 15 01 00 00 00 00 02 68 80
- 15 01 00 00 00 00 02 69 03
- 15 01 00 00 00 00 02 6a 89
- 15 01 00 00 00 00 02 6b 03
- 15 01 00 00 00 00 02 6c 8b
- 15 01 00 00 00 00 02 6d 03
- 15 01 00 00 00 00 02 6e 8d
- 15 01 00 00 00 00 02 6f 03
- 15 01 00 00 00 00 02 70 8e
- 15 01 00 00 00 00 02 71 00
- 15 01 00 00 00 00 02 72 71
- 15 01 00 00 00 00 02 73 00
- 15 01 00 00 00 00 02 74 84
- 15 01 00 00 00 00 02 75 00
- 15 01 00 00 00 00 02 76 a5
- 15 01 00 00 00 00 02 77 00
- 15 01 00 00 00 00 02 78 bb
- 15 01 00 00 00 00 02 79 00
- 15 01 00 00 00 00 02 7a ce
- 15 01 00 00 00 00 02 7b 00
- 15 01 00 00 00 00 02 7c e0
- 15 01 00 00 00 00 02 7d 00
- 15 01 00 00 00 00 02 7e ef
- 15 01 00 00 00 00 02 7f 00
- 15 01 00 00 00 00 02 80 ff
- 15 01 00 00 00 00 02 81 01
- 15 01 00 00 00 00 02 82 0b
- 15 01 00 00 00 00 02 83 01
- 15 01 00 00 00 00 02 84 38
- 15 01 00 00 00 00 02 85 01
- 15 01 00 00 00 00 02 86 5b
- 15 01 00 00 00 00 02 87 01
- 15 01 00 00 00 00 02 88 95
- 15 01 00 00 00 00 02 89 01
- 15 01 00 00 00 00 02 8a c4
- 15 01 00 00 00 00 02 8b 02
- 15 01 00 00 00 00 02 8c 0d
- 15 01 00 00 00 00 02 8d 02
- 15 01 00 00 00 00 02 8e 4a
- 15 01 00 00 00 00 02 8f 02
- 15 01 00 00 00 00 02 90 4c
- 15 01 00 00 00 00 02 91 02
- 15 01 00 00 00 00 02 92 85
- 15 01 00 00 00 00 02 93 02
- 15 01 00 00 00 00 02 94 c3
- 15 01 00 00 00 00 02 95 02
- 15 01 00 00 00 00 02 96 e9
- 15 01 00 00 00 00 02 97 03
- 15 01 00 00 00 00 02 98 16
- 15 01 00 00 00 00 02 99 03
- 15 01 00 00 00 00 02 9a 34
- 15 01 00 00 00 00 02 9b 03
- 15 01 00 00 00 00 02 9c 56
- 15 01 00 00 00 00 02 9d 03
- 15 01 00 00 00 00 02 9e 62
- 15 01 00 00 00 00 02 9f 03
- 15 01 00 00 00 00 02 a0 6c
- 15 01 00 00 00 00 02 a2 03
- 15 01 00 00 00 00 02 a3 74
- 15 01 00 00 00 00 02 a4 03
- 15 01 00 00 00 00 02 a5 80
- 15 01 00 00 00 00 02 a6 03
- 15 01 00 00 00 00 02 a7 89
- 15 01 00 00 00 00 02 a9 03
- 15 01 00 00 00 00 02 aa 8b
- 15 01 00 00 00 00 02 ab 03
- 15 01 00 00 00 00 02 ac 8d
- 15 01 00 00 00 00 02 ad 03
- 15 01 00 00 00 00 02 ae 8e
- 15 01 00 00 00 00 02 af 00
- 15 01 00 00 00 00 02 b0 71
- 15 01 00 00 00 00 02 b1 00
- 15 01 00 00 00 00 02 b2 84
- 15 01 00 00 00 00 02 b3 00
- 15 01 00 00 00 00 02 b4 a5
- 15 01 00 00 00 00 02 b5 00
- 15 01 00 00 00 00 02 b6 bb
- 15 01 00 00 00 00 02 b7 00
- 15 01 00 00 00 00 02 b8 ce
- 15 01 00 00 00 00 02 b9 00
- 15 01 00 00 00 00 02 ba e0
- 15 01 00 00 00 00 02 bb 00
- 15 01 00 00 00 00 02 bc ef
- 15 01 00 00 00 00 02 bd 00
- 15 01 00 00 00 00 02 be ff
- 15 01 00 00 00 00 02 bf 01
- 15 01 00 00 00 00 02 c0 0b
- 15 01 00 00 00 00 02 c1 01
- 15 01 00 00 00 00 02 c2 38
- 15 01 00 00 00 00 02 c3 01
- 15 01 00 00 00 00 02 c4 5b
- 15 01 00 00 00 00 02 c5 01
- 15 01 00 00 00 00 02 c6 95
- 15 01 00 00 00 00 02 c7 01
- 15 01 00 00 00 00 02 c8 c4
- 15 01 00 00 00 00 02 c9 02
- 15 01 00 00 00 00 02 ca 0d
- 15 01 00 00 00 00 02 cb 02
- 15 01 00 00 00 00 02 cc 4a
- 15 01 00 00 00 00 02 cd 02
- 15 01 00 00 00 00 02 ce 4c
- 15 01 00 00 00 00 02 cf 02
- 15 01 00 00 00 00 02 d0 85
- 15 01 00 00 00 00 02 d1 02
- 15 01 00 00 00 00 02 d2 c3
- 15 01 00 00 00 00 02 d3 02
- 15 01 00 00 00 00 02 d4 e9
- 15 01 00 00 00 00 02 d5 03
- 15 01 00 00 00 00 02 d6 16
- 15 01 00 00 00 00 02 d7 03
- 15 01 00 00 00 00 02 d8 34
- 15 01 00 00 00 00 02 d9 03
- 15 01 00 00 00 00 02 da 56
- 15 01 00 00 00 00 02 db 03
- 15 01 00 00 00 00 02 dc 62
- 15 01 00 00 00 00 02 dd 03
- 15 01 00 00 00 00 02 de 6c
- 15 01 00 00 00 00 02 df 03
- 15 01 00 00 00 00 02 e0 74
- 15 01 00 00 00 00 02 e1 03
- 15 01 00 00 00 00 02 e2 80
- 15 01 00 00 00 00 02 e3 03
- 15 01 00 00 00 00 02 e4 89
- 15 01 00 00 00 00 02 e5 03
- 15 01 00 00 00 00 02 e6 8b
- 15 01 00 00 00 00 02 e7 03
- 15 01 00 00 00 00 02 e8 8d
- 15 01 00 00 00 00 02 e9 03
- 15 01 00 00 00 00 02 ea 8e
- 15 01 00 00 00 00 02 FF 10
- 05 01 00 00 00 00 01 29];
- qcom,mdss-dsi-off-command = [15 01 00 00 00 00 02 ff 10
- 05 01 00 00 10 00 01 28
- 15 01 00 00 00 00 02 b0 00
- 05 01 00 00 40 00 01 10
- 15 01 00 00 00 00 02 4f 01];
- qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
- qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
- qcom,mdss-dsi-h-sync-pulse = <0>;
qcom,mdss-dsi-traffic-mode = "burst_mode";
qcom,mdss-dsi-bllp-eof-power-mode;
qcom,mdss-dsi-bllp-power-mode;
@@ -623,10 +40,594 @@
qcom,mdss-dsi-te-check-enable;
qcom,mdss-dsi-te-using-te-pin;
- qcom,config-select = <&dsi_dual_sharp_cmd_config0>;
-
- dsi_dual_sharp_cmd_config0: config0 {
- qcom,split-mode = "dualctl-split";
+ qcom,mdss-dsi-display-timings {
+ timing@0{
+ qcom,mdss-dsi-panel-width = <540>;
+ qcom,mdss-dsi-panel-height = <1920>;
+ qcom,mdss-dsi-h-front-porch = <28>;
+ qcom,mdss-dsi-h-back-porch = <4>;
+ qcom,mdss-dsi-h-pulse-width = <4>;
+ qcom,mdss-dsi-h-sync-skew = <0>;
+ qcom,mdss-dsi-v-back-porch = <12>;
+ qcom,mdss-dsi-v-front-porch = <12>;
+ qcom,mdss-dsi-v-pulse-width = <2>;
+ qcom,mdss-dsi-h-left-border = <0>;
+ qcom,mdss-dsi-h-right-border = <0>;
+ qcom,mdss-dsi-v-top-border = <0>;
+ qcom,mdss-dsi-v-bottom-border = <0>;
+ qcom,mdss-dsi-panel-framerate = <120>;
+ qcom,mdss-dsi-on-command =
+ [15 01 00 00 00 00 02 ff 10
+ 15 01 00 00 00 00 02 fb 01
+ 15 01 00 00 00 00 02 ba 07
+ 15 01 00 00 00 00 02 c0 00
+ 15 01 00 00 00 00 02 bb 10
+ 15 01 00 00 00 00 02 d9 00
+ 15 01 00 00 00 00 02 ef 70
+ 15 01 00 00 00 00 02 f7 80
+ 39 01 00 00 00 00 06 3b 03 0e 0c 08 1c
+ 15 01 00 00 00 00 02 e9 0e
+ 15 01 00 00 00 00 02 ea 0c
+ 15 01 00 00 00 00 02 35 00
+ 15 01 00 00 00 00 02 c0 00
+ 15 01 00 00 00 00 02 ff 20
+ 15 01 00 00 00 00 02 fb 01
+ 15 01 00 00 00 00 02 59 6a
+ 15 01 00 00 00 00 02 0b 1b
+ 15 01 00 00 00 00 02 61 f7
+ 15 01 00 00 00 00 02 62 6c
+ 15 01 00 00 00 00 02 00 01
+ 15 01 00 00 00 00 02 01 55
+ 15 01 00 00 00 00 02 04 c8
+ 15 01 00 00 00 00 02 05 1a
+ 15 01 00 00 00 00 02 0d 93
+ 15 01 00 00 00 00 02 0e 93
+ 15 01 00 00 00 00 02 0f 7e
+ 15 01 00 00 00 00 02 06 69
+ 15 01 00 00 00 00 02 07 bc
+ 15 01 00 00 00 00 02 10 03
+ 15 01 00 00 00 00 02 11 64
+ 15 01 00 00 00 00 02 12 5a
+ 15 01 00 00 00 00 02 13 40
+ 15 01 00 00 00 00 02 14 40
+ 15 01 00 00 00 00 02 15 00
+ 15 01 00 00 00 00 02 33 13
+ 15 01 00 00 00 00 02 5a 40
+ 15 01 00 00 00 00 02 5b 40
+ 15 01 00 00 00 00 02 5e 80
+ 15 01 00 00 00 00 02 ff 24
+ 15 01 00 00 00 00 02 fb 01
+ 15 01 00 00 00 00 02 00 80
+ 15 01 00 00 00 00 02 14 80
+ 15 01 00 00 00 00 02 01 80
+ 15 01 00 00 00 00 02 15 80
+ 15 01 00 00 00 00 02 02 80
+ 15 01 00 00 00 00 02 16 80
+ 15 01 00 00 00 00 02 03 0a
+ 15 01 00 00 00 00 02 17 0c
+ 15 01 00 00 00 00 02 04 06
+ 15 01 00 00 00 00 02 18 08
+ 15 01 00 00 00 00 02 05 80
+ 15 01 00 00 00 00 02 19 80
+ 15 01 00 00 00 00 02 06 80
+ 15 01 00 00 00 00 02 1a 80
+ 15 01 00 00 00 00 02 07 80
+ 15 01 00 00 00 00 02 1b 80
+ 15 01 00 00 00 00 02 08 80
+ 15 01 00 00 00 00 02 1c 80
+ 15 01 00 00 00 00 02 09 80
+ 15 01 00 00 00 00 02 1d 80
+ 15 01 00 00 00 00 02 0a 80
+ 15 01 00 00 00 00 02 1e 80
+ 15 01 00 00 00 00 02 0b 1a
+ 15 01 00 00 00 00 02 1f 1b
+ 15 01 00 00 00 00 02 0c 16
+ 15 01 00 00 00 00 02 20 17
+ 15 01 00 00 00 00 02 0d 1c
+ 15 01 00 00 00 00 02 21 1d
+ 15 01 00 00 00 00 02 0e 18
+ 15 01 00 00 00 00 02 22 19
+ 15 01 00 00 00 00 02 0f 0e
+ 15 01 00 00 00 00 02 23 10
+ 15 01 00 00 00 00 02 10 80
+ 15 01 00 00 00 00 02 24 80
+ 15 01 00 00 00 00 02 11 80
+ 15 01 00 00 00 00 02 25 80
+ 15 01 00 00 00 00 02 12 80
+ 15 01 00 00 00 00 02 26 80
+ 15 01 00 00 00 00 02 13 80
+ 15 01 00 00 00 00 02 27 80
+ 15 01 00 00 00 00 02 74 ff
+ 15 01 00 00 00 00 02 75 ff
+ 15 01 00 00 00 00 02 8d 00
+ 15 01 00 00 00 00 02 8e 00
+ 15 01 00 00 00 00 02 8f 9c
+ 15 01 00 00 00 00 02 90 0c
+ 15 01 00 00 00 00 02 91 0e
+ 15 01 00 00 00 00 02 d6 00
+ 15 01 00 00 00 00 02 d7 20
+ 15 01 00 00 00 00 02 d8 00
+ 15 01 00 00 00 00 02 d9 88
+ 15 01 00 00 00 00 02 e5 05
+ 15 01 00 00 00 00 02 e6 10
+ 15 01 00 00 00 00 02 54 06
+ 15 01 00 00 00 00 02 55 05
+ 15 01 00 00 00 00 02 56 04
+ 15 01 00 00 00 00 02 58 03
+ 15 01 00 00 00 00 02 59 33
+ 15 01 00 00 00 00 02 5a 33
+ 15 01 00 00 00 00 02 5b 01
+ 15 01 00 00 00 00 02 5c 00
+ 15 01 00 00 00 00 02 5d 01
+ 15 01 00 00 00 00 02 5e 0a
+ 15 01 00 00 00 00 02 5f 0a
+ 15 01 00 00 00 00 02 60 0a
+ 15 01 00 00 00 00 02 61 0a
+ 15 01 00 00 00 00 02 62 10
+ 15 01 00 00 00 00 02 63 01
+ 15 01 00 00 00 00 02 64 00
+ 15 01 00 00 00 00 02 65 00
+ 15 01 00 00 00 00 02 ef 00
+ 15 01 00 00 00 00 02 f0 00
+ 15 01 00 00 00 00 02 6d 20
+ 15 01 00 00 00 00 02 66 44
+ 15 01 00 00 00 00 02 68 01
+ 15 01 00 00 00 00 02 69 00
+ 15 01 00 00 00 00 02 67 11
+ 15 01 00 00 00 00 02 6a 06
+ 15 01 00 00 00 00 02 6b 31
+ 15 01 00 00 00 00 02 6c 90
+ 15 01 00 00 00 00 02 ab c3
+ 15 01 00 00 00 00 02 b1 49
+ 15 01 00 00 00 00 02 aa 80
+ 15 01 00 00 00 00 02 b0 90
+ 15 01 00 00 00 00 02 b2 a4
+ 15 01 00 00 00 00 02 b3 00
+ 15 01 00 00 00 00 02 b4 23
+ 15 01 00 00 00 00 02 b5 00
+ 15 01 00 00 00 00 02 b6 00
+ 15 01 00 00 00 00 02 b7 00
+ 15 01 00 00 00 00 02 b8 00
+ 15 01 00 00 00 00 02 b9 00
+ 15 01 00 00 00 00 02 ba 00
+ 15 01 00 00 00 00 02 bb 00
+ 15 01 00 00 00 00 02 bc 00
+ 15 01 00 00 00 00 02 bd 00
+ 15 01 00 00 00 00 02 be 00
+ 15 01 00 00 00 00 02 bf 00
+ 15 01 00 00 00 00 02 c0 00
+ 15 01 00 00 00 00 02 c7 40
+ 15 01 00 00 00 00 02 c9 00
+ 15 01 00 00 00 00 02 c1 2a
+ 15 01 00 00 00 00 02 c2 2a
+ 15 01 00 00 00 00 02 c3 00
+ 15 01 00 00 00 00 02 c4 00
+ 15 01 00 00 00 00 02 c5 00
+ 15 01 00 00 00 00 02 c6 00
+ 15 01 00 00 00 00 02 c8 ab
+ 15 01 00 00 00 00 02 ca 00
+ 15 01 00 00 00 00 02 cb 00
+ 15 01 00 00 00 00 02 cc 20
+ 15 01 00 00 00 00 02 cd 40
+ 15 01 00 00 00 00 02 ce a8
+ 15 01 00 00 00 00 02 cf a8
+ 15 01 00 00 00 00 02 d0 00
+ 15 01 00 00 00 00 02 d1 00
+ 15 01 00 00 00 00 02 d2 00
+ 15 01 00 00 00 00 02 d3 00
+ 15 01 00 00 00 00 02 af 01
+ 15 01 00 00 00 00 02 a4 1e
+ 15 01 00 00 00 00 02 95 41
+ 15 01 00 00 00 00 02 96 03
+ 15 01 00 00 00 00 02 98 00
+ 15 01 00 00 00 00 02 9a 9a
+ 15 01 00 00 00 00 02 9b 03
+ 15 01 00 00 00 00 02 9d 80
+ 15 01 00 00 00 00 02 ff 26
+ 15 01 00 00 00 00 02 fb 01
+ 15 01 00 00 00 00 02 fa d0
+ 15 01 00 00 00 00 02 6b 80
+ 15 01 00 00 00 00 02 6c 5c
+ 15 01 00 00 00 00 02 6d 0c
+ 15 01 00 00 00 00 02 6e 0e
+ 15 01 00 00 00 00 02 58 01
+ 15 01 00 00 00 00 02 59 15
+ 15 01 00 00 00 00 02 5a 01
+ 15 01 00 00 00 00 02 5b 00
+ 15 01 00 00 00 00 02 5c 01
+ 15 01 00 00 00 00 02 5d 2b
+ 15 01 00 00 00 00 02 74 00
+ 15 01 00 00 00 00 02 75 ba
+ 15 01 00 00 00 00 02 81 0a
+ 15 01 00 00 00 00 02 4e 81
+ 15 01 00 00 00 00 02 4f 83
+ 15 01 00 00 00 00 02 51 00
+ 15 01 00 00 00 00 02 53 4d
+ 15 01 00 00 00 00 02 54 03
+ 15 01 00 00 00 00 02 ff e0
+ 15 01 00 00 00 00 02 fb 01
+ 15 01 00 00 00 00 02 b2 81
+ 15 01 00 00 00 00 02 62 28
+ 15 01 00 00 00 00 02 a2 09
+ 15 01 00 00 00 00 02 b3 01
+ 15 01 00 00 00 00 02 ed 00
+ 15 01 00 00 00 00 02 ff 10
+ 05 01 00 00 78 00 01 11
+ 15 01 00 00 00 00 02 ff 20
+ 15 01 00 00 00 00 02 75 00
+ 15 01 00 00 00 00 02 76 71
+ 15 01 00 00 00 00 02 77 00
+ 15 01 00 00 00 00 02 78 84
+ 15 01 00 00 00 00 02 79 00
+ 15 01 00 00 00 00 02 7a a5
+ 15 01 00 00 00 00 02 7b 00
+ 15 01 00 00 00 00 02 7c bb
+ 15 01 00 00 00 00 02 7d 00
+ 15 01 00 00 00 00 02 7e ce
+ 15 01 00 00 00 00 02 7f 00
+ 15 01 00 00 00 00 02 80 e0
+ 15 01 00 00 00 00 02 81 00
+ 15 01 00 00 00 00 02 82 ef
+ 15 01 00 00 00 00 02 83 00
+ 15 01 00 00 00 00 02 84 ff
+ 15 01 00 00 00 00 02 85 01
+ 15 01 00 00 00 00 02 86 0b
+ 15 01 00 00 00 00 02 87 01
+ 15 01 00 00 00 00 02 88 38
+ 15 01 00 00 00 00 02 89 01
+ 15 01 00 00 00 00 02 8a 5b
+ 15 01 00 00 00 00 02 8b 01
+ 15 01 00 00 00 00 02 8c 95
+ 15 01 00 00 00 00 02 8d 01
+ 15 01 00 00 00 00 02 8e c4
+ 15 01 00 00 00 00 02 8f 02
+ 15 01 00 00 00 00 02 90 0d
+ 15 01 00 00 00 00 02 91 02
+ 15 01 00 00 00 00 02 92 4a
+ 15 01 00 00 00 00 02 93 02
+ 15 01 00 00 00 00 02 94 4c
+ 15 01 00 00 00 00 02 95 02
+ 15 01 00 00 00 00 02 96 85
+ 15 01 00 00 00 00 02 97 02
+ 15 01 00 00 00 00 02 98 c3
+ 15 01 00 00 00 00 02 99 02
+ 15 01 00 00 00 00 02 9a e9
+ 15 01 00 00 00 00 02 9b 03
+ 15 01 00 00 00 00 02 9c 16
+ 15 01 00 00 00 00 02 9d 03
+ 15 01 00 00 00 00 02 9e 34
+ 15 01 00 00 00 00 02 9f 03
+ 15 01 00 00 00 00 02 a0 56
+ 15 01 00 00 00 00 02 a2 03
+ 15 01 00 00 00 00 02 a3 62
+ 15 01 00 00 00 00 02 a4 03
+ 15 01 00 00 00 00 02 a5 6c
+ 15 01 00 00 00 00 02 a6 03
+ 15 01 00 00 00 00 02 a7 74
+ 15 01 00 00 00 00 02 a9 03
+ 15 01 00 00 00 00 02 aa 80
+ 15 01 00 00 00 00 02 ab 03
+ 15 01 00 00 00 00 02 ac 89
+ 15 01 00 00 00 00 02 ad 03
+ 15 01 00 00 00 00 02 ae 8b
+ 15 01 00 00 00 00 02 af 03
+ 15 01 00 00 00 00 02 b0 8d
+ 15 01 00 00 00 00 02 b1 03
+ 15 01 00 00 00 00 02 b2 8e
+ 15 01 00 00 00 00 02 b3 00
+ 15 01 00 00 00 00 02 b4 71
+ 15 01 00 00 00 00 02 b5 00
+ 15 01 00 00 00 00 02 b6 84
+ 15 01 00 00 00 00 02 b7 00
+ 15 01 00 00 00 00 02 b8 a5
+ 15 01 00 00 00 00 02 b9 00
+ 15 01 00 00 00 00 02 ba bb
+ 15 01 00 00 00 00 02 bb 00
+ 15 01 00 00 00 00 02 bc ce
+ 15 01 00 00 00 00 02 bd 00
+ 15 01 00 00 00 00 02 be e0
+ 15 01 00 00 00 00 02 bf 00
+ 15 01 00 00 00 00 02 c0 ef
+ 15 01 00 00 00 00 02 c1 00
+ 15 01 00 00 00 00 02 c2 ff
+ 15 01 00 00 00 00 02 c3 01
+ 15 01 00 00 00 00 02 c4 0b
+ 15 01 00 00 00 00 02 c5 01
+ 15 01 00 00 00 00 02 c6 38
+ 15 01 00 00 00 00 02 c7 01
+ 15 01 00 00 00 00 02 c8 5b
+ 15 01 00 00 00 00 02 c9 01
+ 15 01 00 00 00 00 02 ca 95
+ 15 01 00 00 00 00 02 cb 01
+ 15 01 00 00 00 00 02 cc c4
+ 15 01 00 00 00 00 02 cd 02
+ 15 01 00 00 00 00 02 ce 0d
+ 15 01 00 00 00 00 02 cf 02
+ 15 01 00 00 00 00 02 d0 4a
+ 15 01 00 00 00 00 02 d1 02
+ 15 01 00 00 00 00 02 d2 4c
+ 15 01 00 00 00 00 02 d3 02
+ 15 01 00 00 00 00 02 d4 85
+ 15 01 00 00 00 00 02 d5 02
+ 15 01 00 00 00 00 02 d6 c3
+ 15 01 00 00 00 00 02 d7 02
+ 15 01 00 00 00 00 02 d8 e9
+ 15 01 00 00 00 00 02 d9 03
+ 15 01 00 00 00 00 02 da 16
+ 15 01 00 00 00 00 02 db 03
+ 15 01 00 00 00 00 02 dc 34
+ 15 01 00 00 00 00 02 dd 03
+ 15 01 00 00 00 00 02 de 56
+ 15 01 00 00 00 00 02 df 03
+ 15 01 00 00 00 00 02 e0 62
+ 15 01 00 00 00 00 02 e1 03
+ 15 01 00 00 00 00 02 e2 6c
+ 15 01 00 00 00 00 02 e3 03
+ 15 01 00 00 00 00 02 e4 74
+ 15 01 00 00 00 00 02 e5 03
+ 15 01 00 00 00 00 02 e6 80
+ 15 01 00 00 00 00 02 e7 03
+ 15 01 00 00 00 00 02 e8 89
+ 15 01 00 00 00 00 02 e9 03
+ 15 01 00 00 00 00 02 ea 8b
+ 15 01 00 00 00 00 02 eb 03
+ 15 01 00 00 00 00 02 ec 8d
+ 15 01 00 00 00 00 02 ed 03
+ 15 01 00 00 00 00 02 ee 8e
+ 15 01 00 00 00 00 02 ef 00
+ 15 01 00 00 00 00 02 f0 71
+ 15 01 00 00 00 00 02 f1 00
+ 15 01 00 00 00 00 02 f2 84
+ 15 01 00 00 00 00 02 f3 00
+ 15 01 00 00 00 00 02 f4 a5
+ 15 01 00 00 00 00 02 f5 00
+ 15 01 00 00 00 00 02 f6 bb
+ 15 01 00 00 00 00 02 f7 00
+ 15 01 00 00 00 00 02 f8 ce
+ 15 01 00 00 00 00 02 f9 00
+ 15 01 00 00 00 00 02 fa e0
+ 15 01 00 00 00 00 02 ff 21
+ 15 01 00 00 00 00 02 fb 01
+ 15 01 00 00 00 00 02 00 00
+ 15 01 00 00 00 00 02 01 ef
+ 15 01 00 00 00 00 02 02 00
+ 15 01 00 00 00 00 02 03 ff
+ 15 01 00 00 00 00 02 04 01
+ 15 01 00 00 00 00 02 05 0b
+ 15 01 00 00 00 00 02 06 01
+ 15 01 00 00 00 00 02 07 38
+ 15 01 00 00 00 00 02 08 01
+ 15 01 00 00 00 00 02 09 5b
+ 15 01 00 00 00 00 02 0a 01
+ 15 01 00 00 00 00 02 0b 95
+ 15 01 00 00 00 00 02 0c 01
+ 15 01 00 00 00 00 02 0d c4
+ 15 01 00 00 00 00 02 0e 02
+ 15 01 00 00 00 00 02 0f 0d
+ 15 01 00 00 00 00 02 10 02
+ 15 01 00 00 00 00 02 11 4a
+ 15 01 00 00 00 00 02 12 02
+ 15 01 00 00 00 00 02 13 4c
+ 15 01 00 00 00 00 02 14 02
+ 15 01 00 00 00 00 02 15 85
+ 15 01 00 00 00 00 02 16 02
+ 15 01 00 00 00 00 02 17 c3
+ 15 01 00 00 00 00 02 18 02
+ 15 01 00 00 00 00 02 19 e9
+ 15 01 00 00 00 00 02 1a 03
+ 15 01 00 00 00 00 02 1b 16
+ 15 01 00 00 00 00 02 1c 03
+ 15 01 00 00 00 00 02 1d 34
+ 15 01 00 00 00 00 02 1e 03
+ 15 01 00 00 00 00 02 1f 56
+ 15 01 00 00 00 00 02 20 03
+ 15 01 00 00 00 00 02 21 62
+ 15 01 00 00 00 00 02 22 03
+ 15 01 00 00 00 00 02 23 6c
+ 15 01 00 00 00 00 02 24 03
+ 15 01 00 00 00 00 02 25 74
+ 15 01 00 00 00 00 02 26 03
+ 15 01 00 00 00 00 02 27 80
+ 15 01 00 00 00 00 02 28 03
+ 15 01 00 00 00 00 02 29 89
+ 15 01 00 00 00 00 02 2a 03
+ 15 01 00 00 00 00 02 2b 8b
+ 15 01 00 00 00 00 02 2d 03
+ 15 01 00 00 00 00 02 2f 8d
+ 15 01 00 00 00 00 02 30 03
+ 15 01 00 00 00 00 02 31 8e
+ 15 01 00 00 00 00 02 32 00
+ 15 01 00 00 00 00 02 33 71
+ 15 01 00 00 00 00 02 34 00
+ 15 01 00 00 00 00 02 35 84
+ 15 01 00 00 00 00 02 36 00
+ 15 01 00 00 00 00 02 37 a5
+ 15 01 00 00 00 00 02 38 00
+ 15 01 00 00 00 00 02 39 bb
+ 15 01 00 00 00 00 02 3a 00
+ 15 01 00 00 00 00 02 3b ce
+ 15 01 00 00 00 00 02 3d 00
+ 15 01 00 00 00 00 02 3f e0
+ 15 01 00 00 00 00 02 40 00
+ 15 01 00 00 00 00 02 41 ef
+ 15 01 00 00 00 00 02 42 00
+ 15 01 00 00 00 00 02 43 ff
+ 15 01 00 00 00 00 02 44 01
+ 15 01 00 00 00 00 02 45 0b
+ 15 01 00 00 00 00 02 46 01
+ 15 01 00 00 00 00 02 47 38
+ 15 01 00 00 00 00 02 48 01
+ 15 01 00 00 00 00 02 49 5b
+ 15 01 00 00 00 00 02 4a 01
+ 15 01 00 00 00 00 02 4b 95
+ 15 01 00 00 00 00 02 4c 01
+ 15 01 00 00 00 00 02 4d c4
+ 15 01 00 00 00 00 02 4e 02
+ 15 01 00 00 00 00 02 4f 0d
+ 15 01 00 00 00 00 02 50 02
+ 15 01 00 00 00 00 02 51 4a
+ 15 01 00 00 00 00 02 52 02
+ 15 01 00 00 00 00 02 53 4c
+ 15 01 00 00 00 00 02 54 02
+ 15 01 00 00 00 00 02 55 85
+ 15 01 00 00 00 00 02 56 02
+ 15 01 00 00 00 00 02 58 c3
+ 15 01 00 00 00 00 02 59 02
+ 15 01 00 00 00 00 02 5a e9
+ 15 01 00 00 00 00 02 5b 03
+ 15 01 00 00 00 00 02 5c 16
+ 15 01 00 00 00 00 02 5d 03
+ 15 01 00 00 00 00 02 5e 34
+ 15 01 00 00 00 00 02 5f 03
+ 15 01 00 00 00 00 02 60 56
+ 15 01 00 00 00 00 02 61 03
+ 15 01 00 00 00 00 02 62 62
+ 15 01 00 00 00 00 02 63 03
+ 15 01 00 00 00 00 02 64 6c
+ 15 01 00 00 00 00 02 65 03
+ 15 01 00 00 00 00 02 66 74
+ 15 01 00 00 00 00 02 67 03
+ 15 01 00 00 00 00 02 68 80
+ 15 01 00 00 00 00 02 69 03
+ 15 01 00 00 00 00 02 6a 89
+ 15 01 00 00 00 00 02 6b 03
+ 15 01 00 00 00 00 02 6c 8b
+ 15 01 00 00 00 00 02 6d 03
+ 15 01 00 00 00 00 02 6e 8d
+ 15 01 00 00 00 00 02 6f 03
+ 15 01 00 00 00 00 02 70 8e
+ 15 01 00 00 00 00 02 71 00
+ 15 01 00 00 00 00 02 72 71
+ 15 01 00 00 00 00 02 73 00
+ 15 01 00 00 00 00 02 74 84
+ 15 01 00 00 00 00 02 75 00
+ 15 01 00 00 00 00 02 76 a5
+ 15 01 00 00 00 00 02 77 00
+ 15 01 00 00 00 00 02 78 bb
+ 15 01 00 00 00 00 02 79 00
+ 15 01 00 00 00 00 02 7a ce
+ 15 01 00 00 00 00 02 7b 00
+ 15 01 00 00 00 00 02 7c e0
+ 15 01 00 00 00 00 02 7d 00
+ 15 01 00 00 00 00 02 7e ef
+ 15 01 00 00 00 00 02 7f 00
+ 15 01 00 00 00 00 02 80 ff
+ 15 01 00 00 00 00 02 81 01
+ 15 01 00 00 00 00 02 82 0b
+ 15 01 00 00 00 00 02 83 01
+ 15 01 00 00 00 00 02 84 38
+ 15 01 00 00 00 00 02 85 01
+ 15 01 00 00 00 00 02 86 5b
+ 15 01 00 00 00 00 02 87 01
+ 15 01 00 00 00 00 02 88 95
+ 15 01 00 00 00 00 02 89 01
+ 15 01 00 00 00 00 02 8a c4
+ 15 01 00 00 00 00 02 8b 02
+ 15 01 00 00 00 00 02 8c 0d
+ 15 01 00 00 00 00 02 8d 02
+ 15 01 00 00 00 00 02 8e 4a
+ 15 01 00 00 00 00 02 8f 02
+ 15 01 00 00 00 00 02 90 4c
+ 15 01 00 00 00 00 02 91 02
+ 15 01 00 00 00 00 02 92 85
+ 15 01 00 00 00 00 02 93 02
+ 15 01 00 00 00 00 02 94 c3
+ 15 01 00 00 00 00 02 95 02
+ 15 01 00 00 00 00 02 96 e9
+ 15 01 00 00 00 00 02 97 03
+ 15 01 00 00 00 00 02 98 16
+ 15 01 00 00 00 00 02 99 03
+ 15 01 00 00 00 00 02 9a 34
+ 15 01 00 00 00 00 02 9b 03
+ 15 01 00 00 00 00 02 9c 56
+ 15 01 00 00 00 00 02 9d 03
+ 15 01 00 00 00 00 02 9e 62
+ 15 01 00 00 00 00 02 9f 03
+ 15 01 00 00 00 00 02 a0 6c
+ 15 01 00 00 00 00 02 a2 03
+ 15 01 00 00 00 00 02 a3 74
+ 15 01 00 00 00 00 02 a4 03
+ 15 01 00 00 00 00 02 a5 80
+ 15 01 00 00 00 00 02 a6 03
+ 15 01 00 00 00 00 02 a7 89
+ 15 01 00 00 00 00 02 a9 03
+ 15 01 00 00 00 00 02 aa 8b
+ 15 01 00 00 00 00 02 ab 03
+ 15 01 00 00 00 00 02 ac 8d
+ 15 01 00 00 00 00 02 ad 03
+ 15 01 00 00 00 00 02 ae 8e
+ 15 01 00 00 00 00 02 af 00
+ 15 01 00 00 00 00 02 b0 71
+ 15 01 00 00 00 00 02 b1 00
+ 15 01 00 00 00 00 02 b2 84
+ 15 01 00 00 00 00 02 b3 00
+ 15 01 00 00 00 00 02 b4 a5
+ 15 01 00 00 00 00 02 b5 00
+ 15 01 00 00 00 00 02 b6 bb
+ 15 01 00 00 00 00 02 b7 00
+ 15 01 00 00 00 00 02 b8 ce
+ 15 01 00 00 00 00 02 b9 00
+ 15 01 00 00 00 00 02 ba e0
+ 15 01 00 00 00 00 02 bb 00
+ 15 01 00 00 00 00 02 bc ef
+ 15 01 00 00 00 00 02 bd 00
+ 15 01 00 00 00 00 02 be ff
+ 15 01 00 00 00 00 02 bf 01
+ 15 01 00 00 00 00 02 c0 0b
+ 15 01 00 00 00 00 02 c1 01
+ 15 01 00 00 00 00 02 c2 38
+ 15 01 00 00 00 00 02 c3 01
+ 15 01 00 00 00 00 02 c4 5b
+ 15 01 00 00 00 00 02 c5 01
+ 15 01 00 00 00 00 02 c6 95
+ 15 01 00 00 00 00 02 c7 01
+ 15 01 00 00 00 00 02 c8 c4
+ 15 01 00 00 00 00 02 c9 02
+ 15 01 00 00 00 00 02 ca 0d
+ 15 01 00 00 00 00 02 cb 02
+ 15 01 00 00 00 00 02 cc 4a
+ 15 01 00 00 00 00 02 cd 02
+ 15 01 00 00 00 00 02 ce 4c
+ 15 01 00 00 00 00 02 cf 02
+ 15 01 00 00 00 00 02 d0 85
+ 15 01 00 00 00 00 02 d1 02
+ 15 01 00 00 00 00 02 d2 c3
+ 15 01 00 00 00 00 02 d3 02
+ 15 01 00 00 00 00 02 d4 e9
+ 15 01 00 00 00 00 02 d5 03
+ 15 01 00 00 00 00 02 d6 16
+ 15 01 00 00 00 00 02 d7 03
+ 15 01 00 00 00 00 02 d8 34
+ 15 01 00 00 00 00 02 d9 03
+ 15 01 00 00 00 00 02 da 56
+ 15 01 00 00 00 00 02 db 03
+ 15 01 00 00 00 00 02 dc 62
+ 15 01 00 00 00 00 02 dd 03
+ 15 01 00 00 00 00 02 de 6c
+ 15 01 00 00 00 00 02 df 03
+ 15 01 00 00 00 00 02 e0 74
+ 15 01 00 00 00 00 02 e1 03
+ 15 01 00 00 00 00 02 e2 80
+ 15 01 00 00 00 00 02 e3 03
+ 15 01 00 00 00 00 02 e4 89
+ 15 01 00 00 00 00 02 e5 03
+ 15 01 00 00 00 00 02 e6 8b
+ 15 01 00 00 00 00 02 e7 03
+ 15 01 00 00 00 00 02 e8 8d
+ 15 01 00 00 00 00 02 e9 03
+ 15 01 00 00 00 00 02 ea 8e
+ 15 01 00 00 00 00 02 FF 10
+ 05 01 00 00 00 00 01 29];
+ qcom,mdss-dsi-off-command =
+ [15 01 00 00 00 00 02 ff 10
+ 05 01 00 00 10 00 01 28
+ 15 01 00 00 00 00 02 b0 00
+ 05 01 00 00 40 00 01 10
+ 15 01 00 00 00 00 02 4f 01];
+ qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+ qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+ qcom,mdss-dsi-h-sync-pulse = <0>;
+ };
};
};
};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sim-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sim-cmd.dtsi
index 1f08294..50da1bf 100644
--- a/arch/arm64/boot/dts/qcom/dsi-panel-sim-cmd.dtsi
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-sim-cmd.dtsi
@@ -14,27 +14,12 @@
dsi_sim_cmd: qcom,mdss_dsi_sim_cmd{
qcom,mdss-dsi-panel-name = "Simulator cmd mode dsi panel";
qcom,mdss-dsi-panel-type = "dsi_cmd_mode";
- qcom,mdss-dsi-panel-framerate = <60>;
qcom,mdss-dsi-virtual-channel-id = <0>;
qcom,mdss-dsi-stream = <0>;
- qcom,mdss-dsi-panel-width = <640>;
- qcom,mdss-dsi-panel-height = <480>;
- qcom,mdss-dsi-h-front-porch = <20>;
- qcom,mdss-dsi-h-back-porch = <20>;
- qcom,mdss-dsi-h-pulse-width = <16>;
- qcom,mdss-dsi-h-sync-skew = <0>;
- qcom,mdss-dsi-v-back-porch = <16>;
- qcom,mdss-dsi-v-front-porch = <4>;
- qcom,mdss-dsi-v-pulse-width = <1>;
- qcom,mdss-dsi-h-left-border = <0>;
- qcom,mdss-dsi-h-right-border = <0>;
- qcom,mdss-dsi-v-top-border = <0>;
- qcom,mdss-dsi-v-bottom-border = <0>;
qcom,mdss-dsi-bpp = <24>;
qcom,mdss-dsi-color-order = "rgb_swap_rgb";
qcom,mdss-dsi-underflow-color = <0xff>;
qcom,mdss-dsi-border-color = <0>;
- qcom,mdss-dsi-h-sync-pulse = <0>;
qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
qcom,mdss-dsi-bllp-eof-power-mode;
qcom,mdss-dsi-bllp-power-mode;
@@ -42,11 +27,6 @@
qcom,mdss-dsi-lane-1-state;
qcom,mdss-dsi-lane-2-state;
qcom,mdss-dsi-lane-3-state;
- qcom,mdss-dsi-hor-line-idle = <0 40 256>,
- <40 120 128>,
- <120 240 64>;
- qcom,mdss-dsi-panel-timings = [cd 32 22 00 60 64 26 34 29 03
- 04 00];
qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>;
qcom,mdss-dsi-t-clk-post = <0x03>;
qcom,mdss-dsi-t-clk-pre = <0x27>;
@@ -65,33 +45,60 @@
17000 15500 30000 8000 3000>;
qcom,mdss-dsi-panel-peak-brightness = <4200000>;
qcom,mdss-dsi-panel-blackness-level = <3230>;
- qcom,mdss-dsi-on-command = [29 01 00 00 00 00 02 b0 03
- 05 01 00 00 0a 00 01 00
- /* Soft reset, wait 10ms */
- 15 01 00 00 0a 00 02 3a 77
- /* Set Pixel format (24 bpp) */
- 39 01 00 00 0a 00 05 2a 00 00 04 ff
- /* Set Column address */
- 39 01 00 00 0a 00 05 2b 00 00 05 9f
- /* Set page address */
- 15 01 00 00 0a 00 02 35 00
- /* Set tear on */
- 39 01 00 00 0a 00 03 44 00 00
- /* Set tear scan line */
- 15 01 00 00 0a 00 02 51 ff
- /* write display brightness */
- 15 01 00 00 0a 00 02 53 24
- /* write control brightness */
- 15 01 00 00 0a 00 02 55 00
- /* CABC brightness */
- 05 01 00 00 78 00 01 11
- /* exit sleep mode, wait 120ms */
- 05 01 00 00 10 00 01 29];
- /* Set display on, wait 16ms */
- qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
- qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00
- 05 01 00 00 78 00 02 10 00];
- qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
qcom,panel-ack-disabled;
+
+ qcom,mdss-dsi-display-timings {
+ timing@0{
+ qcom,mdss-dsi-panel-width = <640>;
+ qcom,mdss-dsi-panel-height = <480>;
+ qcom,mdss-dsi-h-front-porch = <20>;
+ qcom,mdss-dsi-h-back-porch = <20>;
+ qcom,mdss-dsi-h-pulse-width = <16>;
+ qcom,mdss-dsi-h-sync-skew = <0>;
+ qcom,mdss-dsi-v-back-porch = <16>;
+ qcom,mdss-dsi-v-front-porch = <4>;
+ qcom,mdss-dsi-v-pulse-width = <1>;
+ qcom,mdss-dsi-h-left-border = <0>;
+ qcom,mdss-dsi-h-right-border = <0>;
+ qcom,mdss-dsi-v-top-border = <0>;
+ qcom,mdss-dsi-v-bottom-border = <0>;
+ qcom,mdss-dsi-h-sync-pulse = <0>;
+ qcom,mdss-dsi-panel-framerate = <60>;
+ qcom,mdss-dsi-hor-line-idle = <0 40 256>,
+ <40 120 128>,
+ <120 240 64>;
+ qcom,mdss-dsi-panel-timings =
+ [cd 32 22 00 60 64 26 34 29 03 04 00];
+ qcom,mdss-dsi-on-command =
+ [29 01 00 00 00 00 02 b0 03
+ 05 01 00 00 0a 00 01 00
+ /* Soft reset, wait 10ms */
+ 15 01 00 00 0a 00 02 3a 77
+ /* Set Pixel format (24 bpp) */
+ 39 01 00 00 0a 00 05 2a 00 00 04 ff
+ /* Set Column address */
+ 39 01 00 00 0a 00 05 2b 00 00 05 9f
+ /* Set page address */
+ 15 01 00 00 0a 00 02 35 00
+ /* Set tear on */
+ 39 01 00 00 0a 00 03 44 00 00
+ /* Set tear scan line */
+ 15 01 00 00 0a 00 02 51 ff
+ /* write display brightness */
+ 15 01 00 00 0a 00 02 53 24
+ /* write control brightness */
+ 15 01 00 00 0a 00 02 55 00
+ /* CABC brightness */
+ 05 01 00 00 78 00 01 11
+ /* exit sleep mode, wait 120ms */
+ 05 01 00 00 10 00 01 29];
+ /* Set display on, wait 16ms */
+ qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+ qcom,mdss-dsi-off-command =
+ [05 01 00 00 32 00 02 28 00
+ 05 01 00 00 78 00 02 10 00];
+ qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+ };
+ };
};
};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-cmd.dtsi
index 36f36fb..895cbc5 100644
--- a/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-cmd.dtsi
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-cmd.dtsi
@@ -14,27 +14,12 @@
dsi_dual_sim_cmd: qcom,mdss_dsi_dual_sim_cmd {
qcom,mdss-dsi-panel-name = "Sim dual cmd mode dsi panel";
qcom,mdss-dsi-panel-type = "dsi_cmd_mode";
- qcom,mdss-dsi-panel-framerate = <60>;
qcom,mdss-dsi-virtual-channel-id = <0>;
qcom,mdss-dsi-stream = <0>;
- qcom,mdss-dsi-panel-width = <1280>;
- qcom,mdss-dsi-panel-height = <1440>;
- qcom,mdss-dsi-h-front-porch = <120>;
- qcom,mdss-dsi-h-back-porch = <44>;
- qcom,mdss-dsi-h-pulse-width = <16>;
- qcom,mdss-dsi-h-sync-skew = <0>;
- qcom,mdss-dsi-v-back-porch = <4>;
- qcom,mdss-dsi-v-front-porch = <8>;
- qcom,mdss-dsi-v-pulse-width = <4>;
- qcom,mdss-dsi-h-left-border = <0>;
- qcom,mdss-dsi-h-right-border = <0>;
- qcom,mdss-dsi-v-top-border = <0>;
- qcom,mdss-dsi-v-bottom-border = <0>;
qcom,mdss-dsi-bpp = <24>;
qcom,mdss-dsi-color-order = "rgb_swap_rgb";
qcom,mdss-dsi-underflow-color = <0xff>;
qcom,mdss-dsi-border-color = <0>;
- qcom,mdss-dsi-h-sync-pulse = <0>;
qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
qcom,mdss-dsi-bllp-eof-power-mode;
qcom,mdss-dsi-bllp-power-mode;
@@ -57,33 +42,80 @@
qcom,mdss-dsi-te-check-enable;
qcom,mdss-dsi-te-using-wd;
qcom,mdss-dsi-te-using-te-pin;
- qcom,mdss-dsi-on-command = [29 01 00 00 00 00 02 b0 03
- 05 01 00 00 0a 00 01 00
- /* Soft reset, wait 10ms */
- 15 01 00 00 0a 00 02 3a 77
- /* Set Pixel format (24 bpp) */
- 39 01 00 00 0a 00 05 2a 00 00 04 ff
- /* Set Column address */
- 39 01 00 00 0a 00 05 2b 00 00 05 9f
- /* Set page address */
- 15 01 00 00 0a 00 02 35 00
- /* Set tear on */
- 39 01 00 00 0a 00 03 44 00 00
- /* Set tear scan line */
- 15 01 00 00 0a 00 02 51 ff
- /* write display brightness */
- 15 01 00 00 0a 00 02 53 24
- /* write control brightness */
- 15 01 00 00 0a 00 02 55 00
- /* CABC brightness */
- 05 01 00 00 78 00 01 11
- /* exit sleep mode, wait 120ms */
- 05 01 00 00 10 00 01 29];
- /* Set display on, wait 16ms */
- qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
- qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00
- 05 01 00 00 78 00 02 10 00];
- qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
qcom,panel-ack-disabled;
+
+ qcom,mdss-dsi-display-timings {
+ timing@0{
+ qcom,mdss-dsi-panel-width = <540>;
+ qcom,mdss-dsi-panel-height = <1920>;
+ qcom,mdss-dsi-h-front-porch = <28>;
+ qcom,mdss-dsi-h-back-porch = <4>;
+ qcom,mdss-dsi-h-pulse-width = <4>;
+ qcom,mdss-dsi-h-sync-skew = <0>;
+ qcom,mdss-dsi-v-back-porch = <12>;
+ qcom,mdss-dsi-v-front-porch = <12>;
+ qcom,mdss-dsi-v-pulse-width = <2>;
+ qcom,mdss-dsi-h-left-border = <0>;
+ qcom,mdss-dsi-h-right-border = <0>;
+ qcom,mdss-dsi-v-top-border = <0>;
+ qcom,mdss-dsi-v-bottom-border = <0>;
+ qcom,mdss-dsi-panel-framerate = <120>;
+ qcom,mdss-dsi-on-command =
+ [/* exit sleep mode, wait 0ms */
+ 05 01 00 00 00 00 01 29];
+ /* Set display on, wait 16ms */
+ qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+ qcom,mdss-dsi-off-command =
+ [05 01 00 00 00 00 02 28 00
+ 05 01 00 00 00 00 02 10 00];
+ qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+ };
+ timing@1{
+ qcom,mdss-dsi-panel-width = <1280>;
+ qcom,mdss-dsi-panel-height = <1440>;
+ qcom,mdss-dsi-h-front-porch = <120>;
+ qcom,mdss-dsi-h-back-porch = <44>;
+ qcom,mdss-dsi-h-pulse-width = <16>;
+ qcom,mdss-dsi-h-sync-skew = <0>;
+ qcom,mdss-dsi-v-back-porch = <4>;
+ qcom,mdss-dsi-v-front-porch = <8>;
+ qcom,mdss-dsi-v-pulse-width = <4>;
+ qcom,mdss-dsi-h-left-border = <0>;
+ qcom,mdss-dsi-h-right-border = <0>;
+ qcom,mdss-dsi-v-top-border = <0>;
+ qcom,mdss-dsi-v-bottom-border = <0>;
+ qcom,mdss-dsi-h-sync-pulse = <0>;
+ qcom,mdss-dsi-panel-framerate = <60>;
+ qcom,mdss-dsi-on-command =
+ [/* exit sleep mode, wait 0ms */
+ 05 01 00 00 00 00 01 29];
+ qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+ qcom,mdss-dsi-off-command =
+ [05 01 00 00 00 00 02 28 00
+ 05 01 00 00 00 00 02 10 00];
+ qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+ };
+ timing@2{
+ qcom,mdss-dsi-panel-width = <1080>;
+ qcom,mdss-dsi-panel-height = <3840>;
+ qcom,mdss-dsi-h-front-porch = <30>;
+ qcom,mdss-dsi-h-back-porch = <100>;
+ qcom,mdss-dsi-h-pulse-width = <4>;
+ qcom,mdss-dsi-h-sync-skew = <0>;
+ qcom,mdss-dsi-v-back-porch = <7>;
+ qcom,mdss-dsi-v-front-porch = <8>;
+ qcom,mdss-dsi-v-pulse-width = <1>;
+ qcom,mdss-dsi-h-sync-pulse = <0>;
+ qcom,mdss-dsi-panel-framerate = <40>;
+ qcom,mdss-dsi-on-command =
+ [/* exit sleep mode, wait 0ms */
+ 05 01 00 00 00 00 01 29];
+ qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+ qcom,mdss-dsi-off-command =
+ [05 01 00 00 00 00 02 28 00
+ 05 01 00 00 00 00 02 10 00];
+ qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+ };
+ };
};
};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-video.dtsi
index cca28c7..dbfedb9 100644
--- a/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-video.dtsi
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-video.dtsi
@@ -14,26 +14,11 @@
dsi_dual_sim_vid: qcom,mdss_dsi_dual_sim_video {
qcom,mdss-dsi-panel-name = "Sim dual video mode dsi panel";
qcom,mdss-dsi-panel-type = "dsi_video_mode";
- qcom,mdss-dsi-panel-framerate = <60>;
qcom,mdss-dsi-virtual-channel-id = <0>;
qcom,mdss-dsi-stream = <0>;
- qcom,mdss-dsi-panel-width = <1280>;
- qcom,mdss-dsi-panel-height = <1440>;
- qcom,mdss-dsi-h-front-porch = <120>;
- qcom,mdss-dsi-h-back-porch = <44>;
- qcom,mdss-dsi-h-pulse-width = <16>;
- qcom,mdss-dsi-h-sync-skew = <0>;
- qcom,mdss-dsi-v-back-porch = <4>;
- qcom,mdss-dsi-v-front-porch = <8>;
- qcom,mdss-dsi-v-pulse-width = <4>;
- qcom,mdss-dsi-h-left-border = <0>;
- qcom,mdss-dsi-h-right-border = <0>;
- qcom,mdss-dsi-v-top-border = <0>;
- qcom,mdss-dsi-v-bottom-border = <0>;
qcom,mdss-dsi-bpp = <24>;
qcom,mdss-dsi-underflow-color = <0xff>;
qcom,mdss-dsi-border-color = <0>;
- qcom,mdss-dsi-h-sync-pulse = <0>;
qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
qcom,mdss-dsi-bllp-eof-power-mode;
qcom,mdss-dsi-bllp-power-mode;
@@ -45,11 +30,32 @@
qcom,mdss-dsi-bl-max-level = <4095>;
qcom,mdss-dsi-dma-trigger = "trigger_sw";
qcom,mdss-dsi-mdp-trigger = "none";
- qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
- qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00
- 05 01 00 00 78 00 02 10 00];
- qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
qcom,mdss-dsi-reset-sequence = <1 20>, <0 200>, <1 20>;
qcom,panel-ack-disabled;
+
+ qcom,mdss-dsi-display-timings {
+ timing@0{
+ qcom,mdss-dsi-panel-width = <1280>;
+ qcom,mdss-dsi-panel-height = <1440>;
+ qcom,mdss-dsi-h-front-porch = <120>;
+ qcom,mdss-dsi-h-back-porch = <44>;
+ qcom,mdss-dsi-h-pulse-width = <16>;
+ qcom,mdss-dsi-h-sync-skew = <0>;
+ qcom,mdss-dsi-v-back-porch = <4>;
+ qcom,mdss-dsi-v-front-porch = <8>;
+ qcom,mdss-dsi-v-pulse-width = <4>;
+ qcom,mdss-dsi-h-left-border = <0>;
+ qcom,mdss-dsi-h-right-border = <0>;
+ qcom,mdss-dsi-v-top-border = <0>;
+ qcom,mdss-dsi-v-bottom-border = <0>;
+ qcom,mdss-dsi-h-sync-pulse = <0>;
+ qcom,mdss-dsi-panel-framerate = <60>;
+ qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+ qcom,mdss-dsi-off-command =
+ [05 01 00 00 32 00 02 28 00
+ 05 01 00 00 78 00 02 10 00];
+ qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+ };
+ };
};
};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sim-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sim-video.dtsi
index 98a1f61..40bedd0 100644
--- a/arch/arm64/boot/dts/qcom/dsi-panel-sim-video.dtsi
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-sim-video.dtsi
@@ -14,22 +14,8 @@
dsi_sim_vid: qcom,mdss_dsi_sim_video {
qcom,mdss-dsi-panel-name = "Simulator video mode dsi panel";
qcom,mdss-dsi-panel-type = "dsi_video_mode";
- qcom,mdss-dsi-panel-framerate = <60>;
qcom,mdss-dsi-virtual-channel-id = <0>;
qcom,mdss-dsi-stream = <0>;
- qcom,mdss-dsi-panel-width = <640>;
- qcom,mdss-dsi-panel-height = <480>;
- qcom,mdss-dsi-h-front-porch = <8>;
- qcom,mdss-dsi-h-back-porch = <8>;
- qcom,mdss-dsi-h-pulse-width = <8>;
- qcom,mdss-dsi-h-sync-skew = <0>;
- qcom,mdss-dsi-v-back-porch = <6>;
- qcom,mdss-dsi-v-front-porch = <6>;
- qcom,mdss-dsi-v-pulse-width = <2>;
- qcom,mdss-dsi-h-left-border = <0>;
- qcom,mdss-dsi-h-right-border = <0>;
- qcom,mdss-dsi-v-top-border = <0>;
- qcom,mdss-dsi-v-bottom-border = <0>;
qcom,mdss-dsi-bpp = <24>;
qcom,mdss-dsi-underflow-color = <0xff>;
qcom,mdss-dsi-border-color = <0>;
@@ -38,11 +24,6 @@
17000 15500 30000 8000 3000>;
qcom,mdss-dsi-panel-peak-brightness = <4200000>;
qcom,mdss-dsi-panel-blackness-level = <3230>;
- qcom,mdss-dsi-on-command = [32 01 00 00 00 00 02 00 00];
- qcom,mdss-dsi-off-command = [22 01 00 00 00 00 02 00 00];
- qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
- qcom,mdss-dsi-off-command-state = "dsi_lp_mode";
- qcom,mdss-dsi-h-sync-pulse = <0>;
qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
qcom,mdss-dsi-bllp-eof-power-mode;
qcom,mdss-dsi-bllp-power-mode;
@@ -50,13 +31,39 @@
qcom,mdss-dsi-lane-1-state;
qcom,mdss-dsi-lane-2-state;
qcom,mdss-dsi-lane-3-state;
- qcom,mdss-dsi-panel-timings =
- [00 00 00 00 00 00 00 00 00 00 00 00];
qcom,mdss-dsi-t-clk-post = <0x04>;
qcom,mdss-dsi-t-clk-pre = <0x1b>;
qcom,mdss-dsi-dma-trigger = "trigger_sw";
qcom,mdss-dsi-mdp-trigger = "none";
qcom,mdss-dsi-reset-sequence = <1 0>, <0 0>, <1 0>;
qcom,panel-ack-disabled;
+
+ qcom,mdss-dsi-display-timings {
+ timing@0{
+ qcom,mdss-dsi-panel-width = <640>;
+ qcom,mdss-dsi-panel-height = <480>;
+ qcom,mdss-dsi-h-front-porch = <8>;
+ qcom,mdss-dsi-h-back-porch = <8>;
+ qcom,mdss-dsi-h-pulse-width = <8>;
+ qcom,mdss-dsi-h-sync-skew = <0>;
+ qcom,mdss-dsi-v-back-porch = <6>;
+ qcom,mdss-dsi-v-front-porch = <6>;
+ qcom,mdss-dsi-v-pulse-width = <2>;
+ qcom,mdss-dsi-h-left-border = <0>;
+ qcom,mdss-dsi-h-right-border = <0>;
+ qcom,mdss-dsi-v-top-border = <0>;
+ qcom,mdss-dsi-v-bottom-border = <0>;
+ qcom,mdss-dsi-panel-framerate = <60>;
+ qcom,mdss-dsi-panel-timings =
+ [00 00 00 00 00 00 00 00 00 00 00 00];
+ qcom,mdss-dsi-on-command =
+ [32 01 00 00 00 00 02 00 00];
+ qcom,mdss-dsi-off-command =
+ [22 01 00 00 00 00 02 00 00];
+ qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+ qcom,mdss-dsi-off-command-state = "dsi_lp_mode";
+ qcom,mdss-dsi-h-sync-pulse = <0>;
+ };
+ };
};
};
diff --git a/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-gt3746a6-2900mah.dtsi b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-gt3746a6-2900mah.dtsi
new file mode 100644
index 0000000..95dd07e
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-gt3746a6-2900mah.dtsi
@@ -0,0 +1,81 @@
+/* Copyright (c) 2017, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+qcom,gt3746a6_2900mah {
+ /* #GT3746A6_2900mAh_averaged_MasterSlave_May11th2017*/
+ qcom,max-voltage-uv = <4350000>;
+ qcom,fg-cc-cv-threshold-mv = <4340>;
+ qcom,fastchg-current-ma = <2900>;
+ qcom,batt-id-kohm = <121>;
+ qcom,battery-beta = <3435>;
+ qcom,battery-type = "GT3746A6_2900mah_averaged_masterslave_may11th2017";
+ qcom,checksum = <0xDF27>;
+ qcom,gui-version = "PMI8998GUI - 2.0.0.57";
+ qcom,fg-profile-data = [
+ C9 1F 44 05
+ A5 0A 27 06
+ F0 1C 07 01
+ 49 F2 91 05
+ C3 17 42 23
+ 69 45 E8 52
+ 58 00 00 00
+ 0E 00 00 00
+ 00 00 DF A2
+ 12 CD 0C C3
+ 19 00 08 00
+ 89 C2 A5 ED
+ DF 05 1A 01
+ C0 05 10 12
+ 03 CA C2 32
+ 32 06 09 20
+ 27 00 14 00
+ 69 20 CD 04
+ F1 0A E3 05
+ 12 1D 59 01
+ A3 ED D1 05
+ 95 18 27 23
+ 35 45 6D 53
+ 5F 00 00 00
+ 0E 00 00 00
+ 00 00 0A D5
+ A6 B5 D0 D2
+ 14 00 00 00
+ 52 F2 A5 ED
+ 57 06 AA F2
+ 29 F4 A5 0B
+ 4D FD FA 1A
+ AD 33 CC FF
+ 07 10 00 00
+ 27 0B 99 45
+ 14 00 40 00
+ 26 02 0A FA
+ FF 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ ];
+};
diff --git a/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-mlp356477-2800mah.dtsi b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-mlp356477-2800mah.dtsi
new file mode 100644
index 0000000..98dbf1c
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-mlp356477-2800mah.dtsi
@@ -0,0 +1,82 @@
+/* Copyright (c) 2017, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+qcom,mlp356477_2800mah {
+ /* #mlp356477_2800mah_averaged_MasterSlave_Aug14th2017*/
+ qcom,max-voltage-uv = <4400000>;
+ qcom,fg-cc-cv-threshold-mv = <4390>;
+ qcom,fastchg-current-ma = <2800>;
+ qcom,batt-id-kohm = <82>;
+ qcom,battery-beta = <4250>;
+ qcom,battery-type =
+ "mlp356477_2800mah_averaged_masterslave_aug14th2017";
+ qcom,checksum = <0x71B8>;
+ qcom,gui-version = "PM660GUI - 0.0.0.44";
+ qcom,fg-profile-data = [
+ 60 1F BE 05
+ 75 0A 40 06
+ 81 1D F1 06
+ B4 12 CC 1D
+ CF 18 2A 22
+ 49 3D 4B 4A
+ 52 00 00 00
+ 18 00 00 00
+ 00 00 00 9C
+ 0C CC BA CA
+ 2B 00 08 00
+ C5 E2 F9 ED
+ 30 05 D5 01
+ 9E 06 62 12
+ 4E E2 82 2B
+ 2D 06 09 20
+ 27 00 14 00
+ DD 1F 70 05
+ 9E 0A 23 06
+ 81 1D DD EC
+ 4C 12 D2 1D
+ DB 18 1F 23
+ 3E 45 5E 53
+ 52 00 00 00
+ 0D 00 00 00
+ 00 00 B8 D5
+ 37 CA 89 BB
+ 25 00 00 00
+ AE EA F9 ED
+ BF 05 9D FA
+ DD 05 3E 01
+ B7 F5 8A 22
+ C9 33 CC FF
+ 07 10 00 00
+ 34 0B 66 46
+ 25 00 40 00
+ 87 01 0A FA
+ FF 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ ];
+};
diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi
index 02fedbe..56e74be 100644
--- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi
@@ -34,14 +34,10 @@
<GIC_SPI 369 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 370 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 371 IRQ_TYPE_EDGE_RISING>;
- clock-names = "gcc_ddrss_gpu_axi_clk",
- "gcc_gpu_memnoc_gfx_clk",
- "gpu_cc_ahb_clk",
- "gpu_cc_cx_gmu_clk";
- clocks = <&clock_gcc GCC_DDRSS_GPU_AXI_CLK>,
- <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>,
- <&clock_gpucc GPU_CC_AHB_CLK>,
- <&clock_gpucc GPU_CC_CX_GMU_CLK>;
+ clock-names = "gcc_gpu_memnoc_gfx_clk",
+ "gpu_cc_ahb_clk";
+ clocks = <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>,
+ <&clock_gpucc GPU_CC_AHB_CLK>;
attach-impl-defs =
<0x6000 0x2378>,
<0x6060 0x1055>,
diff --git a/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi b/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi
index bc0b118..0d2f9e8 100644
--- a/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi
@@ -85,7 +85,7 @@
compatible = "qcom,msm-pcm-loopback";
};
- qcom,msm-dai-mi2s {
+ msm_dai_mi2s: qcom,msm-dai-mi2s {
compatible = "qcom,msm-dai-mi2s";
dai_mi2s0: qcom,msm-dai-q6-mi2s-prim {
compatible = "qcom,msm-dai-q6-mi2s";
diff --git a/arch/arm64/boot/dts/qcom/pm660.dtsi b/arch/arm64/boot/dts/qcom/pm660.dtsi
index 5d71f2d..5f23b91 100644
--- a/arch/arm64/boot/dts/qcom/pm660.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm660.dtsi
@@ -652,6 +652,27 @@
reg = <0x1 SPMI_USID>;
#address-cells = <2>;
#size-cells = <0>;
+
+ pm660_haptics: qcom,haptics@c000 {
+ compatible = "qcom,qpnp-haptics";
+ reg = <0xc000 0x100>;
+ interrupts = <0x1 0xc0 0x0 IRQ_TYPE_EDGE_BOTH>,
+ <0x1 0xc0 0x1 IRQ_TYPE_EDGE_BOTH>;
+ interrupt-names = "hap-sc-irq", "hap-play-irq";
+ qcom,pmic-revid = <&pm660_revid>;
+ qcom,pmic-misc = <&pm660_misc>;
+ qcom,misc-clk-trim-error-reg = <0xf3>;
+ qcom,actuator-type = <0>;
+ qcom,play-mode = "direct";
+ qcom,vmax-mv = <3200>;
+ qcom,ilim-ma = <800>;
+ qcom,sc-dbc-cycles = <8>;
+ qcom,wave-play-rate-us = <6667>;
+ qcom,en-brake;
+ qcom,lra-high-z = "opt0";
+ qcom,lra-auto-res-mode = "qwd";
+ qcom,lra-res-cal-period = <4>;
+ };
};
};
diff --git a/arch/arm64/boot/dts/qcom/pm660l.dtsi b/arch/arm64/boot/dts/qcom/pm660l.dtsi
index 0f18ba5..075eaef2 100644
--- a/arch/arm64/boot/dts/qcom/pm660l.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm660l.dtsi
@@ -250,9 +250,8 @@
<0xd900 0x100>;
reg-names = "qpnp-wled-ctrl-base",
"qpnp-wled-sink-base";
- interrupts = <0x3 0xd8 0x1 IRQ_TYPE_EDGE_RISING>,
- <0x3 0xd8 0x2 IRQ_TYPE_EDGE_RISING>;
- interrupt-names = "ovp-irq", "sc-irq";
+ interrupts = <0x3 0xd8 0x1 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "ovp-irq";
linux,name = "wled";
linux,default-trigger = "bkl-trigger";
qcom,fdbk-output = "auto";
@@ -268,9 +267,9 @@
qcom,fs-curr-ua = <25000>;
qcom,cons-sync-write-delay-us = <1000>;
qcom,led-strings-list = [00 01 02];
- qcom,en-ext-pfet-sc-pro;
qcom,loop-auto-gm-en;
qcom,pmic-revid = <&pm660l_revid>;
+ qcom,auto-calibration-enable;
status = "ok";
};
diff --git a/arch/arm64/boot/dts/qcom/pmi8998.dtsi b/arch/arm64/boot/dts/qcom/pmi8998.dtsi
index 09405ee..a8b826a 100644
--- a/arch/arm64/boot/dts/qcom/pmi8998.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi8998.dtsi
@@ -12,9 +12,10 @@
#include <dt-bindings/spmi/spmi.h>
#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/thermal/thermal.h>
&spmi_bus {
- qcom,pmi8998@2 {
+ pmi8998_lsid0: qcom,pmi8998@2 {
compatible = "qcom,spmi-pmic";
reg = <0x2 SPMI_USID>;
#address-cells = <2>;
@@ -335,7 +336,7 @@
};
};
- qcom,pmi8998@3 {
+ pmi8998_lsid1: qcom,pmi8998@3 {
compatible ="qcom,spmi-pmic";
reg = <0x3 SPMI_USID>;
#address-cells = <2>;
@@ -563,6 +564,7 @@
qcom,en-ext-pfet-sc-pro;
qcom,pmic-revid = <&pmi8998_revid>;
qcom,loop-auto-gm-en;
+ qcom,auto-calibration-enable;
status = "disabled";
};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-audio.dtsi b/arch/arm64/boot/dts/qcom/sdm670-audio.dtsi
new file mode 100644
index 0000000..3bd0350
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-audio.dtsi
@@ -0,0 +1,568 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. 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 and
+ * only 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 "msm-audio-lpass.dtsi"
+#include "sdm670-wsa881x.dtsi"
+#include "sdm670-wcd.dtsi"
+#include "sdm670-lpi.dtsi"
+#include <dt-bindings/clock/qcom,audio-ext-clk.h>
+
+&msm_audio_ion {
+ iommus = <&apps_smmu 0x1801 0x0>;
+ qcom,smmu-sid-mask = /bits/ 64 <0xf>;
+};
+
+&soc {
+ qcom,avtimer@62cf700c {
+ compatible = "qcom,avtimer";
+ reg = <0x62cf700c 0x4>,
+ <0x62cf7010 0x4>;
+ reg-names = "avtimer_lsb_addr", "avtimer_msb_addr";
+ qcom,clk-div = <192>;
+ qcom,clk-mult = <10>;
+ };
+
+ tavil_snd: sound-tavil {
+ status = "disabled";
+ compatible = "qcom,sdm670-asoc-snd-tavil";
+ qcom,model = "sdm670-tavil-snd-card";
+ qcom,wcn-btfm;
+ qcom,mi2s-audio-intf;
+ qcom,auxpcm-audio-intf;
+ qcom,msm-mi2s-master = <1>, <1>, <1>, <1>;
+ qcom,audio-routing =
+ "AIF4 VI", "MCLK",
+ "RX_BIAS", "MCLK",
+ "MADINPUT", "MCLK",
+ "hifi amp", "LINEOUT1",
+ "hifi amp", "LINEOUT2",
+ "AMIC2", "MIC BIAS2",
+ "MIC BIAS2", "Headset Mic",
+ "AMIC3", "MIC BIAS2",
+ "MIC BIAS2", "ANCRight Headset Mic",
+ "AMIC4", "MIC BIAS2",
+ "MIC BIAS2", "ANCLeft Headset Mic",
+ "AMIC5", "MIC BIAS3",
+ "MIC BIAS3", "Handset Mic",
+ "DMIC0", "MIC BIAS1",
+ "MIC BIAS1", "Digital Mic0",
+ "DMIC1", "MIC BIAS1",
+ "MIC BIAS1", "Digital Mic1",
+ "DMIC2", "MIC BIAS3",
+ "MIC BIAS3", "Digital Mic2",
+ "DMIC3", "MIC BIAS3",
+ "MIC BIAS3", "Digital Mic3",
+ "DMIC4", "MIC BIAS4",
+ "MIC BIAS4", "Digital Mic4",
+ "DMIC5", "MIC BIAS4",
+ "MIC BIAS4", "Digital Mic5",
+ "SpkrLeft IN", "SPK1 OUT",
+ "SpkrRight IN", "SPK2 OUT";
+
+ qcom,msm-mbhc-hphl-swh = <1>;
+ qcom,msm-mbhc-gnd-swh = <1>;
+ qcom,hph-en0-gpio = <&tavil_hph_en0>;
+ qcom,hph-en1-gpio = <&tavil_hph_en1>;
+ qcom,msm-mclk-freq = <9600000>;
+ qcom,usbc-analog-en1_gpio = <&wcd_usbc_analog_en1_gpio>;
+ asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
+ <&loopback>, <&compress>, <&hostless>,
+ <&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>,
+ <&pcm_noirq>;
+ asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
+ "msm-pcm-dsp.2", "msm-voip-dsp",
+ "msm-pcm-voice", "msm-pcm-loopback",
+ "msm-compress-dsp", "msm-pcm-hostless",
+ "msm-pcm-afe", "msm-lsm-client",
+ "msm-pcm-routing", "msm-cpe-lsm",
+ "msm-compr-dsp", "msm-pcm-dsp-noirq";
+ asoc-cpu = <&dai_mi2s0>, <&dai_mi2s1>,
+ <&dai_mi2s2>, <&dai_mi2s3>,
+ <&dai_pri_auxpcm>, <&dai_sec_auxpcm>,
+ <&dai_tert_auxpcm>, <&dai_quat_auxpcm>,
+ <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>,
+ <&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>,
+ <&sb_4_rx>, <&sb_4_tx>, <&sb_5_rx>, <&sb_5_tx>,
+ <&sb_6_rx>, <&sb_7_rx>, <&sb_7_tx>,
+ <&sb_8_rx>, <&sb_8_tx>,
+ <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>,
+ <&afe_proxy_tx>, <&incall_record_rx>,
+ <&incall_record_tx>, <&incall_music_rx>,
+ <&incall_music_2_rx>,
+ <&usb_audio_rx>, <&usb_audio_tx>,
+ <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>,
+ <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>,
+ <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>,
+ <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>;
+ asoc-cpu-names = "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1",
+ "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
+ "msm-dai-q6-auxpcm.1", "msm-dai-q6-auxpcm.2",
+ "msm-dai-q6-auxpcm.3", "msm-dai-q6-auxpcm.4",
+ "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385",
+ "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387",
+ "msm-dai-q6-dev.16388", "msm-dai-q6-dev.16389",
+ "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391",
+ "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393",
+ "msm-dai-q6-dev.16394", "msm-dai-q6-dev.16395",
+ "msm-dai-q6-dev.16396",
+ "msm-dai-q6-dev.16398", "msm-dai-q6-dev.16399",
+ "msm-dai-q6-dev.16400", "msm-dai-q6-dev.16401",
+ "msm-dai-q6-dev.224", "msm-dai-q6-dev.225",
+ "msm-dai-q6-dev.241", "msm-dai-q6-dev.240",
+ "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772",
+ "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770",
+ "msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673",
+ "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36865",
+ "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881",
+ "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36897",
+ "msm-dai-q6-tdm.36912", "msm-dai-q6-tdm.36913";
+ asoc-codec = <&stub_codec>;
+ asoc-codec-names = "msm-stub-codec.1";
+ qcom,wsa-max-devs = <2>;
+ qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0212>,
+ <&wsa881x_0213>, <&wsa881x_0214>;
+ qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight",
+ "SpkrLeft", "SpkrRight";
+ };
+
+int_codec: sound {
+ status = "okay";
+ compatible = "qcom,sdm670-asoc-snd";
+ qcom,model = "sdm670-snd-card";
+ qcom,wcn-btfm;
+ qcom,mi2s-audio-intf;
+ qcom,auxpcm-audio-intf;
+ qcom,msm-mi2s-master = <1>, <1>, <1>, <1>;
+ qcom,msm-mclk-freq = <9600000>;
+ qcom,msm-mbhc-hphl-swh = <1>;
+ qcom,msm-mbhc-gnd-swh = <1>;
+ qcom,msm-micbias2-ext-cap;
+ qcom,msm-hs-micbias-type = "external";
+ qcom,cdc-pdm-gpios = <&cdc_pdm_gpios>;
+ qcom,cdc-comp-gpios = <&cdc_comp_gpios>;
+ qcom,cdc-dmic-gpios = <&cdc_dmic_gpios>;
+ qcom,audio-routing =
+ "RX_BIAS", "INT_MCLK0",
+ "SPK_RX_BIAS", "INT_MCLK0",
+ "INT_LDO_H", "INT_MCLK0",
+ "MIC BIAS External", "Handset Mic",
+ "MIC BIAS External2", "Headset Mic",
+ "MIC BIAS External", "Secondary Mic",
+ "AMIC1", "MIC BIAS External",
+ "AMIC2", "MIC BIAS External2",
+ "AMIC3", "MIC BIAS External",
+ "DMIC1", "MIC BIAS External",
+ "MIC BIAS External", "Digital Mic1",
+ "DMIC2", "MIC BIAS External",
+ "MIC BIAS External", "Digital Mic2",
+ "DMIC3", "MIC BIAS External",
+ "MIC BIAS External", "Digital Mic3",
+ "DMIC4", "MIC BIAS External",
+ "MIC BIAS External", "Digital Mic4",
+ "SpkrLeft IN", "SPK1 OUT",
+ "SpkrRight IN", "SPK2 OUT",
+ "PDM_IN_RX1", "PDM_OUT_RX1",
+ "PDM_IN_RX2", "PDM_OUT_RX2",
+ "PDM_IN_RX3", "PDM_OUT_RX3",
+ "ADC1_IN", "ADC1_OUT",
+ "ADC2_IN", "ADC2_OUT",
+ "ADC3_IN", "ADC3_OUT";
+
+ asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
+ <&loopback>, <&compress>, <&hostless>,
+ <&afe>, <&lsm>, <&routing>, <&compr>,
+ <&pcm_noirq>;
+ asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
+ "msm-pcm-dsp.2", "msm-voip-dsp",
+ "msm-pcm-voice", "msm-pcm-loopback",
+ "msm-compress-dsp", "msm-pcm-hostless",
+ "msm-pcm-afe", "msm-lsm-client",
+ "msm-pcm-routing", "msm-compr-dsp",
+ "msm-pcm-dsp-noirq";
+ asoc-cpu = <&dai_mi2s0>, <&dai_mi2s1>,
+ <&dai_mi2s2>, <&dai_mi2s3>,
+ <&dai_int_mi2s0>, <&dai_int_mi2s1>,
+ <&dai_int_mi2s2>, <&dai_int_mi2s3>,
+ <&dai_int_mi2s4>, <&dai_int_mi2s5>,
+ <&dai_pri_auxpcm>, <&dai_sec_auxpcm>,
+ <&dai_tert_auxpcm>, <&dai_quat_auxpcm>,
+ <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>,
+ <&afe_proxy_tx>, <&incall_record_rx>,
+ <&incall_record_tx>, <&incall_music_rx>,
+ <&incall_music_2_rx>, <&sb_7_rx>, <&sb_7_tx>,
+ <&sb_8_tx>, <&sb_8_rx>,
+ <&usb_audio_rx>, <&usb_audio_tx>,
+ <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>,
+ <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>,
+ <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>,
+ <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>;
+ asoc-cpu-names = "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1",
+ "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
+ "msm-dai-q6-mi2s.7", "msm-dai-q6-mi2s.8",
+ "msm-dai-q6-mi2s.9", "msm-dai-q6-mi2s.10",
+ "msm-dai-q6-mi2s.11", "msm-dai-q6-mi2s.12",
+ "msm-dai-q6-auxpcm.1", "msm-dai-q6-auxpcm.2",
+ "msm-dai-q6-auxpcm.3", "msm-dai-q6-auxpcm.4",
+ "msm-dai-q6-dev.224", "msm-dai-q6-dev.225",
+ "msm-dai-q6-dev.241", "msm-dai-q6-dev.240",
+ "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772",
+ "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770",
+ "msm-dai-q6-dev.16398", "msm-dai-q6-dev.16399",
+ "msm-dai-q6-dev.16401", "msm-dai-q6-dev.16400",
+ "msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673",
+ "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36865",
+ "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881",
+ "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36897",
+ "msm-dai-q6-tdm.36912", "msm-dai-q6-tdm.36913";
+ asoc-codec = <&stub_codec>, <&msm_digital_codec>,
+ <&pmic_analog_codec>, <&msm_sdw_codec>;
+ asoc-codec-names = "msm-stub-codec.1", "msm-dig-codec",
+ "analog-codec", "msm_sdw_codec";
+
+ qcom,wsa-max-devs = <2>;
+ qcom,wsa-devs = <&wsa881x_211_en>, <&wsa881x_212_en>,
+ <&wsa881x_213_en>, <&wsa881x_214_en>;
+ qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight",
+ "SpkrLeft", "SpkrRight";
+ };
+
+ cdc_pdm_gpios: cdc_pdm_pinctrl {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&cdc_pdm_clk_active &cdc_pdm_sync_active
+ &cdc_pdm_rx0_active &cdc_pdm_rx1_2_active
+ &cdc_pdm_2_gpios_active>;
+ pinctrl-1 = <&cdc_pdm_clk_sleep &cdc_pdm_sync_sleep
+ &cdc_pdm_rx0_sleep &cdc_pdm_rx1_2_sleep
+ &cdc_pdm_2_gpios_sleep>;
+ qcom,lpi-gpios;
+ };
+
+ cdc_comp_gpios: cdc_comp_pinctrl {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&cdc_rx0_comp_active &cdc_rx1_comp_active>;
+ pinctrl-1 = <&cdc_rx0_comp_sleep &cdc_rx1_comp_sleep>;
+ qcom,lpi-gpios;
+ };
+
+ cdc_dmic_gpios: cdc_dmic_pinctrl {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&cdc_dmic12_gpios_active
+ &cdc_dmic34_gpios_active>;
+ pinctrl-1 = <&cdc_dmic12_gpios_sleep
+ &cdc_dmic34_gpios_sleep>;
+ qcom,lpi-gpios;
+ };
+
+ cdc_sdw_gpios: sdw_clk_data_pinctrl {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&sdw_clk_active &sdw_data_active>;
+ pinctrl-1 = <&sdw_clk_sleep &sdw_data_sleep>;
+ };
+
+ wsa_spkr_en1: wsa_spkr_en1_pinctrl {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&spkr_1_sd_n_active>;
+ pinctrl-1 = <&spkr_1_sd_n_sleep>;
+ };
+
+ wsa_spkr_en2: wsa_spkr_en2_pinctrl {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&spkr_2_sd_n_active>;
+ pinctrl-1 = <&spkr_2_sd_n_sleep>;
+ };
+
+ msm_sdw_codec: msm-sdw-codec@62ec1000 {
+ status = "okay";
+ compatible = "qcom,msm-sdw-codec";
+ reg = <0x62ec1000 0x0>;
+ interrupts = <0 161 0>;
+ interrupt-names = "swr_master_irq";
+ qcom,cdc-sdw-gpios = <&cdc_sdw_gpios>;
+
+ swr_master {
+ compatible = "qcom,swr-wcd";
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ wsa881x_211_en: wsa881x_en@20170211 {
+ compatible = "qcom,wsa881x";
+ reg = <0x0 0x20170211>;
+ qcom,spkr-sd-n-node = <&wsa_spkr_en1>;
+ };
+
+ wsa881x_212_en: wsa881x_en@20170212 {
+ compatible = "qcom,wsa881x";
+ reg = <0x0 0x20170212>;
+ qcom,spkr-sd-n-node = <&wsa_spkr_en2>;
+ };
+
+ wsa881x_213_en: wsa881x_en@21170213 {
+ compatible = "qcom,wsa881x";
+ reg = <0x0 0x21170213>;
+ qcom,spkr-sd-n-node = <&wsa_spkr_en1>;
+ };
+
+ wsa881x_214_en: wsa881x_en@21170214 {
+ compatible = "qcom,wsa881x";
+ reg = <0x0 0x21170214>;
+ qcom,spkr-sd-n-node = <&wsa_spkr_en2>;
+ };
+ };
+ };
+
+ wcd9xxx_intc: wcd9xxx-irq {
+ status = "disabled";
+ compatible = "qcom,wcd9xxx-irq";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&tlmm>;
+ qcom,gpio-connect = <&tlmm 80 0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&wcd_intr_default>;
+ };
+
+ clock_audio_lnbb: audio_ext_clk_lnbb {
+ status = "disabled";
+ compatible = "qcom,audio-ref-clk";
+ clock-names = "osr_clk";
+ clocks = <&clock_rpmh RPMH_LN_BB_CLK2>;
+ qcom,node_has_rpm_clock;
+ #clock-cells = <1>;
+ };
+
+ wcd_rst_gpio: msm_cdc_pinctrl@64 {
+ status = "disabled";
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&lpi_cdc_reset_active>;
+ pinctrl-1 = <&lpi_cdc_reset_sleep>;
+ qcom,lpi-gpios;
+ };
+
+ cpe: qcom,msm-cpe-lsm {
+ compatible = "qcom,msm-cpe-lsm";
+ };
+
+ cpe3: qcom,msm-cpe-lsm@3 {
+ compatible = "qcom,msm-cpe-lsm";
+ qcom,msm-cpe-lsm-id = <3>;
+ };
+
+ wdsp_mgr: qcom,wcd-dsp-mgr {
+ compatible = "qcom,wcd-dsp-mgr";
+ qcom,wdsp-components = <&wcd934x_cdc 0>,
+ <&wcd_spi_0 1>,
+ <&glink_spi_xprt_wdsp 2>;
+ qcom,img-filename = "cpe_9340";
+ };
+
+ wdsp_glink: qcom,wcd-dsp-glink {
+ compatible = "qcom,wcd-dsp-glink";
+ };
+};
+
+&slim_aud {
+ status = "disabled";
+ dai_slim: msm_dai_slim {
+ status = "disabled";
+ compatible = "qcom,msm-dai-slim";
+ elemental-addr = [ff ff ff fe 17 02];
+ };
+
+ wcd934x_cdc: tavil_codec {
+ status = "disabled";
+ compatible = "qcom,tavil-slim-pgd";
+ elemental-addr = [00 01 50 02 17 02];
+
+ interrupt-parent = <&wcd9xxx_intc>;
+ interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+ 17 18 19 20 21 22 23 24 25 26 27 28 29
+ 30 31>;
+
+ qcom,wcd-rst-gpio-node = <&wcd_rst_gpio>;
+
+ clock-names = "wcd_clk";
+ clocks = <&clock_audio_lnbb AUDIO_PMIC_LNBB_CLK>;
+
+ cdc-vdd-mic-bias-supply = <&pm660l_bob>;
+ qcom,cdc-vdd-mic-bias-voltage = <3300000 3300000>;
+ qcom,cdc-vdd-mic-bias-current = <30400>;
+
+ qcom,cdc-static-supplies = "cdc-vdd-mic-bias";
+
+ qcom,cdc-micbias1-mv = <1800>;
+ qcom,cdc-micbias2-mv = <1800>;
+ qcom,cdc-micbias3-mv = <1800>;
+ qcom,cdc-micbias4-mv = <1800>;
+
+ qcom,cdc-mclk-clk-rate = <9600000>;
+ qcom,cdc-slim-ifd = "tavil-slim-ifd";
+ qcom,cdc-slim-ifd-elemental-addr = [00 00 50 02 17 02];
+ qcom,cdc-dmic-sample-rate = <4800000>;
+ qcom,cdc-mad-dmic-rate = <600000>;
+
+ qcom,wdsp-cmpnt-dev-name = "tavil_codec";
+
+ wcd_spi_0: wcd_spi {
+ compatible = "qcom,wcd-spi-v2";
+ qcom,master-bus-num = <8>;
+ qcom,chip-select = <0>;
+ qcom,max-frequency = <24000000>;
+ qcom,mem-base-addr = <0x100000>;
+ };
+
+ wcd_usbc_analog_en1_gpio: msm_cdc_pinctrl_usbc_audio_en1 {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&wcd_usbc_analog_en1_active>;
+ pinctrl-1 = <&wcd_usbc_analog_en1_idle>;
+ };
+ };
+};
+
+&msm_dai_mi2s {
+ dai_int_mi2s0: qcom,msm-dai-q6-int-mi2s0 {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <7>;
+ qcom,msm-mi2s-rx-lines = <3>;
+ qcom,msm-mi2s-tx-lines = <0>;
+ };
+
+ dai_int_mi2s1: qcom,msm-dai-q6-int-mi2s1 {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <8>;
+ qcom,msm-mi2s-rx-lines = <3>;
+ qcom,msm-mi2s-tx-lines = <0>;
+ };
+
+ dai_int_mi2s2: qcom,msm-dai-q6-int-mi2s2 {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <9>;
+ qcom,msm-mi2s-rx-lines = <0>;
+ qcom,msm-mi2s-tx-lines = <3>;
+ };
+
+ dai_int_mi2s3: qcom,msm-dai-q6-int-mi2s3 {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <10>;
+ qcom,msm-mi2s-rx-lines = <0>;
+ qcom,msm-mi2s-tx-lines = <3>;
+ };
+
+ dai_int_mi2s4: qcom,msm-dai-q6-int-mi2s4 {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <11>;
+ qcom,msm-mi2s-rx-lines = <3>;
+ qcom,msm-mi2s-tx-lines = <0>;
+ };
+
+ dai_int_mi2s5: qcom,msm-dai-q6-int-mi2s5 {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <12>;
+ qcom,msm-mi2s-rx-lines = <0>;
+ qcom,msm-mi2s-tx-lines = <3>;
+ };
+
+ dai_int_mi2s6: qcom,msm-dai-q6-int-mi2s6 {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <13>;
+ qcom,msm-mi2s-rx-lines = <0>;
+ qcom,msm-mi2s-tx-lines = <3>;
+ };
+};
+
+&pm660l_3 {
+ pmic_analog_codec: analog-codec@f000 {
+ status = "okay";
+ compatible = "qcom,pmic-analog-codec";
+ reg = <0xf000 0x200>;
+ #address-cells = <2>;
+ #size-cells = <0>;
+ interrupt-parent = <&spmi_bus>;
+ interrupts = <0x3 0xf0 0x0 IRQ_TYPE_NONE>,
+ <0x3 0xf0 0x1 IRQ_TYPE_NONE>,
+ <0x3 0xf0 0x2 IRQ_TYPE_NONE>,
+ <0x3 0xf0 0x3 IRQ_TYPE_NONE>,
+ <0x3 0xf0 0x4 IRQ_TYPE_NONE>,
+ <0x3 0xf0 0x5 IRQ_TYPE_NONE>,
+ <0x3 0xf0 0x6 IRQ_TYPE_NONE>,
+ <0x3 0xf0 0x7 IRQ_TYPE_NONE>,
+ <0x3 0xf1 0x0 IRQ_TYPE_NONE>,
+ <0x3 0xf1 0x1 IRQ_TYPE_NONE>,
+ <0x3 0xf1 0x2 IRQ_TYPE_NONE>,
+ <0x3 0xf1 0x3 IRQ_TYPE_NONE>,
+ <0x3 0xf1 0x4 IRQ_TYPE_NONE>,
+ <0x3 0xf1 0x5 IRQ_TYPE_NONE>;
+ interrupt-names = "spk_cnp_int",
+ "spk_clip_int",
+ "spk_ocp_int",
+ "ins_rem_det1",
+ "but_rel_det",
+ "but_press_det",
+ "ins_rem_det",
+ "mbhc_int",
+ "ear_ocp_int",
+ "hphr_ocp_int",
+ "hphl_ocp_det",
+ "ear_cnp_int",
+ "hphr_cnp_int",
+ "hphl_cnp_int";
+
+
+ cdc-vdda-cp-supply = <&pm660_s4>;
+ qcom,cdc-vdda-cp-voltage = <1900000 2050000>;
+ qcom,cdc-vdda-cp-current = <50000>;
+
+ cdc-vdd-pa-supply = <&pm660_s4>;
+ qcom,cdc-vdd-pa-voltage = <2040000 2040000>;
+ qcom,cdc-vdd-pa-current = <260000>;
+
+ cdc-vdd-mic-bias-supply = <&pm660l_l7>;
+ qcom,cdc-vdd-mic-bias-voltage = <3088000 3088000>;
+ qcom,cdc-vdd-mic-bias-current = <5000>;
+
+ qcom,cdc-mclk-clk-rate = <9600000>;
+
+ qcom,cdc-static-supplies = "cdc-vdda-cp",
+ "cdc-vdd-pa";
+
+ qcom,cdc-on-demand-supplies = "cdc-vdd-mic-bias";
+
+ /*
+ * Not marking address @ as driver searches this child
+ * with name msm-dig-codec
+ */
+ msm_digital_codec: msm-dig-codec {
+ compatible = "qcom,msm-digital-codec";
+ reg = <0x62ec0000 0x0>;
+ };
+ };
+};
+
+&pm660_gpios {
+ gpio@c200 {
+ status = "ok";
+ qcom,mode = <1>;
+ qcom,pull = <4>;
+ qcom,vin-sel = <0>;
+ qcom,src-sel = <2>;
+ qcom,master-en = <1>;
+ qcom,out-strength = <2>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-lpi.dtsi b/arch/arm64/boot/dts/qcom/sdm670-lpi.dtsi
new file mode 100644
index 0000000..6e92f0e
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-lpi.dtsi
@@ -0,0 +1,284 @@
+/* Copyright (c) 2017, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+&soc {
+ lpi_tlmm: lpi_pinctrl@62b40000 {
+ compatible = "qcom,lpi-pinctrl";
+ reg = <0x62b40000 0x0>;
+ qcom,num-gpios = <32>;
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ cdc_pdm_clk_active: cdc_pdm_clk_active {
+ mux {
+ pins = "gpio18";
+ function = "func2";
+ };
+
+ config {
+ pins = "gpio18";
+ drive-strength = <8>;
+ output-high;
+ };
+ };
+
+ cdc_pdm_clk_sleep: cdc_pdm_clk_sleep {
+ mux {
+ pins = "gpio18";
+ function = "func2";
+ };
+
+ config {
+ pins = "gpio18";
+ drive-strength = <2>;
+ bias-disable;
+ output-low;
+ };
+ };
+
+ cdc_pdm_sync_active: cdc_pdm_sync_active {
+ mux {
+ pins = "gpio19";
+ function = "func3";
+ };
+
+ config {
+ pins = "gpio19";
+ drive-strength = <8>;
+ output-high;
+ };
+ };
+
+ cdc_pdm_sync_sleep: cdc_pdm_sync_sleep {
+ mux {
+ pins = "gpio19";
+ function = "func3";
+ };
+
+ config {
+ pins = "gpio19";
+ drive-strength = <2>;
+ bias-disable;
+ output-low;
+ };
+ };
+
+ cdc_pdm_rx0_active: cdc_pdm_rx0_active {
+ mux {
+ pins = "gpio21";
+ function = "func2";
+ };
+
+ config {
+ pins = "gpio21";
+ drive-strength = <8>;
+ output-high;
+ };
+ };
+
+ cdc_pdm_rx0_sleep: cdc_pdm_rx0_sleep {
+ mux {
+ pins = "gpio21";
+ function = "func2";
+ };
+
+ config {
+ pins = "gpio21";
+ drive-strength = <2>;
+ bias-disable;
+ output-low;
+ };
+ };
+
+ cdc_pdm_rx1_2_active: cdc_pdm_rx1_2_active {
+ mux {
+ pins = "gpio23", "gpio25";
+ function = "func1";
+ };
+
+ config {
+ pins = "gpio23", "gpio25";
+ drive-strength = <8>;
+ output-high;
+ };
+ };
+
+ cdc_pdm_rx1_2_sleep: cdc_pdm_rx1_2_sleep {
+ mux {
+ pins = "gpio23", "gpio25";
+ function = "func1";
+ };
+
+ config {
+ pins = "gpio23", "gpio25";
+ drive-strength = <2>;
+ bias-disable;
+ output-low;
+ };
+ };
+
+ cdc_pdm_2_gpios_active: cdc_pdm_2_gpios_active {
+ mux {
+ pins = "gpio20";
+ function = "func2";
+ };
+
+ config {
+ pins = "gpio20";
+ drive-strength = <8>;
+ };
+ };
+
+ cdc_pdm_2_gpios_sleep: cdc_pdm_2_gpios_sleep {
+ mux {
+ pins = "gpio20";
+ function = "func2";
+ };
+
+ config {
+ pins = "gpio20";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ cdc_rx0_comp_active: cdc_pdm_rx0_comp_active {
+ mux {
+ pins = "gpio22";
+ function = "func2";
+ };
+
+ config {
+ pins = "gpio22";
+ drive-strength = <8>;
+ };
+ };
+
+ cdc_rx0_comp_sleep: cdc_pdm_rx0_comp_sleep {
+ mux {
+ pins = "gpio22";
+ function = "func2";
+ };
+
+ config {
+ pins = "gpio22";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ cdc_rx1_comp_active: cdc_pdm_rx1_comp_active {
+ mux {
+ pins = "gpio24";
+ function = "func1";
+ };
+
+ config {
+ pins = "gpio24";
+ drive-strength = <8>;
+ };
+ };
+
+ cdc_rx1_comp_sleep: cdc_pdm_rx1_comp_sleep {
+ mux {
+ pins = "gpio24";
+ function = "func1";
+ };
+
+ config {
+ pins = "gpio24";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ lpi_cdc_reset_active: lpi_cdc_reset_active {
+ mux {
+ pins = "gpio29";
+ function = "func2";
+ };
+ config {
+ pins = "gpio29";
+ drive-strength = <16>;
+ output-high;
+ };
+ };
+
+ lpi_cdc_reset_sleep: lpi_cdc_reset_sleep {
+ mux {
+ pins = "gpio29";
+ function = "func2";
+ };
+
+ config {
+ pins = "gpio29";
+ drive-strength = <16>;
+ bias-disable;
+ output-low;
+ };
+ };
+
+ cdc_dmic12_gpios_active: dmic12_gpios_active {
+ mux {
+ pins = "gpio26", "gpio28";
+ function = "func1";
+ };
+
+ config {
+ pins = "gpio26", "gpio28";
+ drive-strength = <8>;
+ output-high;
+ };
+ };
+
+ cdc_dmic12_gpios_sleep: dmic12_gpios_sleep {
+ mux {
+ pins = "gpio26", "gpio28";
+ function = "func1";
+ };
+
+ config {
+ pins = "gpio26", "gpio28";
+ drive-strength = <2>;
+ bias-disable;
+ output-low;
+ };
+ };
+
+ cdc_dmic34_gpios_active: dmic34_gpios_active {
+ mux {
+ pins = "gpio27", "gpio29";
+ function = "func1";
+ };
+
+ config {
+ pins = "gpio27", "gpio29";
+ drive-strength = <8>;
+ input-enable;
+ };
+ };
+
+ cdc_dmic34_gpios_sleep: dmic34_gpios_sleep {
+ mux {
+ pins = "gpio27", "gpio29";
+ function = "func1";
+ };
+
+ config {
+ pins = "gpio27", "gpio29";
+ drive-strength = <2>;
+ pull-down;
+ input-enable;
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi
index dcc5d1b..73df253 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi
@@ -1146,5 +1146,296 @@
};
};
};
+ /* SDC pin type */
+ sdc1_clk_on: sdc1_clk_on {
+ config {
+ pins = "sdc1_clk";
+ bias-disable; /* NO pull */
+ drive-strength = <16>; /* 16 MA */
+ };
+ };
+
+ sdc1_clk_off: sdc1_clk_off {
+ config {
+ pins = "sdc1_clk";
+ bias-disable; /* NO pull */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+
+ sdc1_cmd_on: sdc1_cmd_on {
+ config {
+ pins = "sdc1_cmd";
+ bias-pull-up; /* pull up */
+ drive-strength = <10>; /* 10 MA */
+ };
+ };
+
+ sdc1_cmd_off: sdc1_cmd_off {
+ config {
+ pins = "sdc1_cmd";
+ num-grp-pins = <1>;
+ bias-pull-up; /* pull up */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+
+ sdc1_data_on: sdc1_data_on {
+ config {
+ pins = "sdc1_data";
+ bias-pull-up; /* pull up */
+ drive-strength = <10>; /* 10 MA */
+ };
+ };
+
+ sdc1_data_off: sdc1_data_off {
+ config {
+ pins = "sdc1_data";
+ bias-pull-up; /* pull up */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+
+ sdc2_clk_on: sdc2_clk_on {
+ config {
+ pins = "sdc2_clk";
+ bias-disable; /* NO pull */
+ drive-strength = <16>; /* 16 MA */
+ };
+ };
+
+ sdc2_clk_off: sdc2_clk_off {
+ config {
+ pins = "sdc2_clk";
+ bias-disable; /* NO pull */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+
+ sdc2_cmd_on: sdc2_cmd_on {
+ config {
+ pins = "sdc2_cmd";
+ bias-pull-up; /* pull up */
+ drive-strength = <10>; /* 10 MA */
+ };
+ };
+
+ sdc2_cmd_off: sdc2_cmd_off {
+ config {
+ pins = "sdc2_cmd";
+ bias-pull-up; /* pull up */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+
+ sdc2_data_on: sdc2_data_on {
+ config {
+ pins = "sdc2_data";
+ bias-pull-up; /* pull up */
+ drive-strength = <10>; /* 10 MA */
+ };
+ };
+
+ sdc2_data_off: sdc2_data_off {
+ config {
+ pins = "sdc2_data";
+ bias-pull-up; /* pull up */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+
+ /* USB C analog configuration */
+ wcd_usbc_analog_en1 {
+ wcd_usbc_analog_en1_idle: wcd_usbc_ana_en1_idle {
+ mux {
+ pins = "gpio49";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio49";
+ drive-strength = <2>;
+ bias-pull-down;
+ output-low;
+ };
+ };
+
+ wcd_usbc_analog_en1_active: wcd_usbc_ana_en1_active {
+ mux {
+ pins = "gpio49";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio49";
+ drive-strength = <2>;
+ bias-disable;
+ output-high;
+ };
+ };
+ };
+
+ sdw_clk_pin {
+ sdw_clk_sleep: sdw_clk_sleep {
+ mux {
+ pins = "gpio65";
+ function = "wsa_clk";
+ };
+
+ config {
+ pins = "gpio65";
+ drive-strength = <2>;
+ bias-bus-hold;
+ };
+ };
+
+ sdw_clk_active: sdw_clk_active {
+ mux {
+ pins = "gpio65";
+ function = "wsa_clk";
+ };
+
+ config {
+ pins = "gpio65";
+ drive-strength = <2>;
+ bias-bus-hold;
+ };
+ };
+ };
+
+ sdw_data_pin {
+ sdw_data_sleep: sdw_data_sleep {
+ mux {
+ pins = "gpio66";
+ function = "wsa_data";
+ };
+
+ config {
+ pins = "gpio66";
+ drive-strength = <4>;
+ bias-bus-hold;
+ };
+ };
+
+ sdw_data_active: sdw_data_active {
+ mux {
+ pins = "gpio66";
+ function = "wsa_data";
+ };
+
+ config {
+ pins = "gpio66";
+ drive-strength = <4>;
+ bias-bus-hold;
+ };
+ };
+ };
+
+ /* WSA speaker reset pins */
+ spkr_1_sd_n {
+ spkr_1_sd_n_sleep: spkr_1_sd_n_sleep {
+ mux {
+ pins = "gpio67";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio67";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down;
+ input-enable;
+ };
+ };
+
+ spkr_1_sd_n_active: spkr_1_sd_n_active {
+ mux {
+ pins = "gpio67";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio67";
+ drive-strength = <16>; /* 16 mA */
+ bias-disable;
+ output-high;
+ };
+ };
+ };
+
+ spkr_2_sd_n {
+ spkr_2_sd_n_sleep: spkr_2_sd_n_sleep {
+ mux {
+ pins = "gpio68";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio68";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down;
+ input-enable;
+ };
+ };
+
+ spkr_2_sd_n_active: spkr_2_sd_n_active {
+ mux {
+ pins = "gpio68";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio68";
+ drive-strength = <16>; /* 16 mA */
+ bias-disable;
+ output-high;
+ };
+ };
+ };
+
+ wcd_gnd_mic_swap {
+ wcd_gnd_mic_swap_idle: wcd_gnd_mic_swap_idle {
+ mux {
+ pins = "gpio40";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio40";
+ drive-strength = <2>;
+ bias-pull-down;
+ output-low;
+ };
+ };
+
+ wcd_gnd_mic_swap_active: wcd_gnd_mic_swap_active {
+ mux {
+ pins = "gpio40";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio40";
+ drive-strength = <2>;
+ bias-disable;
+ output-high;
+ };
+ };
+ };
+
+ wcd9xxx_intr {
+ wcd_intr_default: wcd_intr_default{
+ mux {
+ pins = "gpio80";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio80";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* pull down */
+ input-enable;
+ };
+ };
+ };
};
};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi
index b0c436f..0a8c49f 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi
@@ -15,331 +15,6 @@
/* Stub regulators */
/ {
- pm660_s4: regulator-pm660-s4 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660_s4";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <2040000>;
- regulator-max-microvolt = <2040000>;
- };
-
- /* pm660 S5 - VDD_MODEM supply */
- pm660_s5_level: regulator-pm660-s5 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660_s5_level";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
- regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
- };
-
- pm660_s6: regulator-pm660-s6 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660_s6";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <1352000>;
- regulator-max-microvolt = <1352000>;
- };
-
- /* pm660l S1 - VDD_MX supply */
- pm660l_s1_level: regulator-pm660l-s1 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660l_s1_level";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
- regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
- };
-
- pm660l_s1_floor_level: regulator-pm660l-s1-floor-level {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660l_s1_floor_level";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
- regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
- };
-
- pm660l_s1_level_ao: regulator-pm660l-s1-level-ao {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660l_s1_level_ao";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
- regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
- };
-
- /* pm660l S2 - VDD_GFX supply */
- pm660l_s2_level: regulator-pm660l-s2 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660l_s2_level";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
- regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
- };
-
- /* pm660l S3 + S4 - VDD_CX supply */
- pm660l_s3_level: regulator-pm660l-s3-level {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660l_s3_level";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
- regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
- };
-
- pm660l_s3_floor_level: regulator-pm660l-s3-floor-level {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660l_s3_floor_level";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
- regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
- };
-
- pm660l_s3_level_ao: regulator-pm660l-s3-level-ao {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660_s3_level_ao";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
- regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
- };
-
- pm660_l1: regulator-pm660-l1 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660_l1";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1250000>;
- };
-
- pm660_l2: regulator-pm660-l2 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660_l2";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
- };
-
- pm660_l3: regulator-pm660-l3 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660_l3";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
- };
-
- pm660_l5: regulator-pm660-l5 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660_l5";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <800000>;
- regulator-max-microvolt = <800000>;
- };
-
- pm660_l6: regulator-pm660-l6 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660_l6";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1304000>;
- regulator-max-microvolt = <1304000>;
- };
-
- pm660_l7: regulator-pm660-l7 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660_l7";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- };
-
- pm660_l8: regulator-pm660-l8 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660_l8";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- pm660_l9: regulator-pm660-l9 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660_l9";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- pm660_l10: regulator-pm660-l10 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660_l10";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- pm660_l11: regulator-pm660-l11 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660_l11";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- pm660_l12: regulator-pm660-l12 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660_l12";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- pm660_l13: regulator-pm660-l13 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660_l13";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- pm660_l14: regulator-pm660-l14 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660_l14";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- pm660_l15: regulator-pm660-l15 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660_l15";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <2950000>;
- };
-
- pm660_l16: regulator-pm660-l16 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660_l16";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <2700000>;
- regulator-max-microvolt = <2700000>;
- };
-
- pm660_l17: regulator-pm660-l17 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660_l17";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <2950000>;
- };
-
- pm660_l19: regulator-pm660-l19 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660_l19";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <3312000>;
- regulator-max-microvolt = <3312000>;
- };
-
- pm660l_l1: regulator-pm660l-l1 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660l_l1";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <880000>;
- regulator-max-microvolt = <900000>;
- };
-
- pm660l_l2: regulator-pm660l-l2 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660l_l2";
- qcom,hpm-min-load = <5000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <2960000>;
- };
-
- pm660l_l3: regulator-pm660l-l3 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660l_l3";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <2850000>;
- regulator-max-microvolt = <3008000>;
- };
-
- pm660l_l4: regulator-pm660l-l4 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660l_l4";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <2960000>;
- regulator-max-microvolt = <2960000>;
- };
-
- pm660l_l5: regulator-pm660l-l5 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660l_l5";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <2960000>;
- regulator-max-microvolt = <2960000>;
- };
-
- pm660l_l6: regulator-pm660l-l6 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660l_l6";
- qcom,hpm-min-load = <5000>;
- regulator-min-microvolt = <3008000>;
- regulator-max-microvolt = <3300000>;
- };
-
- pm660l_l7: regulator-pm660l-l7 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660l_l7";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <3088000>;
- regulator-max-microvolt = <3100000>;
- };
-
- pm660l_l8: regulator-pm660l-l8 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660l_l8";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3312000>;
- };
-
- /* pm660l L9 = VDD_LPI_CX supply */
- pm660l_l9_level: regulator-pm660l-l9-level {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660l_l9_level";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
- regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
- };
-
- pm660l_l9_floor_level: regulator-pm660l-l9-floor-level {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660l_l9_floor_level";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
- regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
- };
-
- /* pm660l L10 = VDD_LPI_MX supply */
- pm660l_l10_level: regulator-pm660l-l10-level {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660l_l10_level";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
- regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
- };
-
- pm660l_l10_floor_level: regulator-pm660l-l10-floor-level {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660l_l10_floor_level";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
- regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
- };
-
- pm660l_bob: regulator-pm660l-bob {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660l_bob";
- regulator-min-microvolt = <3312000>;
- regulator-max-microvolt = <3312000>;
- };
-
apc0_pwrcl_vreg: regulator-pwrcl {
compatible = "qcom,stub-regulator";
regulator-name = "apc0_pwrcl_corner";
@@ -362,6 +37,598 @@
};
};
+&soc {
+ /* RPMh regulators: */
+ rpmh-regulator-smpa4 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "smpa4";
+ pm660_s4: regulator-pm660-s4 {
+ regulator-name = "pm660_s4";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <2040000>;
+ regulator-max-microvolt = <2040000>;
+ qcom,init-voltage = <2040000>;
+ };
+ };
+
+ /* pm660 S5 - VDD_MODEM supply */
+ rpmh-regulator-modemlvl {
+ compatible = "qcom,rpmh-arc-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "mss.lvl";
+ pm660_s5_level: regulator-pm660-s5 {
+ regulator-name = "pm660_s5_level";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
+ regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
+ };
+ };
+
+ rpmh-regulator-smpa6 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "smpa6";
+ pm660_s6: regulator-pm660-s6 {
+ regulator-name = "pm660_s6";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1352000>;
+ regulator-max-microvolt = <1352000>;
+ qcom,init-voltage = <1352000>;
+ };
+ };
+
+ /* pm660l S1 - VDD_MX supply */
+ rpmh-regulator-mxlvl {
+ compatible = "qcom,rpmh-arc-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "mx.lvl";
+ pm660l_s1_level: regulator-pm660l-s1 {
+ regulator-name = "pm660l_s1_level";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
+ regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
+ };
+
+ pm660l_s1_level_ao: regulator-pm660l-s1-level-ao {
+ regulator-name = "pm660l_s1_level_ao";
+ qcom,set = <RPMH_REGULATOR_SET_ACTIVE>;
+ regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
+ regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
+ };
+ };
+
+ /* pm660l S2 - VDD_GFX supply */
+ rpmh-regulator-gfxlvl {
+ compatible = "qcom,rpmh-arc-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "gfx.lvl";
+ pm660l_s2_level: regulator-pm660l-s2 {
+ regulator-name = "pm660l_s2_level";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt
+ = <RPMH_REGULATOR_LEVEL_MIN_SVS>;
+ regulator-max-microvolt
+ = <RPMH_REGULATOR_LEVEL_MAX>;
+ qcom,init-voltage-level
+ = <RPMH_REGULATOR_LEVEL_MIN_SVS>;
+ };
+ };
+
+ /* pm660l S3 + S4 - VDD_CX supply */
+ rpmh-regulator-cxlvl {
+ compatible = "qcom,rpmh-arc-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "cx.lvl";
+ pm660l_s3_level-parent-supply = <&pm660l_s1_level>;
+ pm660l_s3_level_ao-parent-supply = <&pm660l_s1_level_ao>;
+ pm660l_s3_level: regulator-pm660l-s3-level {
+ regulator-name = "pm660l_s3_level";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
+ regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
+ qcom,min-dropout-voltage-level = <(-1)>;
+ };
+
+ pm660l_s3_level_ao: regulator-pm660l-s3-level-ao {
+ regulator-name = "pm660l_s3_level_ao";
+ qcom,set = <RPMH_REGULATOR_SET_ACTIVE>;
+ regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
+ regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
+ qcom,min-dropout-voltage-level = <(-1)>;
+ };
+ };
+
+ rpmh-regulator-ldoa1 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa1";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l1: regulator-pm660-l1 {
+ regulator-name = "pm660_l1";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1250000>;
+ qcom,init-voltage = <1200000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa2 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa2";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l2: regulator-pm660-l2 {
+ regulator-name = "pm660_l2";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ qcom,init-voltage = <1000000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa3 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa3";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l3: regulator-pm660-l3 {
+ regulator-name = "pm660_l3";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ qcom,init-voltage = <1000000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa5 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa5";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l5: regulator-pm660-l5 {
+ regulator-name = "pm660_l5";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <800000>;
+ qcom,init-voltage = <800000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa6 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa6";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l6: regulator-pm660-l6 {
+ regulator-name = "pm660_l6";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1304000>;
+ regulator-max-microvolt = <1304000>;
+ qcom,init-voltage = <1304000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa7 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa7";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l7: regulator-pm660-l7 {
+ regulator-name = "pm660_l7";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ qcom,init-voltage = <1200000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa8 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa8";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l8: regulator-pm660-l8 {
+ regulator-name = "pm660_l8";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa9 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa9";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l9: regulator-pm660-l9 {
+ regulator-name = "pm660_l9";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa10 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa10";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l10: regulator-pm660-l10 {
+ regulator-name = "pm660_l10";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa11 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa11";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l11: regulator-pm660-l11 {
+ regulator-name = "pm660_l11";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa12 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa12";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l12: regulator-pm660-l12 {
+ regulator-name = "pm660_l12";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa13 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa13";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l13: regulator-pm660-l13 {
+ regulator-name = "pm660_l13";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa14 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa14";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l14: regulator-pm660-l14 {
+ regulator-name = "pm660_l14";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa15 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa15";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l15: regulator-pm660-l15 {
+ regulator-name = "pm660_l15";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ qcom,init-voltage = <1800000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa16 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa16";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l16: regulator-pm660-l16 {
+ regulator-name = "pm660_l16";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <2700000>;
+ regulator-max-microvolt = <2700000>;
+ qcom,init-voltage = <2700000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa17 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa17";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l17: regulator-pm660-l17 {
+ regulator-name = "pm660_l17";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ qcom,init-voltage = <1800000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa19 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa19";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l19: regulator-pm660-l19 {
+ regulator-name = "pm660_l19";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <3312000>;
+ regulator-max-microvolt = <3312000>;
+ qcom,init-voltage = <3312000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldob1 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldob1";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660l_l1: regulator-pm660l-l1 {
+ regulator-name = "pm660l_l1";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <880000>;
+ regulator-max-microvolt = <900000>;
+ qcom,init-voltage = <880000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldob2 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldob2";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660l_l2: regulator-pm660l-l2 {
+ regulator-name = "pm660l_l2";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2960000>;
+ qcom,init-voltage = <1800000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldob3 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldob3";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660l_l3: regulator-pm660l-l3 {
+ regulator-name = "pm660l_l3";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <3008000>;
+ qcom,init-voltage = <2850000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldob4 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldob4";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660l_l4: regulator-pm660l-l4 {
+ regulator-name = "pm660l_l4";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <2960000>;
+ regulator-max-microvolt = <2960000>;
+ qcom,init-voltage = <2960000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldob5 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldob5";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660l_l5: regulator-pm660l-l5 {
+ regulator-name = "pm660l_l5";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <2960000>;
+ regulator-max-microvolt = <2960000>;
+ qcom,init-voltage = <2960000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldob6 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldob6";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660l_l6: regulator-pm660l-l6 {
+ regulator-name = "pm660l_l6";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <3008000>;
+ regulator-max-microvolt = <3300000>;
+ qcom,init-voltage = <3008000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldob7 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldob7";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660l_l7: regulator-pm660l-l7 {
+ regulator-name = "pm660l_l7";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <3088000>;
+ regulator-max-microvolt = <3100000>;
+ qcom,init-voltage = <3088000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldob8 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldob8";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660l_l8: regulator-pm660l-l8 {
+ regulator-name = "pm660l_l8";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3312000>;
+ qcom,init-voltage = <3300000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ /* pm660l L9 = VDD_LPI_CX supply */
+ rpmh-regulator-lcxlvl {
+ compatible = "qcom,rpmh-arc-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "lcx.lvl";
+ pm660l_l9_level: regulator-pm660l-l9-level {
+ regulator-name = "pm660l_l9_level";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
+ regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
+ };
+ };
+
+ /* pm660l L10 = VDD_LPI_MX supply */
+ rpmh-regulator-lmxlvl {
+ compatible = "qcom,rpmh-arc-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "lmx.lvl";
+ pm660l_l10_level: regulator-pm660l-l10-level {
+ regulator-name = "pm660l_l10_level";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
+ regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
+ };
+ };
+
+ rpmh-regulator-bobb1 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "bobb1";
+ pm660l_bob: regulator-pm660l-bob {
+ regulator-name = "pm660l_bob";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <3312000>;
+ regulator-max-microvolt = <3312000>;
+ qcom,init-voltage = <3312000>;
+ };
+ };
+};
+
&pm660_charger {
smb2_vbus: qcom,smb2-vbus {
regulator-name = "smb2-vbus";
diff --git a/arch/arm64/boot/dts/qcom/sdm670-rumi.dtsi b/arch/arm64/boot/dts/qcom/sdm670-rumi.dtsi
index 17b90c7..f2f41fd 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-rumi.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-rumi.dtsi
@@ -77,3 +77,24 @@
spm-level = <0>;
status = "ok";
};
+
+&sdhc_1 {
+ vdd-supply = <&pm660l_l4>;
+ qcom,vdd-voltage-level = <2960000 2960000>;
+ qcom,vdd-current-level = <200 570000>;
+
+ vdd-io-supply = <&pm660_l8>;
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-lpm-sup;
+ qcom,vdd-io-voltage-level = <1800000 1800000>;
+ qcom,vdd-io-current-level = <200 325000>;
+
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on>;
+ pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off>;
+
+ qcom,clk-rates = <400000 20000000 25000000 50000000>;
+ qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+
+ status = "ok";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-smp2p.dtsi b/arch/arm64/boot/dts/qcom/sdm670-smp2p.dtsi
index 6dd1b749..f3e5ddb 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-smp2p.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-smp2p.dtsi
@@ -25,8 +25,8 @@
compatible = "qcom,smp2p";
reg = <0x1799000c 0x4>;
qcom,remote-pid = <2>;
- qcom,irq-bitmask = <0x200>;
- interrupts = <GIC_SPI 157 IRQ_TYPE_EDGE_RISING>;
+ qcom,irq-bitmask = <0x4000000>;
+ interrupts = <GIC_SPI 172 IRQ_TYPE_EDGE_RISING>;
};
qcom,smp2p-cdsp@1799000c {
@@ -245,4 +245,27 @@
interrupt-controller;
#interrupt-cells = <2>;
};
+
+ /* ssr - inbound entry from cdsp */
+ smp2pgpio_ssr_smp2p_5_in: qcom,smp2pgpio-ssr-smp2p-5-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "slave-kernel";
+ qcom,remote-pid = <5>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ /* ssr - outbound entry to cdsp */
+ smp2pgpio_ssr_smp2p_5_out: qcom,smp2pgpio-ssr-smp2p-5-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "master-kernel";
+ qcom,remote-pid = <5>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-wcd.dtsi b/arch/arm64/boot/dts/qcom/sdm670-wcd.dtsi
new file mode 100644
index 0000000..f8d2a04
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-wcd.dtsi
@@ -0,0 +1,167 @@
+/* Copyright (c) 2017, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+&slim_aud {
+ tavil_codec {
+ wcd: wcd_pinctrl@5 {
+ compatible = "qcom,wcd-pinctrl";
+ qcom,num-gpios = <5>;
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ us_euro_sw_wcd_active: us_euro_sw_wcd_active {
+ mux {
+ pins = "gpio1";
+ };
+
+ config {
+ pins = "gpio1";
+ output-high;
+ };
+ };
+
+ us_euro_sw_wcd_sleep: us_euro_sw_wcd_sleep {
+ mux {
+ pins = "gpio1";
+ };
+
+ config {
+ pins = "gpio1";
+ output-low;
+ };
+ };
+
+ spkr_1_wcd_en_active: spkr_1_wcd_en_active {
+ mux {
+ pins = "gpio2";
+ };
+
+ config {
+ pins = "gpio2";
+ output-high;
+ };
+ };
+
+ spkr_1_wcd_en_sleep: spkr_1_wcd_en_sleep {
+ mux {
+ pins = "gpio2";
+ };
+
+ config {
+ pins = "gpio2";
+ input-enable;
+ };
+ };
+
+ spkr_2_wcd_en_active: spkr_2_sd_n_active {
+ mux {
+ pins = "gpio3";
+ };
+
+ config {
+ pins = "gpio3";
+ output-high;
+ };
+ };
+
+ spkr_2_wcd_en_sleep: spkr_2_sd_n_sleep {
+ mux {
+ pins = "gpio3";
+ };
+
+ config {
+ pins = "gpio3";
+ input-enable;
+ };
+ };
+
+ hph_en0_wcd_active: hph_en0_wcd_active {
+ mux {
+ pins = "gpio4";
+ };
+
+ config {
+ pins = "gpio4";
+ output-high;
+ };
+ };
+
+ hph_en0_wcd_sleep: hph_en0_wcd_sleep {
+ mux {
+ pins = "gpio4";
+ };
+
+ config {
+ pins = "gpio4";
+ output-low;
+ };
+ };
+
+ hph_en1_wcd_active: hph_en1_wcd_active {
+ mux {
+ pins = "gpio5";
+ };
+
+ config {
+ pins = "gpio5";
+ output-high;
+ };
+ };
+
+ hph_en1_wcd_sleep: hph_en1_wcd_sleep {
+ mux {
+ pins = "gpio5";
+ };
+
+ config {
+ pins = "gpio5";
+ output-low;
+ };
+ };
+ };
+
+ wsa_spkr_wcd_sd1: msm_cdc_pinctrll {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&spkr_1_wcd_en_active>;
+ pinctrl-1 = <&spkr_1_wcd_en_sleep>;
+ };
+
+ wsa_spkr_wcd_sd2: msm_cdc_pinctrlr {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&spkr_2_wcd_en_active>;
+ pinctrl-1 = <&spkr_2_wcd_en_sleep>;
+ };
+
+ tavil_us_euro_sw: msm_cdc_pinctrl_us_euro_sw {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&us_euro_sw_wcd_active>;
+ pinctrl-1 = <&us_euro_sw_wcd_sleep>;
+ };
+
+ tavil_hph_en0: msm_cdc_pinctrl_hph_en0 {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&hph_en0_wcd_active>;
+ pinctrl-1 = <&hph_en0_wcd_sleep>;
+ };
+
+ tavil_hph_en1: msm_cdc_pinctrl_hph_en1 {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&hph_en1_wcd_active>;
+ pinctrl-1 = <&hph_en1_wcd_sleep>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-wsa881x.dtsi b/arch/arm64/boot/dts/qcom/sdm670-wsa881x.dtsi
new file mode 100644
index 0000000..c35850d
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-wsa881x.dtsi
@@ -0,0 +1,45 @@
+/* Copyright (c) 2017, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+&slim_aud {
+ tavil_codec {
+ swr_master {
+ compatible = "qcom,swr-wcd";
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ wsa881x_0211: wsa881x@20170211 {
+ compatible = "qcom,wsa881x";
+ reg = <0x0 0x20170211>;
+ qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd1>;
+ };
+
+ wsa881x_0212: wsa881x@20170212 {
+ compatible = "qcom,wsa881x";
+ reg = <0x0 0x20170212>;
+ qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd2>;
+ };
+
+ wsa881x_0213: wsa881x@21170213 {
+ compatible = "qcom,wsa881x";
+ reg = <0x0 0x21170213>;
+ qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd1>;
+ };
+
+ wsa881x_0214: wsa881x@21170214 {
+ compatible = "qcom,wsa881x";
+ reg = <0x0 0x21170214>;
+ qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd2>;
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi
index 21c40fc..0dec428 100644
--- a/arch/arm64/boot/dts/qcom/sdm670.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi
@@ -30,6 +30,7 @@
aliases {
ufshc1 = &ufshc_mem; /* Embedded UFS slot */
+ sdhc1 = &sdhc_1; /* SDC1 eMMC slot */
};
aliases {
@@ -825,6 +826,12 @@
reg-names = "pshold-base", "tcsr-boot-misc-detect";
};
+ aop-msg-client {
+ compatible = "qcom,debugfs-qmp-client";
+ mboxes = <&qmp_aop 0>;
+ mbox-names = "aop";
+ };
+
clock_rpmh: qcom,rpmhclk {
compatible = "qcom,dummycc";
clock-output-names = "rpmh_clocks";
@@ -1086,7 +1093,7 @@
qcom,mpu-enabled;
};
- qmp_aop: mailbox@1799000c {
+ qmp_aop: qcom,qmp-aop@c300000 {
compatible = "qcom,qmp-mbox";
label = "aop";
reg = <0xc300000 0x100000>,
@@ -1094,6 +1101,7 @@
reg-names = "msgram", "irq-reg-base";
qcom,irq-mask = <0x1>;
interrupts = <0 389 1>;
+ priority = <0>;
mbox-desc-offset = <0x0>;
#mbox-cells = <1>;
};
@@ -1113,8 +1121,8 @@
reg = <0x86000000 0x200000>,
<0x1799000c 0x4>;
reg-names = "smem", "irq-reg-base";
- qcom,irq-mask = <0x100>;
- interrupts = <GIC_SPI 156 IRQ_TYPE_EDGE_RISING>;
+ qcom,irq-mask = <0x1000000>;
+ interrupts = <GIC_SPI 170 IRQ_TYPE_EDGE_RISING>;
label = "lpass";
qcom,qos-config = <&glink_qos_adsp>;
qcom,ramp-time = <0xaf>;
@@ -1368,6 +1376,19 @@
<CONTROL_TCS 1>;
};
+ disp_rsc: mailbox@af20000 {
+ compatible = "qcom,tcs-drv";
+ label = "display_rsc";
+ reg = <0xaf20000 0x100>, <0xaf21c00 0x3000>;
+ interrupts = <0 129 0>;
+ #mbox-cells = <1>;
+ qcom,drv-id = <0>;
+ qcom,tcs-config = <SLEEP_TCS 1>,
+ <WAKE_TCS 1>,
+ <ACTIVE_TCS 0>,
+ <CONTROL_TCS 1>;
+ };
+
system_pm {
compatible = "qcom,system-pm";
mboxes = <&apps_rsc 0>;
@@ -1715,6 +1736,168 @@
memory-region = <&pil_mba_mem>;
};
};
+
+ qcom,venus@aae0000 {
+ compatible = "qcom,pil-tz-generic";
+ reg = <0xaae0000 0x4000>;
+
+ vdd-supply = <&venus_gdsc>;
+ qcom,proxy-reg-names = "vdd";
+
+ clocks = <&clock_videocc VIDEO_CC_VENUS_CTL_CORE_CLK>,
+ <&clock_videocc VIDEO_CC_VENUS_AHB_CLK>,
+ <&clock_videocc VIDEO_CC_VENUS_CTL_AXI_CLK>;
+ clock-names = "core_clk", "iface_clk", "bus_clk";
+ qcom,proxy-clock-names = "core_clk", "iface_clk", "bus_clk";
+
+ qcom,pas-id = <9>;
+ qcom,msm-bus,name = "pil-venus";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <63 512 0 0>,
+ <63 512 0 304000>;
+ qcom,proxy-timeout-ms = <100>;
+ qcom,firmware-name = "venus";
+ memory-region = <&pil_video_mem>;
+ status = "ok";
+ };
+
+ qcom,turing@8300000 {
+ compatible = "qcom,pil-tz-generic";
+ reg = <0x8300000 0x100000>;
+ interrupts = <0 578 1>;
+
+ vdd_cx-supply = <&pm660l_s3_level>;
+ qcom,proxy-reg-names = "vdd_cx";
+ qcom,vdd_cx-uV-uA = <RPMH_REGULATOR_LEVEL_TURBO 100000>;
+
+ clocks = <&clock_rpmh RPMH_CXO_CLK>;
+ clock-names = "xo";
+ qcom,proxy-clock-names = "xo";
+
+ qcom,pas-id = <18>;
+ qcom,proxy-timeout-ms = <10000>;
+ qcom,smem-id = <601>;
+ qcom,sysmon-id = <7>;
+ qcom,ssctl-instance-id = <0x17>;
+ qcom,firmware-name = "cdsp";
+ memory-region = <&pil_cdsp_mem>;
+
+ /* GPIO inputs from turing */
+ qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_5_in 0 0>;
+ qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_5_in 2 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_5_in 1 0>;
+ qcom,gpio-stop-ack = <&smp2pgpio_ssr_smp2p_5_in 3 0>;
+
+ /* GPIO output to turing*/
+ qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_5_out 0 0>;
+ status = "ok";
+ };
+
+ sdhc_1: sdhci@7c4000 {
+ compatible = "qcom,sdhci-msm-v5";
+ reg = <0x7C4000 0x1000>, <0x7C5000 0x1000>;
+ reg-names = "hc_mem", "cmdq_mem";
+
+ interrupts = <0 641 0>, <0 644 0>;
+ interrupt-names = "hc_irq", "pwr_irq";
+
+ qcom,bus-width = <8>;
+ qcom,large-address-bus;
+
+ clocks = <&clock_gcc GCC_SDCC1_AHB_CLK>,
+ <&clock_gcc GCC_SDCC1_APPS_CLK>;
+ clock-names = "iface_clk", "core_clk";
+
+ qcom,nonremovable;
+
+ qcom,scaling-lower-bus-speed-mode = "DDR52";
+ status = "disabled";
+ };
+
+ qcom,msm-cdsp-loader {
+ compatible = "qcom,cdsp-loader";
+ qcom,proc-img-to-load = "cdsp";
+ };
+
+ qcom,msm-adsprpc-mem {
+ compatible = "qcom,msm-adsprpc-mem-region";
+ memory-region = <&adsp_mem>;
+ };
+
+ qcom,msm_fastrpc {
+ compatible = "qcom,msm-fastrpc-compute";
+
+ qcom,msm_fastrpc_compute_cb1 {
+ compatible = "qcom,msm-fastrpc-compute-cb";
+ label = "cdsprpc-smd";
+ iommus = <&apps_smmu 0x1421 0x30>;
+ dma-coherent;
+ };
+ qcom,msm_fastrpc_compute_cb2 {
+ compatible = "qcom,msm-fastrpc-compute-cb";
+ label = "cdsprpc-smd";
+ iommus = <&apps_smmu 0x1422 0x30>;
+ dma-coherent;
+ };
+ qcom,msm_fastrpc_compute_cb3 {
+ compatible = "qcom,msm-fastrpc-compute-cb";
+ label = "cdsprpc-smd";
+ iommus = <&apps_smmu 0x1423 0x30>;
+ dma-coherent;
+ };
+ qcom,msm_fastrpc_compute_cb4 {
+ compatible = "qcom,msm-fastrpc-compute-cb";
+ label = "cdsprpc-smd";
+ iommus = <&apps_smmu 0x1424 0x30>;
+ dma-coherent;
+ };
+ qcom,msm_fastrpc_compute_cb5 {
+ compatible = "qcom,msm-fastrpc-compute-cb";
+ label = "cdsprpc-smd";
+ iommus = <&apps_smmu 0x1425 0x30>;
+ dma-coherent;
+ };
+ qcom,msm_fastrpc_compute_cb6 {
+ compatible = "qcom,msm-fastrpc-compute-cb";
+ label = "cdsprpc-smd";
+ iommus = <&apps_smmu 0x1426 0x30>;
+ dma-coherent;
+ };
+ qcom,msm_fastrpc_compute_cb7 {
+ compatible = "qcom,msm-fastrpc-compute-cb";
+ label = "cdsprpc-smd";
+ qcom,secure-context-bank;
+ iommus = <&apps_smmu 0x1429 0x30>;
+ dma-coherent;
+ };
+ qcom,msm_fastrpc_compute_cb8 {
+ compatible = "qcom,msm-fastrpc-compute-cb";
+ label = "cdsprpc-smd";
+ qcom,secure-context-bank;
+ iommus = <&apps_smmu 0x142A 0x30>;
+ dma-coherent;
+ };
+ qcom,msm_fastrpc_compute_cb9 {
+ compatible = "qcom,msm-fastrpc-compute-cb";
+ label = "adsprpc-smd";
+ iommus = <&apps_smmu 0x1803 0x0>;
+ dma-coherent;
+ };
+ qcom,msm_fastrpc_compute_cb10 {
+ compatible = "qcom,msm-fastrpc-compute-cb";
+ label = "adsprpc-smd";
+ iommus = <&apps_smmu 0x1804 0x0>;
+ dma-coherent;
+ };
+ qcom,msm_fastrpc_compute_cb11 {
+ compatible = "qcom,msm-fastrpc-compute-cb";
+ label = "adsprpc-smd";
+ iommus = <&apps_smmu 0x1805 0x0>;
+ dma-coherent;
+ };
+ };
};
#include "sdm670-pinctrl.dtsi"
@@ -1742,6 +1925,18 @@
status = "ok";
};
+&hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc {
+ status = "ok";
+};
+
+&hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc {
+ status = "ok";
+};
+
+&hlos1_vote_mmnoc_mmu_tbu_sf_gdsc {
+ status = "ok";
+};
+
&bps_gdsc {
status = "ok";
};
@@ -1778,6 +1973,7 @@
clock-names = "core_root_clk";
clocks = <&clock_gfx GPU_CC_GX_GFX3D_CLK_SRC>;
qcom,force-enable-root-clk;
+ parent-supply = <&pm660l_s2_level>;
status = "ok";
};
@@ -1798,3 +1994,4 @@
#include "pm660.dtsi"
#include "pm660l.dtsi"
#include "sdm670-regulator.dtsi"
+#include "sdm670-audio.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-cdp-overlay.dts
index 0006937..a78672d 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-cdp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-cdp-overlay.dts
@@ -27,7 +27,7 @@
/ {
model = "Qualcomm Technologies, Inc. sdm845 4K Display Panel CDP";
compatible = "qcom,sdm845-cdp", "qcom,sdm845", "qcom,cdp";
- qcom,msm-id = <321 0x0>;
+ qcom,msm-id = <321 0x10000>;
qcom,board-id = <1 1>;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-mtp-overlay.dts
index 2675b96..a776d42 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-mtp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-mtp-overlay.dts
@@ -27,7 +27,7 @@
/ {
model = "Qualcomm Technologies, Inc. sdm845 4K Display Panel MTP";
compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp";
- qcom,msm-id = <321 0x0>;
+ qcom,msm-id = <321 0x10000>;
qcom,board-id = <8 1>;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd-overlay.dts
index 39c9d37..c6622d4 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd-overlay.dts
@@ -27,6 +27,38 @@
/ {
model = "Qualcomm Technologies, Inc. sdm845 4K Display Panel QRD";
compatible = "qcom,sdm845-qrd", "qcom,sdm845", "qcom,qrd";
- qcom,msm-id = <321 0x0>;
+ qcom,msm-id = <321 0x10000>;
qcom,board-id = <11 1>;
};
+
+&dsi_nt35597_truly_dsc_cmd_display {
+ /delete-property/ qcom,dsi-display-active;
+};
+
+&dsi_sharp_4k_dsc_video {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+ qcom,mdss-dsi-panel-orientation = "180";
+};
+
+&dsi_sharp_4k_dsc_cmd {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+ qcom,mdss-dsi-panel-orientation = "180";
+};
+
+&dsi_sharp_4k_dsc_video_display {
+ qcom,dsi-display-active;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd.dts b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd.dts
index 5951f6d..20f80c9 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd.dts
@@ -22,3 +22,35 @@
compatible = "qcom,sdm845-qrd", "qcom,sdm845", "qcom,qrd";
qcom,board-id = <11 1>;
};
+
+&dsi_nt35597_truly_dsc_cmd_display {
+ /delete-property/ qcom,dsi-display-active;
+};
+
+&dsi_sharp_4k_dsc_video {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+ qcom,mdss-dsi-panel-orientation = "180";
+};
+
+&dsi_sharp_4k_dsc_cmd {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+ qcom,mdss-dsi-panel-orientation = "180";
+};
+
+&dsi_sharp_4k_dsc_video_display {
+ qcom,dsi-display-active;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-cdp-overlay.dts
index efc78e0..7991aad 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-cdp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-cdp-overlay.dts
@@ -26,6 +26,6 @@
/ {
model = "Qualcomm Technologies, Inc. SDM845 v1 CDP";
compatible = "qcom,sdm845-cdp", "qcom,sdm845", "qcom,cdp";
- qcom,msm-id = <321 0x0>;
+ qcom,msm-id = <321 0x10000>;
qcom,board-id = <1 0>;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
index c4ec012..3a0e4b6 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
@@ -11,6 +11,8 @@
*/
#include <dt-bindings/gpio/gpio.h>
+#include "sdm845-pmic-overlay.dtsi"
+#include "sdm845-pinctrl-overlay.dtsi"
#include "sdm845-camera-sensor-cdp.dtsi"
&vendor {
@@ -169,10 +171,6 @@
pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on>;
pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>;
- qcom,clk-rates = <400000 20000000 25000000
- 50000000 100000000 200000000>;
- qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
-
extcon = <&extcon_storage_cd>;
status = "ok";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
index 3f05846..de50aec 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
@@ -27,26 +27,20 @@
compatible = "qcom,devbw";
governor = "bw_vbif";
qcom,src-dst-ports = <26 512>;
- /*
- * active-only flag is used while registering the bus
- * governor.It helps release the bus vote when the CPU
- * subsystem is inactiv3
- */
- qcom,active-only;
qcom,bw-tbl =
< 0 /* off */ >,
- < 762 /* 100 MHz */ >,
- < 1144 /* 150 MHz */ >,
- < 1525 /* 200 MHz */ >,
- < 2288 /* 300 MHz */ >,
- < 3143 /* 412 MHz */ >,
- < 4173 /* 547 MHz */ >,
- < 5195 /* 681 MHz */ >,
- < 5859 /* 768 MHz */ >,
- < 7759 /* 1017 MHz */ >,
- < 9887 /* 1296 MHz */ >,
- < 11863 /* 1555 MHz */ >,
- < 13763 /* 1804 MHz */ >;
+ < 381 /* 100 MHz */ >,
+ < 572 /* 150 MHz */ >,
+ < 762 /* 200 MHz */ >,
+ < 1144 /* 300 MHz */ >,
+ < 1571 /* 412 MHz */ >,
+ < 2086 /* 547 MHz */ >,
+ < 2597 /* 681 MHz */ >,
+ < 2929 /* 768 MHz */ >,
+ < 3879 /* 1017 MHz */ >,
+ < 4943 /* 1296 MHz */ >,
+ < 5931 /* 1555 MHz */ >,
+ < 6881 /* 1804 MHz */ >;
};
msm_gpu: qcom,kgsl-3d0@5000000 {
@@ -61,7 +55,7 @@
qcom,chipid = <0x06030000>;
- qcom,initial-pwrlevel = <2>;
+ qcom,initial-pwrlevel = <5>;
qcom,gpu-quirk-hfi-use-reg;
@@ -99,23 +93,24 @@
qcom,gpubw-dev = <&gpubw>;
qcom,bus-control;
qcom,msm-bus,name = "grp3d";
+ qcom,bus-width = <32>;
qcom,msm-bus,num-cases = <13>;
qcom,msm-bus,num-paths = <1>;
qcom,msm-bus,vectors-KBps =
<26 512 0 0>,
- <26 512 0 800000>, // 1 bus=100
- <26 512 0 1200000>, // 2 bus=150
- <26 512 0 1600000>, // 3 bus=200
- <26 512 0 2400000>, // 4 bus=300
- <26 512 0 3296000>, // 5 bus=412
- <26 512 0 4376000>, // 6 bus=547
- <26 512 0 5448000>, // 7 bus=681
- <26 512 0 6144000>, // 8 bus=768
- <26 512 0 8136000>, // 9 bus=1017
- <26 512 0 10368000>, // 10 bus=1296
- <26 512 0 12440000>, // 11 bus=1555
- <26 512 0 14432000>; // 12 bus=1804
+ <26 512 0 400000>, // 1 bus=100
+ <26 512 0 600000>, // 2 bus=150
+ <26 512 0 800000>, // 3 bus=200
+ <26 512 0 1200000>, // 4 bus=300
+ <26 512 0 1648000>, // 5 bus=412
+ <26 512 0 2188000>, // 6 bus=547
+ <26 512 0 2724000>, // 7 bus=681
+ <26 512 0 3072000>, // 8 bus=768
+ <26 512 0 4068000>, // 9 bus=1017
+ <26 512 0 5184000>, // 10 bus=1296
+ <26 512 0 6220000>, // 11 bus=1555
+ <26 512 0 7216000>; // 12 bus=1804
/* GDSC regulator names */
regulator-names = "vddcx", "vdd";
@@ -170,31 +165,65 @@
qcom,gpu-pwrlevel@0 {
reg = <0>;
- qcom,gpu-freq = <280000000>;
- qcom,bus-freq = <4>;
- qcom,bus-min = <3>;
- qcom,bus-max = <5>;
+ qcom,gpu-freq = <600000000>;
+ qcom,bus-freq = <12>;
+ qcom,bus-min = <11>;
+ qcom,bus-max = <12>;
};
qcom,gpu-pwrlevel@1 {
reg = <1>;
- qcom,gpu-freq = <280000000>;
- qcom,bus-freq = <4>;
- qcom,bus-min = <3>;
- qcom,bus-max = <5>;
+ qcom,gpu-freq = <548000000>;
+ qcom,bus-freq = <12>;
+ qcom,bus-min = <10>;
+ qcom,bus-max = <12>;
};
qcom,gpu-pwrlevel@2 {
reg = <2>;
+ qcom,gpu-freq = <487000000>;
+ qcom,bus-freq = <10>;
+ qcom,bus-min = <9>;
+ qcom,bus-max = <11>;
+ };
+
+
+ qcom,gpu-pwrlevel@3 {
+ reg = <3>;
+ qcom,gpu-freq = <425000000>;
+ qcom,bus-freq = <9>;
+ qcom,bus-min = <8>;
+ qcom,bus-max = <10>;
+ };
+
+ qcom,gpu-pwrlevel@4 {
+ reg = <4>;
+ qcom,gpu-freq = <338000000>;
+ qcom,bus-freq = <8>;
+ qcom,bus-min = <7>;
+ qcom,bus-max = <9>;
+ };
+
+
+ qcom,gpu-pwrlevel@5 {
+ reg = <5>;
qcom,gpu-freq = <280000000>;
+ qcom,bus-freq = <5>;
+ qcom,bus-min = <5>;
+ qcom,bus-max = <7>;
+ };
+
+ qcom,gpu-pwrlevel@6 {
+ reg = <6>;
+ qcom,gpu-freq = <210000000>;
qcom,bus-freq = <4>;
qcom,bus-min = <3>;
qcom,bus-max = <5>;
};
- qcom,gpu-pwrlevel@3 {
- reg = <3>;
+ qcom,gpu-pwrlevel@7 {
+ reg = <7>;
qcom,gpu-freq = <0>;
qcom,bus-freq = <0>;
qcom,bus-min = <0>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi b/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi
new file mode 100644
index 0000000..cac5bc0
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi
@@ -0,0 +1,398 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+/ {
+ /delete-node/regulator-pm8998-s4;
+};
+
+&dsi_sharp_4k_dsc_video_display {
+ /delete-property/ vddio-supply;
+};
+
+&dsi_sharp_4k_dsc_cmd_display {
+ /delete-property/ vddio-supply;
+};
+
+&dsi_sharp_1080_cmd_display {
+ /delete-property/ vddio-supply;
+};
+
+&dsi_dual_sharp_1080_120hz_cmd_display {
+ /delete-property/ vddio-supply;
+};
+
+&dsi_dual_nt35597_truly_video_display {
+ vddio-supply = <&pm660_l11>;
+ lab-supply = <&lcdb_ldo_vreg>;
+ ibb-supply = <&lcdb_ncp_vreg>;
+};
+
+&dsi_dual_nt35597_truly_cmd_display {
+ vddio-supply = <&pm660_l11>;
+ lab-supply = <&lcdb_ldo_vreg>;
+ ibb-supply = <&lcdb_ncp_vreg>;
+};
+
+&dsi_nt35597_truly_dsc_cmd_display {
+ vddio-supply = <&pm660_l11>;
+ lab-supply = <&lcdb_ldo_vreg>;
+ ibb-supply = <&lcdb_ncp_vreg>;
+};
+
+&dsi_nt35597_truly_dsc_video_display {
+ vddio-supply = <&pm660_l11>;
+ lab-supply = <&lcdb_ldo_vreg>;
+ ibb-supply = <&lcdb_ncp_vreg>;
+};
+
+&sde_dp {
+ status = "disabled";
+ /delete-property/ vdda-1p2-supply;
+ /delete-property/ vdda-0p9-supply;
+ /delete-property/ qcom,dp-usbpd-detection;
+};
+
+&mdss_dp_pll {
+ status = "disabled";
+};
+
+&bluetooth {
+ /delete-property/ qca,bt-vdd-io-supply;
+ /delete-property/ qca,bt-vdd-xtal-supply;
+ /delete-property/ qca,bt-vdd-core-supply;
+ /delete-property/ qca,bt-vdd-pa-supply;
+ /delete-property/ qca,bt-vdd-ldo-supply;
+};
+
+&ufsphy_mem {
+ /delete-property/ vdda-phy-supply;
+ /delete-property/ vdda-pll-supply;
+};
+
+&ufshc_mem {
+ /delete-property/ vcc-supply;
+ /delete-property/ vccq2-supply;
+ /delete-property/ qcom,vddp-ref-clk-supply;
+};
+
+&ufsphy_card {
+ /delete-property/ vdda-phy-supply;
+ /delete-property/ vdda-pll-supply;
+};
+
+&ufshc_card {
+ /delete-property/ vcc-supply;
+ /delete-property/ vccq2-supply;
+ /delete-property/ qcom,vddp-ref-clk-supply;
+};
+
+&sdhc_2 {
+ /delete-property/ vdd-supply;
+ /delete-property/ vdd-io-supply;
+};
+
+&vendor {
+ extcon_usb1 {
+ /delete-property/ id-gpio;
+ /delete-property/ vbus-gpio;
+ /delete-property/ pinctrl-names;
+ /delete-property/ pinctrl-0;
+ };
+
+ usb1_vbus_vreg {
+ /delete-property/ gpio;
+ /delete-property/ pinctrl-names;
+ /delete-property/ pinctrl-0;
+ };
+};
+
+&qupv3_se3_i2c {
+ nq@28 {
+ /delete-property/ qcom,nq-clkreq;
+ /* delete "nfc_clk_default" -- PMIC GPIO */
+ pinctrl-0 = <&nfc_int_active &nfc_enable_active>;
+ };
+};
+
+&pcie0 {
+ /delete-property/ vreg-1.8-supply;
+ /delete-property/ vreg-0.9-supply;
+ /delete-property/ vreg-cx-supply;
+};
+
+&cam_csiphy0 {
+ /delete-property/ mipi-csi-vdd-supply;
+};
+
+&cam_csiphy1 {
+ /delete-property/ mipi-csi-vdd-supply;
+};
+
+&cam_csiphy2 {
+ /delete-property/ mipi-csi-vdd-supply;
+};
+
+&led_flash_rear {
+ /delete-property/ flash-source;
+ /delete-property/ torch-source;
+ /delete-property/ switch-source;
+};
+
+&led_flash_front {
+ /delete-property/ flash-source;
+ /delete-property/ torch-source;
+ /delete-property/ switch-source;
+};
+
+&actuator_regulator {
+ /delete-property/ vin-supply;
+};
+
+
+&eeprom_rear {
+ /delete-property/ cam_vio-supply;
+ /delete-property/ cam_vana-supply;
+};
+
+&eeprom_rear_aux {
+ /delete-property/ cam_vio-supply;
+ /delete-property/ cam_vana-supply;
+};
+
+&eeprom_front {
+ /delete-property/ cam_vio-supply;
+ /delete-property/ cam_vana-supply;
+};
+
+&cam_cci {
+ qcom,cam-sensor@0 {
+ /delete-property/ cam_vio-supply;
+ /delete-property/ cam_vana-supply;
+ };
+
+ qcom,cam-sensor@1 {
+ /delete-property/ cam_vio-supply;
+ /delete-property/ cam_vana-supply;
+ };
+
+ qcom,cam-sensor@2 {
+ /delete-property/ cam_vio-supply;
+ /delete-property/ cam_vana-supply;
+ };
+};
+
+&clock_gcc {
+ /delete-property/ vdd_cx-supply;
+ /delete-property/ vdd_cx_ao-supply;
+};
+
+&clock_videocc {
+ /delete-property/ vdd_cx-supply;
+};
+
+&clock_camcc {
+ /delete-property/ vdd_cx-supply;
+ /delete-property/ vdd_mx-supply;
+};
+
+&clock_dispcc {
+ /delete-property/ vdd_cx-supply;
+};
+
+&clock_gpucc {
+ /delete-property/ vdd_cx-supply;
+};
+
+&clock_gfx {
+ /delete-property/ vdd_gfx-supply;
+ /delete-property/ vdd_mx-supply;
+};
+
+&pil_modem {
+ /delete-property/ vdd_cx-supply;
+ /delete-property/ vdd_mx-supply;
+};
+
+&gpu_gx_gdsc {
+ /delete-property/ parent-supply;
+};
+
+&soc {
+ /delete-node/ gpio_keys;
+
+ qcom,lpass@17300000 {
+ /delete-property/ vdd_cx-supply;
+ };
+
+ qcom,ssc@5c00000 {
+ /delete-property/ vdd_cx-supply;
+ };
+
+ qcom,spss@1880000 {
+ /delete-property/ vdd_cx-supply;
+ /delete-property/ vdd_mx-supply;
+ };
+
+ qcom,turing@8300000 {
+ /delete-property/ vdd_cx-supply;
+ };
+
+ qcom,qbt1000 {
+ /delete-property/ qcom,finger-detect-gpio;
+ };
+
+ qcom,icnss@18800000 {
+ /delete-property/ vdd-0.8-cx-mx-supply;
+ /delete-property/ vdd-1.8-xo-supply;
+ /delete-property/ vdd-1.3-rfa-supply;
+ /delete-property/ vdd-3.3-ch0-supply;
+ };
+
+ qcom,mdss_dsi_ctrl0@ae94000 {
+ vdda-1p2-supply = <&pm660_l1>;
+ };
+
+ qcom,mdss_dsi_ctrl1@ae96000 {
+ vdda-1p2-supply = <&pm660_l1>;
+ };
+
+ qcom,mdss_dsi_phy0@ae94400 {
+ vdda-0p9-supply = <&pm660l_l1>;
+ };
+
+ qcom,mdss_dsi_phy0@ae96400 {
+ vdda-0p9-supply = <&pm660l_l1>;
+ };
+
+ gpio-regulator@1 {
+ /delete-property/ gpio;
+ /delete-property/ vin-supply;
+ /delete-property/ pinctrl-names;
+ /delete-property/ pinctrl-0;
+ };
+
+ gpio-regulator@2 {
+ /delete-property/ gpio;
+ /delete-property/ vin-supply;
+ /delete-property/ pinctrl-names;
+ /delete-property/ pinctrl-0;
+ };
+
+ /delete-node/ qcom,spmi-debug@6b22000;
+
+};
+
+&wil6210 {
+ /delete-property/ vdd-supply;
+ /delete-property/ vddio-supply;
+};
+
+&usb0 {
+ /delete-property/ extcon;
+};
+
+&qusb_phy0 {
+ /delete-property/ vdd-supply;
+ /delete-property/ vdda18-supply;
+ /delete-property/ vdda33-supply;
+};
+
+&usb_qmp_dp_phy {
+ /delete-property/ vdd-supply;
+ /delete-property/ core-supply;
+};
+
+&qusb_phy1 {
+ /delete-property/ vdd-supply;
+ /delete-property/ vdda18-supply;
+ /delete-property/ vdda33-supply;
+};
+
+&usb_qmp_phy {
+ /delete-property/ vdd-supply;
+ /delete-property/ core-supply;
+};
+
+&soc {
+ /* Delete all regulators */
+ /delete-node/ cprh-ctrl@17dc0000;
+ /delete-node/ cprh-ctrl@17db0000;
+ /delete-node/ rpmh-regulator-ebilvl;
+ /delete-node/ rpmh-regulator-smpa2;
+ /delete-node/ rpmh-regulator-smpa3;
+ /delete-node/ rpmh-regulator-smpa5;
+ /delete-node/ rpmh-regulator-mxlvl;
+ /delete-node/ rpmh-regulator-smpa7;
+ /delete-node/ rpmh-regulator-cxlvl;
+ /delete-node/ rpmh-regulator-ldoa1;
+ /delete-node/ rpmh-regulator-ldoa2;
+ /delete-node/ rpmh-regulator-ldoa3;
+ /delete-node/ rpmh-regulator-lmxlvl;
+ /delete-node/ rpmh-regulator-ldoa5;
+ /delete-node/ rpmh-regulator-ldoa6;
+ /delete-node/ rpmh-regulator-ldoa7;
+ /delete-node/ rpmh-regulator-ldoa8;
+ /delete-node/ rpmh-regulator-ldoa9;
+ /delete-node/ rpmh-regulator-ldoa10;
+ /delete-node/ rpmh-regulator-ldoa11;
+ /delete-node/ rpmh-regulator-ldoa12;
+ /delete-node/ rpmh-regulator-ldoa13;
+ /delete-node/ rpmh-regulator-ldoa14;
+ /delete-node/ rpmh-regulator-ldoa15;
+ /delete-node/ rpmh-regulator-ldoa16;
+ /delete-node/ rpmh-regulator-ldoa17;
+ /delete-node/ rpmh-regulator-ldoa18;
+ /delete-node/ rpmh-regulator-ldoa19;
+ /delete-node/ rpmh-regulator-ldoa20;
+ /delete-node/ rpmh-regulator-ldoa21;
+ /delete-node/ rpmh-regulator-ldoa22;
+ /delete-node/ rpmh-regulator-ldoa23;
+ /delete-node/ rpmh-regulator-ldoa24;
+ /delete-node/ rpmh-regulator-ldoa25;
+ /delete-node/ rpmh-regulator-ldoa26;
+ /delete-node/ rpmh-regulator-lcxlvl;
+ /delete-node/ rpmh-regulator-ldoa28;
+ /delete-node/ rpmh-regulator-vsa1;
+ /delete-node/ rpmh-regulator-vsa2;
+ /delete-node/ rpmh-regulator-bobb1;
+ /delete-node/ rpmh-regulator-gfxlvl;
+ /delete-node/ rpmh-regulator-msslvl;
+ /delete-node/ rpmh-regulator-smpc3;
+};
+
+&spmi_bus {
+ /delete-node/ qcom,pm8998@0;
+ /delete-node/ qcom,pm8998@1;
+ /delete-node/ qcom,pm8005@4;
+ /delete-node/ qcom,pm8005@5;
+};
+
+/delete-node/ &pmi8998_lsid0;
+/delete-node/ &pmi8998_lsid1;
+/delete-node/ &ext_5v_boost;
+
+#include "pm660.dtsi"
+#include "pm660l.dtsi"
+#include "sdm670-regulator.dtsi"
+
+&soc {
+ /delete-node/ thermal-zones;
+};
+
+&lmh_dcvs1 {
+ /delete-property/ isens_vref-supply;
+ /delete-property/ isens-vref-settings;
+};
+
+&pm660l_wled {
+ qcom,led-strings-list = [01 02];
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-audio.dtsi b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-audio.dtsi
new file mode 100644
index 0000000..f861ca3
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-audio.dtsi
@@ -0,0 +1,81 @@
+/* Copyright (c) 2017, The Linux Foundation. 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 and
+ * only 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 "sdm670-audio.dtsi"
+
+&msm_audio_ion {
+ iommus = <&apps_smmu 0x1821 0x0>;
+ qcom,smmu-sid-mask = /bits/ 64 <0xf>;
+};
+
+&qupv3_se8_spi {
+ status = "okay";
+};
+
+&pm660l_3 {
+ /delete-node/analog-codec;
+};
+
+&soc {
+ /delete-node/msm-sdw-codec@62ec1000;
+ /delete-node/sound;
+ /delete-node/cdc_pdm_pinctrl;
+ /delete-node/wsa_spkr_en1_pinctrl;
+ /delete-node/wsa_spkr_en2_pinctrl;
+ /delete-node/sdw_clk_data_pinctrl;
+};
+
+&msm_audio_ion {
+ iommus = <&apps_smmu 0x1821 0x0>;
+};
+
+&wcd9xxx_intc {
+ status = "okay";
+ qcom,gpio-connect = <&tlmm 54 0>;
+};
+
+&wdsp_mgr {
+ status = "okay";
+};
+
+&wdsp_glink {
+ status = "okay";
+};
+
+&slim_aud {
+ status = "okay";
+};
+
+&dai_slim {
+ status = "okay";
+};
+
+&wcd934x_cdc {
+ status = "okay";
+};
+
+&clock_audio_lnbb {
+ status = "okay";
+};
+
+&wcd_rst_gpio {
+ status = "okay";
+};
+
+&wcd9xxx_intc {
+ status = "okay";
+};
+
+&tavil_snd {
+ status = "okay";
+};
+
diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-cdp-overlay.dts
new file mode 100644
index 0000000..da59bcf
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-cdp-overlay.dts
@@ -0,0 +1,30 @@
+/* Copyright (c) 2017, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm845-sde-display.dtsi"
+#include "sdm845-interposer-sdm670-cdp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM845 v1 Interposer SDM670 CDP";
+ compatible = "qcom,sdm845-cdp", "qcom,sdm845", "qcom,cdp";
+ qcom,msm-id = <321 0x0>;
+ qcom,board-id = <1 4>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-cdp.dts b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-cdp.dts
new file mode 100644
index 0000000..ebb5e8f
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-cdp.dts
@@ -0,0 +1,24 @@
+/* Copyright (c) 2017, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+
+/dts-v1/;
+
+#include "sdm845-interposer-sdm670.dtsi"
+#include "sdm845-sde-display.dtsi"
+#include "sdm845-interposer-sdm670-cdp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. MSM sdm845 v1 Interposer SDM670 CDP";
+ compatible = "qcom,sdm845-cdp", "qcom,sdm845", "qcom,cdp";
+ qcom,board-id = <1 4>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-cdp.dtsi
new file mode 100644
index 0000000..ad15615
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-cdp.dtsi
@@ -0,0 +1,15 @@
+/* Copyright (c) 2017, The Linux Foundation. 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 and
+ * only 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 "sdm845-cdp.dtsi"
+#include "sdm845-interposer-pm660.dtsi"
+#include "sdm845-interposer-sdm670-audio.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-mtp-overlay.dts
new file mode 100644
index 0000000..3ca15b9
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-mtp-overlay.dts
@@ -0,0 +1,30 @@
+/* Copyright (c) 2017, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm845-sde-display.dtsi"
+#include "sdm845-interposer-sdm670-mtp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM845 v1 Interposer SDM670 MTP";
+ compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp";
+ qcom,msm-id = <321 0x0>;
+ qcom,board-id = <8 4>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-mtp.dts b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-mtp.dts
new file mode 100644
index 0000000..39664f1
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-mtp.dts
@@ -0,0 +1,24 @@
+/* Copyright (c) 2017, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+
+/dts-v1/;
+
+#include "sdm845-interposer-sdm670.dtsi"
+#include "sdm845-sde-display.dtsi"
+#include "sdm845-interposer-sdm670-mtp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. MSM sdm845 v1 Interposer SDM670 MTP";
+ compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp";
+ qcom,board-id = <8 4>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-mtp.dtsi
new file mode 100644
index 0000000..c709770
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-mtp.dtsi
@@ -0,0 +1,19 @@
+/* Copyright (c) 2017, The Linux Foundation. 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 and
+ * only 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 "sdm845-mtp.dtsi"
+#include "sdm845-interposer-pm660.dtsi"
+#include "sdm845-interposer-sdm670-audio.dtsi"
+
+&qupv3_se10_i2c {
+ /delete-node/ qcom,smb1355@8;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670.dts b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670.dts
new file mode 100644
index 0000000..c5e4ae1
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670.dts
@@ -0,0 +1,21 @@
+/* Copyright (c) 2017, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+/dts-v1/;
+
+#include "sdm845-interposer-sdm670.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM845 Interposer SDM670";
+ compatible = "qcom,sdm845";
+ qcom,msm-id = <321 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670.dtsi
new file mode 100644
index 0000000..9341507
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670.dtsi
@@ -0,0 +1,20 @@
+/* Copyright (c) 2017, The Linux Foundation. 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 and
+ * only 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 "sdm845.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM845 Interposer SDM670";
+ compatible = "qcom,sdm845";
+ qcom,msm-id = <321 0x0>;
+};
+
diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts
index 45941a1..2d1d9b6 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts
@@ -26,6 +26,6 @@
/ {
model = "Qualcomm Technologies, Inc. SDM845 v1 MTP";
compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp";
- qcom,msm-id = <321 0x0>;
+ qcom,msm-id = <321 0x10000>;
qcom,board-id = <8 0>;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
index 1453975..c3e8b60 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
@@ -11,6 +11,8 @@
*/
#include <dt-bindings/gpio/gpio.h>
+#include "sdm845-pmic-overlay.dtsi"
+#include "sdm845-pinctrl-overlay.dtsi"
#include "sdm845-camera-sensor-mtp.dtsi"
#include "smb1355.dtsi"
@@ -245,10 +247,6 @@
pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on>;
pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>;
- qcom,clk-rates = <400000 20000000 25000000
- 50000000 100000000 200000000>;
- qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
-
extcon = <&extcon_storage_cd>;
status = "ok";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-pinctrl-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pinctrl-overlay.dtsi
new file mode 100644
index 0000000..8dd75b69
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-pinctrl-overlay.dtsi
@@ -0,0 +1,51 @@
+/* Copyright (c) 2017, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+&pmi8998_gpios {
+ usb2_vbus_boost {
+ usb2_vbus_boost_default: usb2_vbus_boost_default {
+ pins = "gpio2";
+ function = "normal";
+ output-low;
+ power-source = <0>;
+ };
+ };
+
+ usb2_vbus_det {
+ usb2_vbus_det_default: usb2_vbus_det_default {
+ pins = "gpio8";
+ function = "normal";
+ input-enable;
+ bias-pull-down;
+ power-source = <1>; /* VPH input supply */
+ };
+ };
+
+ usb2_id_det {
+ usb2_id_det_default: usb2_id_det_default {
+ pins = "gpio9";
+ function = "normal";
+ input-enable;
+ bias-pull-up;
+ power-source = <0>;
+ };
+ };
+
+ usb2_ext_5v_boost {
+ usb2_ext_5v_boost_default: usb2_ext_5v_boost_default {
+ pins = "gpio10";
+ function = "normal";
+ output-low;
+ power-source = <0>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
index 04f67cd..3e27297 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
@@ -1400,6 +1400,90 @@
};
};
+ quat_tdm {
+ quat_tdm_sleep: quat_tdm_sleep {
+ mux {
+ pins = "gpio58", "gpio59";
+ function = "qua_mi2s";
+ };
+
+ config {
+ pins = "gpio58", "gpio59";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+
+ quat_tdm_active: quat_tdm_active {
+ mux {
+ pins = "gpio58", "gpio59";
+ function = "qua_mi2s";
+ };
+
+ config {
+ pins = "gpio58", "gpio59";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL */
+ };
+ };
+ };
+
+ quat_tdm_dout {
+ quat_tdm_dout_sleep: quat_tdm_dout_sleep {
+ mux {
+ pins = "gpio61";
+ function = "qua_mi2s";
+ };
+
+ config {
+ pins = "gpio61";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+
+ quat_tdm_dout_active: quat_tdm_dout_active {
+ mux {
+ pins = "gpio61";
+ function = "qua_mi2s";
+ };
+
+ config {
+ pins = "gpio61";
+ drive-strength = <2>; /* 2 mA */
+ bias-disable; /* NO PULL */
+ };
+ };
+ };
+
+ quat_tdm_din {
+ quat_tdm_din_sleep: quat_tdm_din_sleep {
+ mux {
+ pins = "gpio60";
+ function = "qua_mi2s";
+ };
+
+ config {
+ pins = "gpio60";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+
+ quat_tdm_din_active: quat_tdm_din_active {
+ mux {
+ pins = "gpio60";
+ function = "qua_mi2s";
+ };
+
+ config {
+ pins = "gpio60";
+ drive-strength = <2>; /* 2 mA */
+ bias-disable; /* NO PULL */
+ };
+ };
+ };
+
/* QUPv3 South SE mappings */
/* SE 0 pin mappings */
qupv3_se0_i2c_pins: qupv3_se0_i2c_pins {
@@ -2927,43 +3011,3 @@
};
};
};
-
-&pmi8998_gpios {
- usb2_vbus_boost {
- usb2_vbus_boost_default: usb2_vbus_boost_default {
- pins = "gpio2";
- function = "normal";
- output-low;
- power-source = <0>;
- };
- };
-
- usb2_vbus_det {
- usb2_vbus_det_default: usb2_vbus_det_default {
- pins = "gpio8";
- function = "normal";
- input-enable;
- bias-pull-down;
- power-source = <1>; /* VPH input supply */
- };
- };
-
- usb2_id_det {
- usb2_id_det_default: usb2_id_det_default {
- pins = "gpio9";
- function = "normal";
- input-enable;
- bias-pull-up;
- power-source = <0>;
- };
- };
-
- usb2_ext_5v_boost {
- usb2_ext_5v_boost_default: usb2_ext_5v_boost_default {
- pins = "gpio10";
- function = "normal";
- output-low;
- power-source = <0>;
- };
- };
-};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi
index 6215771..c8698c28 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi
@@ -51,7 +51,7 @@
reg = <2>;
label = "l3-pc";
qcom,psci-mode = <0x4>;
- qcom,latency-us = <4562>;
+ qcom,latency-us = <3201>;
qcom,ss-power = <408>;
qcom,energy-overhead = <2421840>;
qcom,time-overhead = <5376>;
@@ -105,7 +105,7 @@
reg = <1>;
qcom,psci-cpu-mode = <0x2>;
qcom,spm-cpu-mode = "ret";
- qcom,latency-us = <86>;
+ qcom,latency-us = <119>;
qcom,ss-power = <449>;
qcom,energy-overhead = <78456>;
qcom,time-overhead = <167>;
@@ -115,7 +115,7 @@
reg = <2>;
qcom,spm-cpu-mode = "pc";
qcom,psci-cpu-mode = <0x3>;
- qcom,latency-us = <612>;
+ qcom,latency-us = <461>;
qcom,ss-power = <436>;
qcom,energy-overhead = <418225>;
qcom,time-overhead = <885>;
@@ -127,7 +127,7 @@
reg = <3>;
qcom,spm-cpu-mode = "rail-pc";
qcom,psci-cpu-mode = <0x4>;
- qcom,latency-us = <700>;
+ qcom,latency-us = <531>;
qcom,ss-power = <400>;
qcom,energy-overhead = <428225>;
qcom,time-overhead = <1000>;
@@ -157,7 +157,7 @@
reg = <1>;
qcom,psci-cpu-mode = <0x2>;
qcom,spm-cpu-mode = "ret";
- qcom,latency-us = <86>;
+ qcom,latency-us = <116>;
qcom,ss-power = <449>;
qcom,energy-overhead = <78456>;
qcom,time-overhead = <167>;
@@ -167,7 +167,7 @@
reg = <2>;
qcom,spm-cpu-mode = "pc";
qcom,psci-cpu-mode = <0x3>;
- qcom,latency-us = <612>;
+ qcom,latency-us = <621>;
qcom,ss-power = <436>;
qcom,energy-overhead = <418225>;
qcom,time-overhead = <885>;
@@ -179,7 +179,7 @@
reg = <3>;
qcom,spm-cpu-mode = "rail-pc";
qcom,psci-cpu-mode = <0x4>;
- qcom,latency-us = <700>;
+ qcom,latency-us = <1061>;
qcom,ss-power = <400>;
qcom,energy-overhead = <428225>;
qcom,time-overhead = <1000>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-pmic-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pmic-overlay.dtsi
new file mode 100644
index 0000000..000d65e7
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-pmic-overlay.dtsi
@@ -0,0 +1,39 @@
+/* Copyright (c) 2017, The Linux Foundation. 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 and
+ * only 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 <dt-bindings/gpio/gpio.h>
+
+#include "pmi8998.dtsi"
+
+&vendor {
+ ext_5v_boost: ext_5v_boost {
+ status = "disabled";
+ compatible = "regulator-fixed";
+ regulator-name = "ext_5v_boost";
+ gpio = <&pmi8998_gpios 10 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+
+ regulator-enable-ramp-delay = <1600>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb2_ext_5v_boost_default>;
+ };
+};
+
+&pmi8998_charger {
+ smb2_vconn: qcom,smb2-vconn {
+ regulator-name = "smb2-vconn";
+ };
+};
+
+&usb0 {
+ extcon = <&pmi8998_pdphy>, <&pmi8998_pdphy>, <&eud>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qrd-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qrd-audio-overlay.dtsi
index b11c912..361fa2f 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qrd-audio-overlay.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-qrd-audio-overlay.dtsi
@@ -30,33 +30,31 @@
};
};
-&wcd934x_cdc {
- wcd_pinctrl@5 {
- us_euro_sw_wcd_active {
- mux {
- pins = "gpio1";
- };
-
- config {
- pins = "gpio1";
- /delete-property/ output-high;
- bias-high-impedance;
- };
- };
-
- us_euro_sw_wcd_sleep {
- mux {
- pins = "gpio1";
- };
-
- config {
- pins = "gpio1";
- /delete-property/ output-low;
- bias-high-impedance;
- };
- };
+&us_euro_sw_wcd_active {
+ mux {
+ pins = "gpio1";
};
+ config {
+ pins = "gpio1";
+ /delete-property/ output-high;
+ bias-high-impedance;
+ };
+};
+
+&us_euro_sw_wcd_sleep {
+ mux {
+ pins = "gpio1";
+ };
+
+ config {
+ pins = "gpio1";
+ /delete-property/ output-low;
+ bias-high-impedance;
+ };
+};
+
+&wcd934x_cdc {
swr_master {
wsa881x@20170211 {
compatible = "qcom,wsa881x";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-qrd-overlay.dts
index 6cead9d..c8136de 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qrd-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-qrd-overlay.dts
@@ -26,6 +26,6 @@
/ {
model = "Qualcomm Technologies, Inc. SDM845 v1 QRD";
compatible = "qcom,sdm845-qrd", "qcom,sdm845", "qcom,qrd";
- qcom,msm-id = <321 0x0>;
+ qcom,msm-id = <321 0x10000>;
qcom,board-id = <11 0>;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
index 9cf18b7..6122eee 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
@@ -10,6 +10,8 @@
* GNU General Public License for more details.
*/
+#include "sdm845-pmic-overlay.dtsi"
+#include "sdm845-pinctrl-overlay.dtsi"
#include "smb1355.dtsi"
#include <dt-bindings/gpio/gpio.h>
@@ -37,8 +39,7 @@
qrd_batterydata: qcom,battery-data {
qcom,batt-id-range-pct = <15>;
- #include "fg-gen3-batterydata-itech-3000mah.dtsi"
- #include "fg-gen3-batterydata-ascent-3450mah.dtsi"
+ #include "fg-gen3-batterydata-gt3746a6-2900mah.dtsi"
};
};
@@ -84,6 +85,7 @@
&pmi8998_fg {
qcom,battery-data = <&qrd_batterydata>;
+ qcom,fg-bmd-en-delay-ms = <300>;
};
&smb1355_charger {
@@ -170,10 +172,6 @@
pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on>;
pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>;
- qcom,clk-rates = <400000 20000000 25000000
- 50000000 100000000 200000000>;
- qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
-
extcon = <&extcon_storage_cd>;
status = "ok";
@@ -189,35 +187,42 @@
qcom,led-strings-list = [01 02];
};
+&pmi8998_haptics {
+ qcom,vmax-mv = <1800>;
+ qcom,wave-play-rate-us = <4347>;
+ qcom,lra-auto-mode;
+ status = "okay";
+};
+
&mdss_mdp {
connectors = <&sde_rscc &sde_wb>;
};
-&dsi_sharp_4k_dsc_video {
+&dsi_nt35597_truly_dsc_cmd {
qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
qcom,mdss-dsi-bl-min-level = <1>;
qcom,mdss-dsi-bl-max-level = <4095>;
- qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,mdss-dsi-mode-sel-gpio-state = "single_port";
qcom,panel-mode-gpio = <&tlmm 52 0>;
qcom,platform-te-gpio = <&tlmm 10 0>;
qcom,platform-reset-gpio = <&tlmm 6 0>;
qcom,mdss-dsi-panel-orientation = "180";
};
-&dsi_sharp_4k_dsc_cmd {
+&dsi_nt35597_truly_dsc_video {
qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
qcom,mdss-dsi-bl-min-level = <1>;
qcom,mdss-dsi-bl-max-level = <4095>;
- qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,mdss-dsi-mode-sel-gpio-state = "single_port";
qcom,panel-mode-gpio = <&tlmm 52 0>;
qcom,platform-te-gpio = <&tlmm 10 0>;
qcom,platform-reset-gpio = <&tlmm 6 0>;
qcom,mdss-dsi-panel-orientation = "180";
};
-&dsi_sharp_4k_dsc_video_display {
+&dsi_nt35597_truly_dsc_cmd_display {
qcom,dsi-display-active;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
index b826768..f50df47 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
@@ -453,7 +453,7 @@
};
apc1_cpr: cprh-ctrl@17db0000 {
- compatible = "qcom,cprh-sdm845-kbss-regulator";
+ compatible = "qcom,cprh-sdm845-v1-kbss-regulator";
reg = <0x17db0000 0x4000>,
<0x00784000 0x1000>,
<0x17830000 0x1000>;
@@ -792,6 +792,14 @@
regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
};
+
+ mx_cdev: mx-cdev-lvl {
+ compatible = "qcom,regulator-cooling-device";
+ regulator-cdev-supply = <&pm8998_s6_level>;
+ regulator-levels = <RPMH_REGULATOR_LEVEL_NOM
+ RPMH_REGULATOR_LEVEL_OFF>;
+ #cooling-cells = <2>;
+ };
};
rpmh-regulator-smpa7 {
@@ -854,6 +862,25 @@
qcom,init-voltage = <880000>;
qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
};
+
+ pm8998_l1_ao: regulator-l1-ao {
+ regulator-name = "pm8998_l1_ao";
+ qcom,set = <RPMH_REGULATOR_SET_ACTIVE>;
+ regulator-min-microvolt = <880000>;
+ regulator-max-microvolt = <880000>;
+ qcom,init-voltage = <880000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+
+ regulator-l1-so {
+ regulator-name = "pm8998_l1_so";
+ qcom,set = <RPMH_REGULATOR_SET_SLEEP>;
+ regulator-min-microvolt = <880000>;
+ regulator-max-microvolt = <880000>;
+ qcom,init-voltage = <880000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ qcom,init-enable = <0>;
+ };
};
rpmh-regulator-ldoa2 {
@@ -904,13 +931,6 @@
regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
};
-
- mx_cdev: regulator-cdev {
- compatible = "qcom,rpmh-reg-cdev";
- mboxes = <&qmp_aop 0>;
- qcom,reg-resource-name = "mx";
- #cooling-cells = <2>;
- };
};
rpmh-regulator-ldoa5 {
@@ -1421,21 +1441,13 @@
};
};
- ext_5v_boost: ext_5v_boost {
+ refgen: refgen-regulator@ff1000 {
+ compatible = "qcom,refgen-regulator";
+ reg = <0xff1000 0x60>;
+ regulator-name = "refgen";
+ regulator-enable-ramp-delay = <5>;
status = "disabled";
- compatible = "regulator-fixed";
- regulator-name = "ext_5v_boost";
- gpio = <&pmi8998_gpios 10 GPIO_ACTIVE_HIGH>;
- enable-active-high;
-
- regulator-enable-ramp-delay = <1600>;
- pinctrl-names = "default";
- pinctrl-0 = <&usb2_ext_5v_boost_default>;
- };
-};
-
-&pmi8998_charger {
- smb2_vconn: qcom,smb2-vconn {
- regulator-name = "smb2-vconn";
+ proxy-supply = <&refgen>;
+ qcom,proxy-consumer-enable;
};
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-rumi.dtsi b/arch/arm64/boot/dts/qcom/sdm845-rumi.dtsi
index 6991b17..e7fd8a0 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-rumi.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-rumi.dtsi
@@ -11,6 +11,8 @@
*/
#include <dt-bindings/spmi/spmi.h>
+#include "sdm845-pmic-overlay.dtsi"
+#include "sdm845-pinctrl-overlay.dtsi"
&ufsphy_mem {
compatible = "qcom,ufs-phy-qrbtc-sdm845";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
index 6fb4f37..f33e400 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
@@ -369,6 +369,14 @@
label = "wb_display";
};
+ ext_disp: qcom,msm-ext-disp {
+ compatible = "qcom,msm-ext-disp";
+
+ ext_disp_audio_codec: qcom,msm-ext-disp-audio-codec-rx {
+ compatible = "qcom,msm-ext-disp-audio-codec-rx";
+ };
+ };
+
sde_dp: qcom,dp_display@0{
cell-index = <0>;
compatible = "qcom,dp-display";
@@ -410,8 +418,19 @@
"crypto_clk", "pixel_clk_rcg", "pixel_parent";
qcom,dp-usbpd-detection = <&pmi8998_pdphy>;
+ qcom,ext-disp = <&ext_disp>;
- qcom,aux-cfg-settings = [00 13 04 00 0a 26 0a 03 bb 03];
+ qcom,aux-cfg0-settings = [20 00];
+ qcom,aux-cfg1-settings = [24 13 23 1d];
+ qcom,aux-cfg2-settings = [28 24];
+ qcom,aux-cfg3-settings = [2c 00];
+ qcom,aux-cfg4-settings = [30 0a];
+ qcom,aux-cfg5-settings = [34 26];
+ qcom,aux-cfg6-settings = [38 0a];
+ qcom,aux-cfg7-settings = [3c 03];
+ qcom,aux-cfg8-settings = [40 bb];
+ qcom,aux-cfg9-settings = [44 03];
+
qcom,max-pclk-frequency-khz = <576000>;
qcom,core-supply-entries {
@@ -472,108 +491,180 @@
};
&dsi_dual_nt35597_truly_video {
- qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 07 05 03 04 00];
qcom,mdss-dsi-t-clk-post = <0x0D>;
qcom,mdss-dsi-t-clk-pre = <0x2D>;
- qcom,display-topology = <2 0 2>,
- <1 0 2>;
- qcom,default-topology-index = <0>;
+ qcom,mdss-dsi-display-timings {
+ timing@0{
+ qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07
+ 07 05 03 04 00];
+ qcom,display-topology = <2 0 2>,
+ <1 0 2>;
+ qcom,default-topology-index = <0>;
+ };
+ };
};
&dsi_dual_nt35597_truly_cmd {
- qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 07 05 03 04 00];
qcom,mdss-dsi-t-clk-post = <0x0D>;
qcom,mdss-dsi-t-clk-pre = <0x2D>;
- qcom,display-topology = <2 0 2>,
- <1 0 2>;
- qcom,default-topology-index = <0>;
+ qcom,mdss-dsi-display-timings {
+ timing@0{
+ qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07
+ 07 05 03 04 00];
+ qcom,display-topology = <2 0 2>,
+ <1 0 2>;
+ qcom,default-topology-index = <0>;
+ };
+ };
};
&dsi_nt35597_truly_dsc_cmd {
- qcom,mdss-dsi-panel-phy-timings = [00 15 05 05 20 1f 05 05 03 03 04 00];
qcom,mdss-dsi-t-clk-post = <0x0b>;
qcom,mdss-dsi-t-clk-pre = <0x23>;
- qcom,display-topology = <1 1 1>,
- <2 2 1>, /* dsc merge */
- <2 1 1>; /* 3d mux */
- qcom,default-topology-index = <1>;
+ qcom,mdss-dsi-display-timings {
+ timing@0{
+ qcom,mdss-dsi-panel-phy-timings = [00 15 05 05 20 1f 05
+ 05 03 03 04 00];
+ qcom,display-topology = <1 1 1>,
+ <2 2 1>, /* dsc merge */
+ <2 1 1>; /* 3d mux */
+ qcom,default-topology-index = <1>;
+ };
+ };
};
&dsi_nt35597_truly_dsc_video {
- qcom,mdss-dsi-panel-phy-timings = [00 15 05 05 20 1f 05 05 03 03 04 00];
qcom,mdss-dsi-t-clk-post = <0x0b>;
qcom,mdss-dsi-t-clk-pre = <0x23>;
- qcom,display-topology = <1 1 1>,
- <2 2 1>, /* dsc merge */
- <2 1 1>; /* 3d mux */
- qcom,default-topology-index = <1>;
+ qcom,mdss-dsi-display-timings {
+ timing@0{
+ qcom,mdss-dsi-panel-phy-timings = [00 15 05 05 20 1f 05
+ 04 03 03 04 00];
+ qcom,display-topology = <1 1 1>,
+ <2 2 1>, /* dsc merge */
+ <2 1 1>; /* 3d mux */
+ qcom,default-topology-index = <1>;
+ };
+ };
};
&dsi_sharp_4k_dsc_video {
- qcom,mdss-dsi-panel-phy-timings = [00 18 06 06 21 20 06 06 04 03 04 00];
qcom,mdss-dsi-t-clk-post = <0x0c>;
qcom,mdss-dsi-t-clk-pre = <0x27>;
- qcom,display-topology = <2 2 2>;
- qcom,default-topology-index = <0>;
+ qcom,mdss-dsi-display-timings {
+ timing@0{
+ qcom,mdss-dsi-panel-phy-timings = [00 18 06 06 21 20 06
+ 06 04 03 04 00];
+ qcom,display-topology = <2 2 2>;
+ qcom,default-topology-index = <0>;
+ };
+ };
};
&dsi_sharp_4k_dsc_cmd {
- qcom,mdss-dsi-panel-phy-timings = [00 18 06 06 21 20 06 06 04 03 04 00];
qcom,mdss-dsi-t-clk-post = <0x0c>;
qcom,mdss-dsi-t-clk-pre = <0x27>;
- qcom,display-topology = <2 2 2>;
- qcom,default-topology-index = <0>;
+ qcom,mdss-dsi-display-timings {
+ timing@0{
+ qcom,mdss-dsi-panel-phy-timings = [00 18 06 06 21 20 06
+ 06 04 03 04 00];
+ qcom,display-topology = <2 2 2>;
+ qcom,default-topology-index = <0>;
+ };
+ };
};
&dsi_dual_sharp_1080_120hz_cmd {
- qcom,mdss-dsi-panel-phy-timings = [00 24 09 09 26 24 09 09 06 03 04 00];
qcom,mdss-dsi-t-clk-post = <0x0f>;
qcom,mdss-dsi-t-clk-pre = <0x36>;
- qcom,display-topology = <2 0 2>,
- <1 0 2>;
- qcom,default-topology-index = <0>;
+ qcom,mdss-dsi-display-timings {
+ timing@0{
+ qcom,mdss-dsi-panel-phy-timings = [00 24 09 09 26 24 09
+ 09 06 03 04 00];
+ qcom,display-topology = <2 0 2>,
+ <1 0 2>;
+ qcom,default-topology-index = <0>;
+ };
+ };
};
&dsi_sharp_1080_cmd {
- qcom,mdss-dsi-panel-phy-timings = [00 1A 06 06 22 20 07 07 04 03 04 00];
qcom,mdss-dsi-t-clk-post = <0x0c>;
qcom,mdss-dsi-t-clk-pre = <0x29>;
- qcom,display-topology = <1 0 1>;
- qcom,default-topology-index = <0>;
+ qcom,mdss-dsi-display-timings {
+ timing@0{
+ qcom,mdss-dsi-panel-phy-timings = [00 1A 06 06 22 20 07
+ 07 04 03 04 00];
+ qcom,display-topology = <1 0 1>;
+ qcom,default-topology-index = <0>;
+ };
+ };
};
&dsi_sim_vid {
- qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 07 05 03 04 00];
qcom,mdss-dsi-t-clk-post = <0x0d>;
qcom,mdss-dsi-t-clk-pre = <0x2d>;
- qcom,display-topology = <1 0 1>,
- <2 0 1>;
- qcom,default-topology-index = <0>;
+ qcom,mdss-dsi-display-timings {
+ timing@0{
+ qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07
+ 07 05 03 04 00];
+ qcom,display-topology = <1 0 1>,
+ <2 0 1>;
+ qcom,default-topology-index = <0>;
+ };
+ };
};
&dsi_dual_sim_vid {
- qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 07 05 03 04 00];
qcom,mdss-dsi-t-clk-post = <0x0d>;
qcom,mdss-dsi-t-clk-pre = <0x2d>;
- qcom,display-topology = <2 0 2>,
- <1 0 2>;
- qcom,default-topology-index = <0>;
+ qcom,mdss-dsi-display-timings {
+ timing@0{
+ qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07
+ 07 05 03 04 00];
+ qcom,display-topology = <2 0 2>,
+ <1 0 2>;
+ qcom,default-topology-index = <0>;
+ };
+ };
};
&dsi_sim_cmd {
- qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 07 05 03 04 00];
qcom,mdss-dsi-t-clk-post = <0x0d>;
qcom,mdss-dsi-t-clk-pre = <0x2d>;
- qcom,display-topology = <1 0 1>,
- <2 0 1>;
- qcom,default-topology-index = <0>;
+ qcom,mdss-dsi-display-timings {
+ timing@0{
+ qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07
+ 07 05 03 04 00];
+ qcom,display-topology = <1 0 1>,
+ <2 0 1>;
+ qcom,default-topology-index = <0>;
+ };
+ };
};
&dsi_dual_sim_cmd {
- qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 07 05 03 04 00];
qcom,mdss-dsi-t-clk-post = <0x0d>;
qcom,mdss-dsi-t-clk-pre = <0x2d>;
- qcom,display-topology = <2 0 2>,
- <1 0 2>;
- qcom,default-topology-index = <0>;
+ qcom,mdss-dsi-display-timings {
+ timing@0{
+ qcom,mdss-dsi-panel-phy-timings = [00 24 09 09 26 24 09
+ 09 06 03 04 00];
+ qcom,display-topology = <2 0 2>;
+ qcom,default-topology-index = <0>;
+ };
+ timing@1{
+ qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07
+ 07 05 03 04 00];
+ qcom,display-topology = <2 0 2>,
+ <1 0 2>;
+ qcom,default-topology-index = <0>;
+ };
+ timing@2{
+ qcom,mdss-dsi-panel-phy-timings = [00 18 06 06 21 20 06
+ 06 04 03 04 00];
+ qcom,display-topology = <2 0 2>;
+ qcom,default-topology-index = <0>;
+ };
+ };
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
index 17adbf4..121565e 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
@@ -14,11 +14,9 @@
mdss_mdp: qcom,mdss_mdp@ae00000 {
compatible = "qcom,sde-kms";
reg = <0x0ae00000 0x81d40>,
- <0x0aeb0000 0x2008>,
- <0x0aeac000 0xf0>;
+ <0x0aeb0000 0x2008>;
reg-names = "mdp_phys",
- "vbif_phys",
- "regdma_phys";
+ "vbif_phys";
clocks =
<&clock_gcc GCC_DISP_AHB_CLK>,
@@ -30,7 +28,7 @@
clock-names = "gcc_iface", "gcc_bus", "iface_clk",
"bus_clk", "core_clk", "vsync_clk";
clock-rate = <0 0 0 0 300000000 19200000 0>;
- clock-max-rate = <0 0 0 0 430000000 19200000 0>;
+ clock-max-rate = <0 0 0 0 412500000 19200000 0>;
sde-vdd-supply = <&mdss_core_gdsc>;
@@ -181,9 +179,6 @@
/* offsets are relative to "mdp_phys + qcom,sde-off */
qcom,sde-inline-rot-clk-ctrl = <0x2bc 0x8>, <0x2bc 0xc>;
- qcom,sde-reg-dma-off = <0>;
- qcom,sde-reg-dma-version = <0x1>;
- qcom,sde-reg-dma-trigger-off = <0x119c>;
qcom,sde-sspp-vig-blocks {
qcom,sde-vig-csc-off = <0x1a00>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sim.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sim.dtsi
index a03148d..efb337d 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sim.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sim.dtsi
@@ -10,6 +10,9 @@
* GNU General Public License for more details.
*/
+#include "sdm845-pmic-overlay.dtsi"
+#include "sdm845-pinctrl-overlay.dtsi"
+
&pmi8998_charger {
qcom,suspend-input;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi b/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi
index ec048ca..f721025 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi
@@ -21,6 +21,8 @@
reg = <0x0a600000 0xf8c00>,
<0x088ee000 0x400>;
reg-names = "core_base", "ahb2phy_base";
+ iommus = <&apps_smmu 0x740 0x0>;
+ qcom,smmu-s1-bypass;
#address-cells = <1>;
#size-cells = <1>;
ranges;
@@ -34,7 +36,7 @@
qcom,dwc-usb3-msm-tx-fifo-size = <21288>;
qcom,num-gsi-evt-buffs = <0x3>;
qcom,use-pdc-interrupts;
- extcon = <&pmi8998_pdphy>, <&pmi8998_pdphy>, <&eud>;
+ extcon = <0>, <0>, <&eud>;
clocks = <&clock_gcc GCC_USB30_PRIM_MASTER_CLK>,
<&clock_gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>,
@@ -61,10 +63,10 @@
<MSM_BUS_MASTER_USB3 MSM_BUS_SLAVE_IPA_CFG 0 0>,
<MSM_BUS_MASTER_AMPSS_M0 MSM_BUS_SLAVE_USB3 0 0>,
<MSM_BUS_MASTER_USB3
- MSM_BUS_SLAVE_EBI_CH0 240000 800000>,
+ MSM_BUS_SLAVE_EBI_CH0 240000 700000>,
<MSM_BUS_MASTER_USB3
MSM_BUS_SLAVE_IPA_CFG 0 2400>,
- <MSM_BUS_MASTER_AMPSS_M0 MSM_BUS_SLAVE_USB3 0 80000>;
+ <MSM_BUS_MASTER_AMPSS_M0 MSM_BUS_SLAVE_USB3 0 40000>;
dwc3@a600000 {
compatible = "snps,dwc3";
@@ -331,6 +333,8 @@
reg = <0x0a800000 0xf8c00>,
<0x088ee000 0x400>;
reg-names = "core_base", "ahb2phy_base";
+ iommus = <&apps_smmu 0x760 0x0>;
+ qcom,smmu-s1-bypass;
#address-cells = <1>;
#size-cells = <1>;
ranges;
@@ -368,8 +372,8 @@
<MSM_BUS_MASTER_USB3_1 MSM_BUS_SLAVE_EBI_CH0 0 0>,
<MSM_BUS_MASTER_AMPSS_M0 MSM_BUS_SLAVE_USB3_1 0 0>,
<MSM_BUS_MASTER_USB3_1
- MSM_BUS_SLAVE_EBI_CH0 240000 800000>,
- <MSM_BUS_MASTER_AMPSS_M0 MSM_BUS_SLAVE_USB3_1 0 80000>;
+ MSM_BUS_SLAVE_EBI_CH0 240000 700000>,
+ <MSM_BUS_MASTER_AMPSS_M0 MSM_BUS_SLAVE_USB3_1 0 40000>;
dwc3@a600000 {
compatible = "snps,dwc3";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
index dbe6267..512bbb0 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
@@ -18,23 +18,778 @@
qcom,msm-id = <321 0x20000>;
};
+&sdhc_2 {
+ /delete-property/ qcom,sdr104-wa;
+};
+
+/delete-node/ &apc0_cpr;
+/delete-node/ &apc1_cpr;
+
+&soc {
+ /* CPR controller regulators */
+ apc0_cpr: cprh-ctrl@17dc0000 {
+ compatible = "qcom,cprh-sdm845-v2-kbss-regulator";
+ reg = <0x17dc0000 0x4000>,
+ <0x00784000 0x1000>,
+ <0x17840000 0x1000>;
+ reg-names = "cpr_ctrl", "fuse_base", "saw";
+ clocks = <&clock_gcc GCC_CPUSS_RBCPR_CLK>;
+ clock-names = "core_clk";
+ qcom,cpr-ctrl-name = "apc0";
+ qcom,cpr-controller-id = <0>;
+
+ qcom,cpr-sensor-time = <1000>;
+ qcom,cpr-loop-time = <5000000>;
+ qcom,cpr-idle-cycles = <15>;
+ qcom,cpr-up-down-delay-time = <3000>;
+ qcom,cpr-step-quot-init-min = <11>;
+ qcom,cpr-step-quot-init-max = <12>;
+ qcom,cpr-count-mode = <0>; /* All at once */
+ qcom,cpr-count-repeat = <20>;
+ qcom,cpr-down-error-step-limit = <1>;
+ qcom,cpr-up-error-step-limit = <1>;
+ qcom,cpr-corner-switch-delay-time = <1042>;
+ qcom,cpr-voltage-settling-time = <1760>;
+ qcom,cpr-reset-step-quot-loop-en;
+
+ qcom,voltage-step = <4000>;
+ qcom,voltage-base = <352000>;
+ qcom,cpr-saw-use-unit-mV;
+
+ qcom,saw-avs-ctrl = <0x101C031>;
+ qcom,saw-avs-limit = <0x3B803B8>;
+
+ qcom,cpr-enable;
+ qcom,cpr-hw-closed-loop;
+
+ qcom,cpr-panic-reg-addr-list =
+ <0x17dc3a84 0x17dc3a88 0x17840c18>;
+ qcom,cpr-panic-reg-name-list =
+ "APSS_SILVER_CPRH_STATUS_0",
+ "APSS_SILVER_CPRH_STATUS_1",
+ "SILVER_SAW4_PMIC_STS";
+
+ qcom,cpr-aging-ref-voltage = <952000>;
+ vdd-supply = <&pm8998_s13>;
+
+ thread@0 {
+ qcom,cpr-thread-id = <0>;
+ qcom,cpr-consecutive-up = <0>;
+ qcom,cpr-consecutive-down = <0>;
+ qcom,cpr-up-threshold = <2>;
+ qcom,cpr-down-threshold = <2>;
+
+ apc0_pwrcl_vreg: regulator {
+ regulator-name = "apc0_pwrcl_corner";
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <18>;
+
+ qcom,cpr-fuse-corners = <4>;
+ qcom,cpr-fuse-combos = <16>;
+ qcom,cpr-speed-bins = <2>;
+ qcom,cpr-speed-bin-corners = <18 18>;
+ qcom,cpr-corners = <18>;
+
+ qcom,cpr-corner-fmax-map = <6 12 15 18>;
+
+ qcom,cpr-voltage-ceiling =
+ <828000 828000 828000 828000 828000
+ 828000 828000 828000 828000 828000
+ 828000 828000 828000 828000 828000
+ 884000 1000000 1000000>;
+
+ qcom,cpr-voltage-floor =
+ <568000 568000 568000 568000 568000
+ 568000 568000 568000 568000 568000
+ 568000 568000 568000 568000 568000
+ 568000 568000 568000>;
+
+ qcom,cpr-floor-to-ceiling-max-range =
+ <32000 32000 32000 32000 32000
+ 32000 32000 32000 32000 32000
+ 32000 32000 32000 32000 32000
+ 32000 40000 40000>;
+
+ qcom,corner-frequencies =
+ <300000000 403200000 480000000
+ 576000000 652800000 748800000
+ 825600000 902400000 979200000
+ 1056000000 1132800000 1228800000
+ 1324800000 1420800000 1516800000
+ 1612800000 1689600000 1766400000>;
+
+ qcom,cpr-ro-scaling-factor =
+ <2594 2795 2576 2761 2469 2673 2198
+ 2553 3188 3255 3191 2962 3055 2984
+ 2043 2947>,
+ <2594 2795 2576 2761 2469 2673 2198
+ 2553 3188 3255 3191 2962 3055 2984
+ 2043 2947>,
+ <2259 2389 2387 2531 2294 2464 2218
+ 2476 2525 2855 2817 2836 2740 2490
+ 1950 2632>,
+ <2259 2389 2387 2531 2294 2464 2218
+ 2476 2525 2855 2817 2836 2740 2490
+ 1950 2632>;
+
+ qcom,cpr-open-loop-voltage-fuse-adjustment =
+ <100000 100000 100000 100000>;
+
+ qcom,cpr-closed-loop-voltage-fuse-adjustment =
+ <100000 100000 100000 100000>;
+
+ qcom,allow-voltage-interpolation;
+ qcom,allow-quotient-interpolation;
+ qcom,cpr-scaled-open-loop-voltage-as-ceiling;
+
+ qcom,cpr-aging-max-voltage-adjustment = <15000>;
+ qcom,cpr-aging-ref-corner = <18>;
+ qcom,cpr-aging-ro-scaling-factor = <1620>;
+ qcom,allow-aging-voltage-adjustment =
+ /* Speed bin 0 */
+ <0 1 1 1 1 1 1 1>,
+ /* Speed bin 1 */
+ <0 1 1 1 1 1 1 1>;
+ qcom,allow-aging-open-loop-voltage-adjustment =
+ <1>;
+ };
+ };
+
+ thread@1 {
+ qcom,cpr-thread-id = <1>;
+ qcom,cpr-consecutive-up = <0>;
+ qcom,cpr-consecutive-down = <0>;
+ qcom,cpr-up-threshold = <2>;
+ qcom,cpr-down-threshold = <2>;
+
+ apc0_l3_vreg: regulator {
+ regulator-name = "apc0_l3_corner";
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <15>;
+
+ qcom,cpr-fuse-corners = <4>;
+ qcom,cpr-fuse-combos = <16>;
+ qcom,cpr-speed-bins = <2>;
+ qcom,cpr-speed-bin-corners = <14 15>;
+ qcom,cpr-corners =
+ /* Speed bin 0 */
+ <14 14 14 14 14 14 14 14>,
+ /* Speed bin 1 */
+ <15 15 15 15 15 15 15 15>;
+
+ qcom,cpr-corner-fmax-map =
+ /* Speed bin 0 */
+ <4 8 11 14>,
+ /* Speed bin 1 */
+ <4 8 11 15>;
+
+ qcom,cpr-voltage-ceiling =
+ /* Speed bin 0 */
+ <828000 828000 828000 828000 828000
+ 828000 828000 828000 828000 828000
+ 828000 884000 884000 1000000>,
+ /* Speed bin 1 */
+ <828000 828000 828000 828000 828000
+ 828000 828000 828000 828000 828000
+ 828000 884000 884000 1000000
+ 1000000>;
+
+ qcom,cpr-voltage-floor =
+ /* Speed bin 0 */
+ <568000 568000 568000 568000 568000
+ 568000 568000 568000 568000 568000
+ 568000 568000 568000 568000>,
+ /* Speed bin 1 */
+ <568000 568000 568000 568000 568000
+ 568000 568000 568000 568000 568000
+ 568000 568000 568000 568000
+ 568000>;
+
+ qcom,cpr-floor-to-ceiling-max-range =
+ /* Speed bin 0 */
+ <32000 32000 32000 32000 32000
+ 32000 32000 32000 32000 32000
+ 32000 32000 32000 40000>,
+ /* Speed bin 1 */
+ <32000 32000 32000 32000 32000
+ 32000 32000 32000 32000 32000
+ 32000 32000 32000 40000 40000>;
+
+ qcom,corner-frequencies =
+ /* Speed bin 0 */
+ <300000000 403200000 480000000
+ 576000000 652800000 748800000
+ 844800000 940800000 1036800000
+ 1132800000 1209600000 1305600000
+ 1401600000 1478400000>,
+ /* Speed bin 1 */
+ <300000000 403200000 480000000
+ 576000000 652800000 748800000
+ 844800000 940800000 1036800000
+ 1132800000 1209600000 1305600000
+ 1401600000 1497600000 1593600000>;
+
+ qcom,cpr-ro-scaling-factor =
+ <2857 3056 2828 2952 2699 2796 2447
+ 2631 2630 2579 2244 3343 3287 3137
+ 3164 2656>,
+ <2857 3056 2828 2952 2699 2796 2447
+ 2631 2630 2579 2244 3343 3287 3137
+ 3164 2656>,
+ <2439 2577 2552 2667 2461 2577 2394
+ 2536 2132 2307 2191 2903 2838 2912
+ 2501 2095>,
+ <2439 2577 2552 2667 2461 2577 2394
+ 2536 2132 2307 2191 2903 2838 2912
+ 2501 2095>;
+
+ qcom,cpr-open-loop-voltage-fuse-adjustment =
+ <100000 100000 100000 100000>;
+
+ qcom,cpr-closed-loop-voltage-fuse-adjustment =
+ <100000 100000 100000 100000>;
+
+ qcom,allow-voltage-interpolation;
+ qcom,allow-quotient-interpolation;
+ qcom,cpr-scaled-open-loop-voltage-as-ceiling;
+
+ qcom,cpr-aging-max-voltage-adjustment = <15000>;
+ qcom,cpr-aging-ref-corner = <14>;
+ qcom,cpr-aging-ro-scaling-factor = <1620>;
+ qcom,allow-aging-voltage-adjustment =
+ /* Speed bin 0 */
+ <0 1 1 1 1 1 1 1>,
+ /* Speed bin 1 */
+ <0 1 1 1 1 1 1 1>;
+ qcom,allow-aging-open-loop-voltage-adjustment =
+ <1>;
+ };
+ };
+ };
+
+ apc1_cpr: cprh-ctrl@17db0000 {
+ compatible = "qcom,cprh-sdm845-v2-kbss-regulator";
+ reg = <0x17db0000 0x4000>,
+ <0x00784000 0x1000>,
+ <0x17830000 0x1000>;
+ reg-names = "cpr_ctrl", "fuse_base", "saw";
+ clocks = <&clock_gcc GCC_CPUSS_RBCPR_CLK>;
+ clock-names = "core_clk";
+ qcom,cpr-ctrl-name = "apc1";
+ qcom,cpr-controller-id = <1>;
+
+ qcom,cpr-sensor-time = <1000>;
+ qcom,cpr-loop-time = <5000000>;
+ qcom,cpr-idle-cycles = <15>;
+ qcom,cpr-up-down-delay-time = <3000>;
+ qcom,cpr-step-quot-init-min = <9>;
+ qcom,cpr-step-quot-init-max = <14>;
+ qcom,cpr-count-mode = <0>; /* All at once */
+ qcom,cpr-count-repeat = <20>;
+ qcom,cpr-down-error-step-limit = <1>;
+ qcom,cpr-up-error-step-limit = <1>;
+ qcom,cpr-corner-switch-delay-time = <1042>;
+ qcom,cpr-voltage-settling-time = <1760>;
+ qcom,cpr-reset-step-quot-loop-en;
+
+ qcom,apm-threshold-voltage = <800000>;
+ qcom,apm-crossover-voltage = <880000>;
+ qcom,mem-acc-threshold-voltage = <852000>;
+ qcom,mem-acc-crossover-voltage = <852000>;
+
+ qcom,voltage-step = <4000>;
+ qcom,voltage-base = <352000>;
+ qcom,cpr-saw-use-unit-mV;
+
+ qcom,saw-avs-ctrl = <0x101C031>;
+ qcom,saw-avs-limit = <0x4700470>;
+
+ qcom,cpr-enable;
+ qcom,cpr-hw-closed-loop;
+
+ qcom,cpr-panic-reg-addr-list =
+ <0x17db3a84 0x17830c18>;
+ qcom,cpr-panic-reg-name-list =
+ "APSS_GOLD_CPRH_STATUS_0", "GOLD_SAW4_PMIC_STS";
+
+ qcom,cpr-aging-ref-voltage = <1136000>;
+ vdd-supply = <&pm8998_s12>;
+
+ thread@0 {
+ qcom,cpr-thread-id = <0>;
+ qcom,cpr-consecutive-up = <0>;
+ qcom,cpr-consecutive-down = <0>;
+ qcom,cpr-up-threshold = <2>;
+ qcom,cpr-down-threshold = <2>;
+
+ apc1_perfcl_vreg: regulator {
+ regulator-name = "apc1_perfcl_corner";
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <33>;
+
+ qcom,cpr-fuse-corners = <5>;
+ qcom,cpr-fuse-combos = <16>;
+ qcom,cpr-speed-bins = <2>;
+ qcom,cpr-speed-bin-corners = <28 31>;
+ qcom,cpr-corners =
+ /* Speed bin 0 */
+ <28 28 28 28 28 28 28 28>,
+ /* Speed bin 1 */
+ <31 31 31 31 31 31 31 31>;
+
+ qcom,cpr-corner-fmax-map =
+ /* Speed bin 0 */
+ <7 14 22 27 28>,
+ /* Speed bin 1 */
+ <7 14 22 27 31>;
+
+ qcom,cpr-voltage-ceiling =
+ /* Speed bin 0 */
+ <828000 828000 828000 828000 828000
+ 828000 828000 828000 828000 828000
+ 828000 828000 828000 828000 828000
+ 828000 828000 828000 884000 884000
+ 884000 884000 1104000 1104000 1104000
+ 1104000 1136000 1136000>,
+ /* Speed bin 1 */
+ <828000 828000 828000 828000 828000
+ 828000 828000 828000 828000 828000
+ 828000 828000 828000 828000 828000
+ 828000 828000 828000 884000 884000
+ 884000 884000 1104000 1104000 1104000
+ 1104000 1136000 1136000 1136000 1136000
+ 1136000>;
+
+ qcom,cpr-voltage-floor =
+ /* Speed bin 0 */
+ <568000 568000 568000 568000 568000
+ 568000 568000 568000 568000 568000
+ 568000 568000 568000 568000 568000
+ 568000 568000 568000 568000 568000
+ 568000 568000 568000 568000 568000
+ 568000 568000 568000>,
+ /* Speed bin 1 */
+ <568000 568000 568000 568000 568000
+ 568000 568000 568000 568000 568000
+ 568000 568000 568000 568000 568000
+ 568000 568000 568000 568000 568000
+ 568000 568000 568000 568000 568000
+ 568000 568000 568000 568000 568000
+ 568000>;
+
+ qcom,cpr-floor-to-ceiling-max-range =
+ /* Speed bin 0 */
+ <32000 32000 32000 32000 32000
+ 32000 32000 32000 32000 32000
+ 32000 32000 32000 32000 32000
+ 32000 32000 32000 32000 32000
+ 32000 32000 32000 32000 32000
+ 32000 32000 32000>,
+ /* Speed bin 1 */
+ <32000 32000 32000 32000 32000
+ 32000 32000 32000 32000 32000
+ 32000 32000 32000 32000 32000
+ 32000 32000 32000 32000 32000
+ 32000 32000 32000 32000 32000
+ 32000 32000 40000 40000 40000
+ 40000>;
+
+ qcom,corner-frequencies =
+ /* Speed bin 0 */
+ <300000000 403200000 480000000
+ 576000000 652800000 748800000
+ 825600000 902400000 979200000
+ 1056000000 1132800000 1209600000
+ 1286400000 1363200000 1459200000
+ 1536000000 1612800000 1689600000
+ 1766400000 1843200000 1920000000
+ 1996800000 2092800000 2169600000
+ 2246400000 2323200000 2400000000
+ 2400000000>,
+ /* Speed bin 1 */
+ <300000000 403200000 480000000
+ 576000000 652800000 748800000
+ 825600000 902400000 979200000
+ 1056000000 1132800000 1209600000
+ 1286400000 1363200000 1459200000
+ 1536000000 1612800000 1689600000
+ 1766400000 1843200000 1920000000
+ 1996800000 2092800000 2169600000
+ 2246400000 2323200000 2400000000
+ 2476800000 2553600000 2630400000
+ 2707200000>;
+
+ qcom,cpr-ro-scaling-factor =
+ <2857 3056 2828 2952 2699 2796 2447
+ 2631 2630 2579 2244 3343 3287 3137
+ 3164 2656>,
+ <2857 3056 2828 2952 2699 2796 2447
+ 2631 2630 2579 2244 3343 3287 3137
+ 3164 2656>,
+ <2086 2208 2273 2408 2203 2327 2213
+ 2340 1755 2039 2049 2474 2437 2618
+ 2003 1675>,
+ <2086 2208 2273 2408 2203 2327 2213
+ 2340 1755 2039 2049 2474 2437 2618
+ 2003 1675>,
+ <2086 2208 2273 2408 2203 2327 2213
+ 2340 1755 2039 2049 2474 2437 2618
+ 2003 1675>;
+
+ qcom,cpr-open-loop-voltage-fuse-adjustment =
+ <100000 100000 100000 100000 100000>;
+
+ qcom,cpr-closed-loop-voltage-fuse-adjustment =
+ <100000 100000 100000 100000 100000>;
+
+ qcom,allow-voltage-interpolation;
+ qcom,allow-quotient-interpolation;
+ qcom,cpr-scaled-open-loop-voltage-as-ceiling;
+
+ qcom,cpr-aging-max-voltage-adjustment = <15000>;
+ qcom,cpr-aging-ref-corner = <27 31>;
+ qcom,cpr-aging-ro-scaling-factor = <1700>;
+ qcom,allow-aging-voltage-adjustment =
+ /* Speed bin 0 */
+ <0 1 1 1 1 1 1 1>,
+ /* Speed bin 1 */
+ <0 1 1 1 1 1 1 1>;
+ qcom,allow-aging-open-loop-voltage-adjustment =
+ <1>;
+ };
+ };
+ };
+};
+
+&clock_cpucc {
+ compatible = "qcom,clk-cpu-osm-v2";
+
+ vdd-l3-supply = <&apc0_l3_vreg>;
+ vdd-pwrcl-supply = <&apc0_pwrcl_vreg>;
+ vdd-perfcl-supply = <&apc1_perfcl_vreg>;
+
+ qcom,l3-speedbin0-v0 =
+ < 300000000 0x000c000f 0x00002020 0x1 1 >,
+ < 403200000 0x500c0115 0x00002020 0x1 2 >,
+ < 480000000 0x50140219 0x00002020 0x1 3 >,
+ < 576000000 0x5014031e 0x00002020 0x1 4 >,
+ < 652800000 0x401c0422 0x00002020 0x1 5 >,
+ < 748800000 0x401c0527 0x00002020 0x1 6 >,
+ < 844800000 0x4024062c 0x00002323 0x2 7 >,
+ < 940800000 0x40240731 0x00002727 0x2 8 >,
+ < 1036800000 0x40240836 0x00002b2b 0x2 9 >,
+ < 1132800000 0x402c093b 0x00002f2f 0x2 10 >,
+ < 1209600000 0x402c0a3f 0x00003232 0x2 11 >,
+ < 1305600000 0x40340b44 0x00003636 0x2 12 >,
+ < 1401600000 0x40340c49 0x00003a3a 0x2 13 >,
+ < 1478400000 0x403c0d4d 0x00003e3e 0x2 14 >;
+
+ qcom,l3-speedbin1-v0 =
+ < 300000000 0x000c000f 0x00002020 0x1 1 >,
+ < 403200000 0x500c0115 0x00002020 0x1 2 >,
+ < 480000000 0x50140219 0x00002020 0x1 3 >,
+ < 576000000 0x5014031e 0x00002020 0x1 4 >,
+ < 652800000 0x401c0422 0x00002020 0x1 5 >,
+ < 748800000 0x401c0527 0x00002020 0x1 6 >,
+ < 844800000 0x4024062c 0x00002323 0x2 7 >,
+ < 940800000 0x40240731 0x00002727 0x2 8 >,
+ < 1036800000 0x40240836 0x00002b2b 0x2 9 >,
+ < 1132800000 0x402c093b 0x00002f2f 0x2 10 >,
+ < 1209600000 0x402c0a3f 0x00003232 0x2 11 >,
+ < 1305600000 0x40340b44 0x00003636 0x2 12 >,
+ < 1401600000 0x40340c49 0x00003a3a 0x2 13 >,
+ < 1497600000 0x403c0d4e 0x00003e3e 0x2 14 >,
+ < 1593600000 0x403c0e53 0x00004242 0x2 15 >;
+
+ qcom,pwrcl-speedbin0-v0 =
+ < 300000000 0x000c000f 0x00002020 0x1 1 >,
+ < 403200000 0x500c0115 0x00002020 0x1 2 >,
+ < 480000000 0x50140219 0x00002020 0x1 3 >,
+ < 576000000 0x5014031e 0x00002020 0x1 4 >,
+ < 652800000 0x401c0422 0x00002020 0x1 5 >,
+ < 748800000 0x401c0527 0x00002020 0x1 6 >,
+ < 825600000 0x401c062b 0x00002222 0x1 7 >,
+ < 902400000 0x4024072f 0x00002626 0x1 8 >,
+ < 979200000 0x40240833 0x00002929 0x1 9 >,
+ < 1056000000 0x402c0937 0x00002c2c 0x2 10 >,
+ < 1132800000 0x402c0a3b 0x00002f2f 0x2 11 >,
+ < 1228800000 0x402c0b40 0x00003333 0x2 12 >,
+ < 1324800000 0x40340c45 0x00003737 0x2 13 >,
+ < 1420800000 0x40340d4a 0x00003b3b 0x2 14 >,
+ < 1516800000 0x403c0e4f 0x00003f3f 0x2 15 >,
+ < 1612800000 0x403c0f54 0x00004343 0x2 16 >,
+ < 1689600000 0x40441058 0x00004646 0x2 17 >,
+ < 1766400000 0x4044115c 0x00004a4a 0x2 18 >;
+
+ qcom,pwrcl-speedbin1-v0 =
+ < 300000000 0x000c000f 0x00002020 0x1 1 >,
+ < 403200000 0x500c0115 0x00002020 0x1 2 >,
+ < 480000000 0x50140219 0x00002020 0x1 3 >,
+ < 576000000 0x5014031e 0x00002020 0x1 4 >,
+ < 652800000 0x401c0422 0x00002020 0x1 5 >,
+ < 748800000 0x401c0527 0x00002020 0x1 6 >,
+ < 825600000 0x401c062b 0x00002222 0x1 7 >,
+ < 902400000 0x4024072f 0x00002626 0x1 8 >,
+ < 979200000 0x40240833 0x00002929 0x1 9 >,
+ < 1056000000 0x402c0937 0x00002c2c 0x2 10 >,
+ < 1132800000 0x402c0a3b 0x00002f2f 0x2 11 >,
+ < 1228800000 0x402c0b40 0x00003333 0x2 12 >,
+ < 1324800000 0x40340c45 0x00003737 0x2 13 >,
+ < 1420800000 0x40340d4a 0x00003b3b 0x2 14 >,
+ < 1516800000 0x403c0e4f 0x00003f3f 0x2 15 >,
+ < 1612800000 0x403c0f54 0x00004343 0x2 16 >,
+ < 1689600000 0x40441058 0x00004646 0x2 17 >,
+ < 1766400000 0x4044115c 0x00004a4a 0x2 18 >;
+
+ qcom,perfcl-speedbin0-v0 =
+ < 300000000 0x000c000f 0x00002020 0x1 1 >,
+ < 403200000 0x500c0115 0x00002020 0x1 2 >,
+ < 480000000 0x50140219 0x00002020 0x1 3 >,
+ < 576000000 0x5014031e 0x00002020 0x1 4 >,
+ < 652800000 0x401c0422 0x00002020 0x1 5 >,
+ < 748800000 0x401c0527 0x00002020 0x1 6 >,
+ < 825600000 0x401c062b 0x00002222 0x1 7 >,
+ < 902400000 0x4024072f 0x00002626 0x1 8 >,
+ < 979200000 0x40240833 0x00002929 0x1 9 >,
+ < 1056000000 0x402c0937 0x00002c2c 0x1 10 >,
+ < 1132800000 0x402c0a3b 0x00002f2f 0x1 11 >,
+ < 1209600000 0x402c0b3f 0x00003232 0x2 12 >,
+ < 1286400000 0x40340c43 0x00003636 0x2 13 >,
+ < 1363200000 0x40340d47 0x00003939 0x2 14 >,
+ < 1459200000 0x403c0e4c 0x00003d3d 0x2 15 >,
+ < 1536000000 0x403c0f50 0x00004040 0x2 16 >,
+ < 1612800000 0x403c1054 0x00004343 0x2 17 >,
+ < 1689600000 0x40441158 0x00004646 0x2 18 >,
+ < 1766400000 0x4044125c 0x00004a4a 0x2 19 >,
+ < 1843200000 0x40441360 0x00004d4d 0x2 20 >,
+ < 1920000000 0x404c1464 0x00005050 0x2 21 >,
+ < 1996800000 0x404c1568 0x00005353 0x2 22 >,
+ < 2092800000 0x4054166d 0x00005757 0x2 23 >,
+ < 2169600000 0x40541771 0x00005a5a 0x2 24 >,
+ < 2246400000 0x40541875 0x00005e5e 0x2 25 >,
+ < 2323200000 0x40541979 0x00006161 0x2 26 >,
+ < 2400000000 0x40541a7d 0x00006464 0x2 27 >;
+
+ qcom,perfcl-speedbin1-v0 =
+ < 300000000 0x000c000f 0x00002020 0x1 1 >,
+ < 403200000 0x500c0115 0x00002020 0x1 2 >,
+ < 480000000 0x50140219 0x00002020 0x1 3 >,
+ < 576000000 0x5014031e 0x00002020 0x1 4 >,
+ < 652800000 0x401c0422 0x00002020 0x1 5 >,
+ < 748800000 0x401c0527 0x00002020 0x1 6 >,
+ < 825600000 0x401c062b 0x00002222 0x1 7 >,
+ < 902400000 0x4024072f 0x00002626 0x1 8 >,
+ < 979200000 0x40240833 0x00002929 0x1 9 >,
+ < 1056000000 0x402c0937 0x00002c2c 0x1 10 >,
+ < 1132800000 0x402c0a3b 0x00002f2f 0x1 11 >,
+ < 1209600000 0x402c0b3f 0x00003232 0x2 12 >,
+ < 1286400000 0x40340c43 0x00003636 0x2 13 >,
+ < 1363200000 0x40340d47 0x00003939 0x2 14 >,
+ < 1459200000 0x403c0e4c 0x00003d3d 0x2 15 >,
+ < 1536000000 0x403c0f50 0x00004040 0x2 16 >,
+ < 1612800000 0x403c1054 0x00004343 0x2 17 >,
+ < 1689600000 0x40441158 0x00004646 0x2 18 >,
+ < 1766400000 0x4044125c 0x00004a4a 0x2 19 >,
+ < 1843200000 0x40441360 0x00004d4d 0x2 20 >,
+ < 1920000000 0x404c1464 0x00005050 0x2 21 >,
+ < 1996800000 0x404c1568 0x00005353 0x2 22 >,
+ < 2092800000 0x4054166d 0x00005757 0x2 23 >,
+ < 2169600000 0x40541771 0x00005a5a 0x2 24 >,
+ < 2246400000 0x40541875 0x00005e5e 0x2 25 >,
+ < 2323200000 0x40541979 0x00006161 0x2 26 >,
+ < 2400000000 0x40541a7d 0x00006464 0x2 27 >,
+ < 2476800000 0x40541b81 0x00006767 0x2 28 >,
+ < 2553600000 0x40541c85 0x00006a6a 0x2 29 >,
+ < 2630400000 0x40541d89 0x00006e6e 0x2 30 >,
+ < 2707200000 0x40541e8d 0x00007171 0x2 31 >;
+
+ qcom,l3-memacc-level-vc-bin0 = <8 13>;
+ qcom,l3-memacc-level-vc-bin1 = <8 13>;
+
+ qcom,pwrcl-memacc-level-vc-bin0 = <12 16>;
+ qcom,pwrcl-memacc-level-vc-bin1 = <12 16>;
+
+ qcom,perfcl-memacc-level-vc-bin0 = <14 22>;
+ qcom,perfcl-memacc-level-vc-bin1 = <14 22>;
+};
+
+&bwmon {
+ qcom,count-unit = <0x10000>;
+};
+
&clock_gcc {
- compatible = "qcom,gcc-sdm845-v2";
+ compatible = "qcom,gcc-sdm845-v2", "syscon";
};
&clock_camcc {
- compatible = "qcom,cam_cc-sdm845-v2";
+ compatible = "qcom,cam_cc-sdm845-v2", "syscon";
};
&clock_dispcc {
- compatible = "qcom,dispcc-sdm845-v2";
+ compatible = "qcom,dispcc-sdm845-v2", "syscon";
+};
+
+&clock_gpucc {
+ compatible = "qcom,gpucc-sdm845-v2", "syscon";
+};
+
+&clock_gfx {
+ compatible = "qcom,gfxcc-sdm845-v2";
};
&clock_videocc {
- compatible = "qcom,video_cc-sdm845-v2";
+ compatible = "qcom,video_cc-sdm845-v2", "syscon";
+};
+
+&clock_aop {
+ compatible = "qcom,aop-qmp-clk-v2";
};
&msm_vidc {
qcom,allowed-clock-rates = <100000000 200000000 330000000
404000000 444000000 533000000>;
};
+
+&refgen {
+ status = "ok";
+ regulator-always-on;
+};
+
+&spss_utils {
+ qcom,spss-dev-firmware-name = "spss2d"; /* 8 chars max */
+ qcom,spss-test-firmware-name = "spss2t"; /* 8 chars max */
+ qcom,spss-prod-firmware-name = "spss2p"; /* 8 chars max */
+};
+
+&mdss_mdp {
+ clock-max-rate = <0 0 0 0 430000000 19200000 0>;
+};
+
+&energy_costs {
+ CPU_COST_0: core-cost0 {
+ busy-cost-data = <
+ 300000 11
+ 403200 17
+ 480000 21
+ 576000 26
+ 652800 31
+ 748800 37
+ 825600 42
+ 902400 47
+ 979200 52
+ 1056000 57
+ 1132800 62
+ 1228800 69
+ 1324800 78
+ 1420800 89
+ 1516800 103
+ 1612800 122
+ 1689600 140
+ 1766400 159
+ >;
+ idle-cost-data = <
+ 22 18 14 12
+ >;
+ };
+ CPU_COST_1: core-cost1 {
+ busy-cost-data = <
+ 300000 130
+ 403200 480
+ 480000 730
+ 576000 1030
+ 652800 1260
+ 748800 1530
+ 825600 1740
+ 902400 1930
+ 979200 2110
+ 1056000 2290
+ 1132800 2460
+ 1209600 2630
+ 1286400 2800
+ 1363200 2980
+ 1459200 3240
+ 1536000 3490
+ 1612800 3780
+ 1689600 4120
+ 1766400 4530
+ 1843200 5020
+ 1920000 5590
+ 1996800 6230
+ 2092800 7120
+ 2169600 7870
+ 2246400 8620
+ 2323200 9330
+ 2400000 10030
+ 2476800 10830
+ 2553600 12080
+ 2630400 14580
+ 2707200 19960
+ >;
+ idle-cost-data = <
+ 100 80 60 40
+ >;
+ };
+ CLUSTER_COST_0: cluster-cost0 {
+ busy-cost-data = <
+ 300000 3
+ 403200 4
+ 480000 4
+ 576000 4
+ 652800 5
+ 748800 5
+ 825600 6
+ 902400 7
+ 979200 7
+ 1056000 8
+ 1132800 9
+ 1228800 9
+ 1324800 10
+ 1420800 11
+ 1516800 12
+ 1612800 13
+ 1689600 15
+ 1766400 17
+ >;
+ idle-cost-data = <
+ 4 3 2 1
+ >;
+ };
+ CLUSTER_COST_1: cluster-cost1 {
+ busy-cost-data = <
+ 300000 24
+ 403200 24
+ 480000 25
+ 576000 25
+ 652800 26
+ 748800 27
+ 825600 28
+ 902400 29
+ 979200 30
+ 1056000 32
+ 1132800 34
+ 1209600 37
+ 1286400 40
+ 1363200 45
+ 1459200 50
+ 1536000 57
+ 1612800 64
+ 1689600 74
+ 1766400 84
+ 1843200 96
+ 1920000 106
+ 1996800 113
+ 2092800 120
+ 2169600 125
+ 2246400 127
+ 2323200 130
+ 2400000 135
+ 2476800 140
+ 2553600 145
+ 2630400 150
+ 2707200 155
+ >;
+ idle-cost-data = <
+ 4 3 2 1
+ >;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi b/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi
index 1c07c5e..42299cd 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi
@@ -79,7 +79,7 @@
label = "venus-llcc";
qcom,bus-master = <MSM_BUS_MASTER_VIDEO_P0>;
qcom,bus-slave = <MSM_BUS_SLAVE_LLCC>;
- qcom,bus-governor = "performance";
+ qcom,bus-governor = "msm-vidc-llcc";
qcom,bus-range-kbps = <17000 125700>;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index 11d553d..88f2e05d 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -29,7 +29,7 @@
/ {
model = "Qualcomm Technologies, Inc. SDM845";
compatible = "qcom,sdm845";
- qcom,msm-id = <321 0x0>;
+ qcom,msm-id = <321 0x10000>;
interrupt-parent = <&pdc>;
aliases {
@@ -344,7 +344,7 @@
};
};
- energy-costs {
+ energy_costs: energy-costs {
compatible = "sched-energy";
CPU_COST_0: core-cost0 {
@@ -515,12 +515,17 @@
#size-cells = <2>;
ranges;
- removed_region1: removed_region1@85700000 {
+ hyp_region: hyp_region@85700000 {
no-map;
- reg = <0 0x85700000 0 0x800000>;
+ reg = <0 0x85700000 0 0x600000>;
};
- removed_region2: removed_region2@85fc0000 {
+ xbl_region: xbl_region@85e00000 {
+ no-map;
+ reg = <0 0x85e00000 0 0x100000>;
+ };
+
+ removed_region: removed_region@85fc0000 {
no-map;
reg = <0 0x85fc0000 0 0x2f40000>;
};
@@ -531,64 +536,70 @@
reg = <0 0x8ab00000 0 0x500000>;
};
- pil_modem_mem: modem_region@8b000000 {
+ pil_ipa_fw_mem: pil_ipa_fw_region@8b000000 {
compatible = "removed-dma-pool";
no-map;
- reg = <0 0x8b000000 0 0x7300000>;
+ reg = <0 0x8b000000 0 0x10000>;
};
- pil_video_mem: pil_video_region@92300000 {
+ pil_ipa_gsi_mem: pil_ipa_gsi_region@8b010000 {
compatible = "removed-dma-pool";
no-map;
- reg = <0 0x92300000 0 0x500000>;
+ reg = <0 0x8b010000 0 0x5000>;
};
- pil_cdsp_mem: cdsp_regions@92800000 {
+ pil_gpu_mem: pil_gpu_region@8b015000 {
compatible = "removed-dma-pool";
no-map;
- reg = <0 0x92800000 0 0x800000>;
+ reg = <0 0x8b015000 0 0x1000>;
};
- pil_adsp_mem: pil_adsp_region@93000000 {
+ pil_adsp_mem: pil_adsp_region@8b100000 {
compatible = "removed-dma-pool";
no-map;
- reg = <0 0x93000000 0 0x1a00000>;
+ reg = <0 0x8b100000 0 0x1a00000>;
};
- pil_mba_mem: pil_mba_region@0x94a00000 {
- compatible = "removed-dma-pool";
- no-map;
- reg = <0 0x94a00000 0 0x200000>;
+ wlan_fw_region: wlan_fw_region@8cb00000 {
+ compatible = "shared-dma-pool";
+ reg = <0 0x8cb00000 0 0x100000>;
};
- pil_slpi_mem: pil_slpi_region@94c00000 {
+ pil_modem_mem: modem_region@8cc00000 {
compatible = "removed-dma-pool";
no-map;
- reg = <0 0x94c00000 0 0x1400000>;
+ reg = <0 0x8cc00000 0 0x7600000>;
};
- pil_ipa_fw_mem: pil_ipa_fw_region@96000000 {
+ pil_video_mem: pil_video_region@94200000 {
compatible = "removed-dma-pool";
no-map;
- reg = <0 0x96000000 0 0x10000>;
+ reg = <0 0x94200000 0 0x500000>;
};
- pil_ipa_gsi_mem: pil_ipa_gsi_region@96010000 {
+ pil_cdsp_mem: cdsp_regions@94700000 {
compatible = "removed-dma-pool";
no-map;
- reg = <0 0x96010000 0 0x5000>;
+ reg = <0 0x94700000 0 0x800000>;
};
- pil_gpu_mem: pil_gpu_region@96015000 {
+ pil_mba_mem: pil_mba_region@0x94f00000 {
compatible = "removed-dma-pool";
no-map;
- reg = <0 0x96015000 0 0x1000>;
+ reg = <0 0x94f00000 0 0x200000>;
};
- pil_spss_mem: spss_region@96100000 {
+ pil_slpi_mem: pil_slpi_region@95100000 {
compatible = "removed-dma-pool";
no-map;
- reg = <0 0x96100000 0 0x100000>;
+ reg = <0 0x95100000 0 0x1400000>;
+ };
+
+
+ pil_spss_mem: spss_region@96500000 {
+ compatible = "removed-dma-pool";
+ no-map;
+ reg = <0 0x96500000 0 0x100000>;
};
adsp_mem: adsp_region {
@@ -602,7 +613,7 @@
qseecom_mem: qseecom_region {
compatible = "shared-dma-pool";
alloc-ranges = <0 0x00000000 0 0xffffffff>;
- reusable;
+ no-map;
alignment = <0 0x400000>;
size = <0 0x1400000>;
};
@@ -935,10 +946,9 @@
qcom,core-dev-table =
< 300000 762 >,
< 748800 1720 >,
- < 979200 2929 >,
- < 1209600 3879 >,
- < 1516800 4943 >,
- < 1593600 5931 >;
+ < 1132800 2086 >,
+ < 1440000 2929 >,
+ < 1593600 3879 >;
};
devfreq_memlat_4: qcom,cpu4-memlat-mon {
@@ -948,10 +958,12 @@
qcom,cachemiss-ev = <0x2A>;
qcom,core-dev-table =
< 300000 762 >,
+ < 499200 1720 >,
+ < 806400 2086 >,
< 1036800 2929 >,
< 1190400 3879 >,
< 1574400 4943 >,
- < 1804800 5931 >,
+ < 1728000 5931 >,
< 1958400 6881 >;
};
@@ -960,7 +972,6 @@
clock-names = "devfreq_clk";
clocks = <&clock_cpucc L3_CLUSTER0_VOTE_CLK>;
governor = "performance";
- qcom,prepare-clk;
};
l3_cpu4: qcom,l3-cpu4 {
@@ -968,7 +979,6 @@
clock-names = "devfreq_clk";
clocks = <&clock_cpucc L3_CLUSTER1_VOTE_CLK>;
governor = "performance";
- qcom,prepare-clk;
};
devfreq_l3lat_0: qcom,cpu0-l3lat-mon {
@@ -1154,8 +1164,8 @@
< 652800000 0x401c0422 0x00002020 0x1 5 >,
< 729600000 0x401c0526 0x00002020 0x1 6 >,
< 806400000 0x401c062a 0x00002222 0x1 7 >,
- < 883200000 0x4024072e 0x00002525 0x2 8 >,
- < 960000000 0x40240832 0x00002828 0x2 9 >;
+ < 883200000 0x4024072e 0x00002525 0x1 8 >,
+ < 960000000 0x40240832 0x00002828 0x1 9 >;
qcom,l3-speedbin1-v0 =
< 300000000 0x000c000f 0x00002020 0x1 1 >,
@@ -1165,10 +1175,10 @@
< 652800000 0x401c0422 0x00002020 0x1 5 >,
< 729600000 0x401c0526 0x00002020 0x1 6 >,
< 806400000 0x401c062a 0x00002222 0x1 7 >,
- < 883200000 0x4024072e 0x00002525 0x2 8 >,
- < 960000000 0x40240832 0x00002828 0x2 9 >,
- < 1036800000 0x40240936 0x00002b2b 0x3 10 >,
- < 1094400000 0x402c0a39 0x00002e2e 0x3 11 >;
+ < 883200000 0x4024072e 0x00002525 0x1 8 >,
+ < 960000000 0x40240832 0x00002828 0x1 9 >,
+ < 1036800000 0x40240936 0x00002b2b 0x1 10 >,
+ < 1094400000 0x402c0a39 0x00002e2e 0x1 11 >;
qcom,l3-speedbin2-v0 =
< 300000000 0x000c000f 0x00002020 0x1 1 >,
@@ -1178,12 +1188,12 @@
< 652800000 0x401c0422 0x00002020 0x1 5 >,
< 729600000 0x401c0526 0x00002020 0x1 6 >,
< 806400000 0x401c062a 0x00002222 0x1 7 >,
- < 883200000 0x4024072e 0x00002525 0x2 8 >,
- < 960000000 0x40240832 0x00002828 0x2 9 >,
- < 1036800000 0x40240936 0x00002b2b 0x3 10 >,
- < 1113600000 0x402c0a3a 0x00002e2e 0x3 11 >,
- < 1209600000 0x402c0b3f 0x00003232 0x3 12 >,
- < 1305600000 0x40340c44 0x00003636 0x3 13 >;
+ < 883200000 0x4024072e 0x00002525 0x1 8 >,
+ < 960000000 0x40240832 0x00002828 0x1 9 >,
+ < 1036800000 0x40240936 0x00002b2b 0x1 10 >,
+ < 1113600000 0x402c0a3a 0x00002e2e 0x1 11 >,
+ < 1209600000 0x402c0b3f 0x00003232 0x1 12 >,
+ < 1305600000 0x40340c44 0x00003636 0x1 13 >;
qcom,pwrcl-speedbin0-v0 =
< 300000000 0x000c000f 0x00002020 0x1 1 >,
@@ -1198,11 +1208,11 @@
< 1056000000 0x402c0937 0x00002c2c 0x1 10 >,
< 1132800000 0x402c0a3b 0x00002f2f 0x1 11 >,
< 1209600000 0x402c0b3f 0x00003232 0x1 12 >,
- < 1286400000 0x40340c43 0x00003636 0x2 13 >,
- < 1363200000 0x40340d47 0x00003939 0x2 14 >,
- < 1440000000 0x40340e4b 0x00003c3c 0x2 15 >,
- < 1516800000 0x403c0f4f 0x00003f3f 0x2 16 >,
- < 1593600000 0x403c1053 0x00004242 0x2 17 >;
+ < 1286400000 0x40340c43 0x00003636 0x1 13 >,
+ < 1363200000 0x40340d47 0x00003939 0x1 14 >,
+ < 1440000000 0x40340e4b 0x00003c3c 0x1 15 >,
+ < 1516800000 0x403c0f4f 0x00003f3f 0x1 16 >,
+ < 1593600000 0x403c1053 0x00004242 0x1 17 >;
qcom,pwrcl-speedbin1-v0 =
< 300000000 0x000c000f 0x00002020 0x1 1 >,
@@ -1217,13 +1227,13 @@
< 1056000000 0x402c0937 0x00002c2c 0x1 10 >,
< 1132800000 0x402c0a3b 0x00002f2f 0x1 11 >,
< 1209600000 0x402c0b3f 0x00003232 0x1 12 >,
- < 1286400000 0x40340c43 0x00003636 0x2 13 >,
- < 1363200000 0x40340d47 0x00003939 0x2 14 >,
- < 1440000000 0x40340e4b 0x00003c3c 0x2 15 >,
- < 1516800000 0x403c0f4f 0x00003f3f 0x2 16 >,
- < 1593600000 0x403c1053 0x00004242 0x2 17 >,
- < 1651200000 0x403c1156 0x00004545 0x3 18 >,
- < 1708800000 0x40441259 0x00004747 0x3 19 >;
+ < 1286400000 0x40340c43 0x00003636 0x1 13 >,
+ < 1363200000 0x40340d47 0x00003939 0x1 14 >,
+ < 1440000000 0x40340e4b 0x00003c3c 0x1 15 >,
+ < 1516800000 0x403c0f4f 0x00003f3f 0x1 16 >,
+ < 1593600000 0x403c1053 0x00004242 0x1 17 >,
+ < 1651200000 0x403c1156 0x00004545 0x1 18 >,
+ < 1708800000 0x40441259 0x00004747 0x1 19 >;
qcom,pwrcl-speedbin2-v0 =
< 300000000 0x000c000f 0x00002020 0x1 1 >,
@@ -1238,13 +1248,13 @@
< 1056000000 0x402c0937 0x00002c2c 0x1 10 >,
< 1132800000 0x402c0a3b 0x00002f2f 0x1 11 >,
< 1209600000 0x402c0b3f 0x00003232 0x1 12 >,
- < 1286400000 0x40340c43 0x00003636 0x2 13 >,
- < 1363200000 0x40340d47 0x00003939 0x2 14 >,
- < 1440000000 0x40340e4b 0x00003c3c 0x2 15 >,
- < 1516800000 0x403c0f4f 0x00003f3f 0x2 16 >,
- < 1593600000 0x403c1053 0x00004242 0x2 17 >,
- < 1670400000 0x40441157 0x00004646 0x3 18 >,
- < 1747200000 0x4044125b 0x00004949 0x3 19 >;
+ < 1286400000 0x40340c43 0x00003636 0x1 13 >,
+ < 1363200000 0x40340d47 0x00003939 0x1 14 >,
+ < 1440000000 0x40340e4b 0x00003c3c 0x1 15 >,
+ < 1516800000 0x403c0f4f 0x00003f3f 0x1 16 >,
+ < 1593600000 0x403c1053 0x00004242 0x1 17 >,
+ < 1670400000 0x40441157 0x00004646 0x1 18 >,
+ < 1747200000 0x4044125b 0x00004949 0x1 19 >;
qcom,perfcl-speedbin0-v0 =
< 300000000 0x000c000f 0x00002020 0x1 1 >,
@@ -1259,16 +1269,16 @@
< 1036800000 0x40240936 0x00002b2b 0x1 10 >,
< 1113600000 0x402c0a3a 0x00002e2e 0x1 11 >,
< 1190400000 0x402c0b3e 0x00003232 0x1 12 >,
- < 1267200000 0x40340c42 0x00003535 0x2 13 >,
- < 1344000000 0x40340d46 0x00003838 0x2 14 >,
- < 1420800000 0x40340e4a 0x00003b3b 0x2 15 >,
- < 1497600000 0x403c0f4e 0x00003e3e 0x2 16 >,
- < 1574400000 0x403c1052 0x00004242 0x2 17 >,
- < 1651200000 0x403c1156 0x00004545 0x2 18 >,
- < 1728000000 0x4044125a 0x00004848 0x3 19 >,
- < 1804800000 0x4044135e 0x00004b4b 0x3 20 >,
- < 1881600000 0x404c1462 0x00004e4e 0x3 21 >,
- < 1958400000 0x404c1566 0x00005252 0x3 22 >;
+ < 1267200000 0x40340c42 0x00003535 0x1 13 >,
+ < 1344000000 0x40340d46 0x00003838 0x1 14 >,
+ < 1420800000 0x40340e4a 0x00003b3b 0x1 15 >,
+ < 1497600000 0x403c0f4e 0x00003e3e 0x1 16 >,
+ < 1574400000 0x403c1052 0x00004242 0x1 17 >,
+ < 1651200000 0x403c1156 0x00004545 0x1 18 >,
+ < 1728000000 0x4044125a 0x00004848 0x1 19 >,
+ < 1804800000 0x4044135e 0x00004b4b 0x1 20 >,
+ < 1881600000 0x404c1462 0x00004e4e 0x1 21 >,
+ < 1958400000 0x404c1566 0x00005252 0x1 22 >;
qcom,perfcl-speedbin1-v0 =
< 300000000 0x000c000f 0x00002020 0x1 1 >,
@@ -1283,18 +1293,18 @@
< 1036800000 0x40240936 0x00002b2b 0x1 10 >,
< 1113600000 0x402c0a3a 0x00002e2e 0x1 11 >,
< 1190400000 0x402c0b3e 0x00003232 0x1 12 >,
- < 1267200000 0x40340c42 0x00003535 0x2 13 >,
- < 1344000000 0x40340d46 0x00003838 0x2 14 >,
- < 1420800000 0x40340e4a 0x00003b3b 0x2 15 >,
- < 1497600000 0x403c0f4e 0x00003e3e 0x2 16 >,
- < 1574400000 0x403c1052 0x00004242 0x2 17 >,
- < 1651200000 0x403c1156 0x00004545 0x2 18 >,
- < 1728000000 0x4044125a 0x00004848 0x3 19 >,
- < 1804800000 0x4044135e 0x00004b4b 0x3 20 >,
- < 1881600000 0x404c1462 0x00004e4e 0x3 21 >,
- < 1958400000 0x404c1566 0x00005252 0x3 22 >,
- < 2035200000 0x404c166a 0x00005555 0x3 23 >,
- < 2092800000 0x4054176d 0x00005757 0x3 24 >;
+ < 1267200000 0x40340c42 0x00003535 0x1 13 >,
+ < 1344000000 0x40340d46 0x00003838 0x1 14 >,
+ < 1420800000 0x40340e4a 0x00003b3b 0x1 15 >,
+ < 1497600000 0x403c0f4e 0x00003e3e 0x1 16 >,
+ < 1574400000 0x403c1052 0x00004242 0x1 17 >,
+ < 1651200000 0x403c1156 0x00004545 0x1 18 >,
+ < 1728000000 0x4044125a 0x00004848 0x1 19 >,
+ < 1804800000 0x4044135e 0x00004b4b 0x1 20 >,
+ < 1881600000 0x404c1462 0x00004e4e 0x1 21 >,
+ < 1958400000 0x404c1566 0x00005252 0x1 22 >,
+ < 2035200000 0x404c166a 0x00005555 0x1 23 >,
+ < 2092800000 0x4054176d 0x00005757 0x1 24 >;
qcom,perfcl-speedbin2-v0 =
< 300000000 0x000c000f 0x00002020 0x1 1 >,
@@ -1309,26 +1319,36 @@
< 1036800000 0x40240936 0x00002b2b 0x1 10 >,
< 1113600000 0x402c0a3a 0x00002e2e 0x1 11 >,
< 1190400000 0x402c0b3e 0x00003232 0x1 12 >,
- < 1267200000 0x40340c42 0x00003535 0x2 13 >,
- < 1344000000 0x40340d46 0x00003838 0x2 14 >,
- < 1420800000 0x40340e4a 0x00003b3b 0x2 15 >,
- < 1497600000 0x403c0f4e 0x00003e3e 0x2 16 >,
- < 1574400000 0x403c1052 0x00004242 0x2 17 >,
- < 1651200000 0x403c1156 0x00004545 0x2 18 >,
- < 1728000000 0x4044125a 0x00004848 0x3 19 >,
- < 1804800000 0x4044135e 0x00004b4b 0x3 20 >,
- < 1881600000 0x404c1462 0x00004e4e 0x3 21 >,
- < 1958400000 0x404c1566 0x00005252 0x3 22 >,
- < 2035200000 0x404c166a 0x00005555 0x3 23 >,
- < 2112000000 0x4054176e 0x00005858 0x3 24 >,
- < 2208000000 0x40541873 0x00005c5c 0x3 25 >;
+ < 1267200000 0x40340c42 0x00003535 0x1 13 >,
+ < 1344000000 0x40340d46 0x00003838 0x1 14 >,
+ < 1420800000 0x40340e4a 0x00003b3b 0x1 15 >,
+ < 1497600000 0x403c0f4e 0x00003e3e 0x1 16 >,
+ < 1574400000 0x403c1052 0x00004242 0x1 17 >,
+ < 1651200000 0x403c1156 0x00004545 0x1 18 >,
+ < 1728000000 0x4044125a 0x00004848 0x1 19 >,
+ < 1804800000 0x4044135e 0x00004b4b 0x1 20 >,
+ < 1881600000 0x404c1462 0x00004e4e 0x1 21 >,
+ < 1958400000 0x404c1566 0x00005252 0x1 22 >,
+ < 2035200000 0x404c166a 0x00005555 0x1 23 >,
+ < 2112000000 0x4054176e 0x00005858 0x1 24 >,
+ < 2208000000 0x40541873 0x00005c5c 0x1 25 >;
+
+ qcom,l3-memacc-level-vc-bin0 = <7 63>;
+ qcom,l3-memacc-level-vc-bin1 = <7 9>;
+ qcom,l3-memacc-level-vc-bin2 = <7 9>;
+
+ qcom,pwrcl-memacc-level-vc-bin0 = <12 63>;
+ qcom,pwrcl-memacc-level-vc-bin1 = <12 17>;
+ qcom,pwrcl-memacc-level-vc-bin2 = <12 17>;
+
+ qcom,perfcl-memacc-level-vc-bin0 = <12 18>;
+ qcom,perfcl-memacc-level-vc-bin1 = <12 18>;
+ qcom,perfcl-memacc-level-vc-bin2 = <12 18>;
qcom,up-timer =
<1000 1000 1000>;
qcom,down-timer =
<100000 100000 100000>;
- qcom,pc-override-index =
- <0 0 0>;
qcom,set-ret-inactive;
qcom,enable-llm-freq-vote;
qcom,llm-freq-up-timer =
@@ -1392,7 +1412,7 @@
};
clock_aop: qcom,aopclk {
- compatible = "qcom,aop-qmp-clk";
+ compatible = "qcom,aop-qmp-clk-v1";
#clock-cells = <1>;
mboxes = <&qmp_aop 0>;
mbox-names = "qdss_clk";
@@ -1676,13 +1696,18 @@
<81 512 1338562 4096000>,
<1 608 1338562 4096000>;
qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000
- 100000000 200000000 4294967295>;
+ 100750000 200000000 4294967295>;
qcom,sdr104-wa;
qcom,restore-after-cx-collapse;
- qcom,devfreq,freq-table = <50000000 200000000>;
+ qcom,clk-rates = <400000 20000000 25000000
+ 50000000 100000000 201500000>;
+ qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50",
+ "SDR104";
+
+ qcom,devfreq,freq-table = <50000000 201500000>;
clocks = <&clock_gcc GCC_SDCC2_AHB_CLK>,
<&clock_gcc GCC_SDCC2_APPS_CLK>;
clock-names = "iface_clk", "core_clk";
@@ -1966,6 +1991,7 @@
qcom,msm_fastrpc {
compatible = "qcom,msm-fastrpc-compute";
+ qcom,rpc-latency-us = <611>;
qcom,msm_fastrpc_compute_cb1 {
compatible = "qcom,msm-fastrpc-compute-cb";
@@ -2700,6 +2726,13 @@
<&clock_gcc GCC_CE1_AXI_CLK>;
qcom,ce-opp-freq = <171430000>;
qcom,request-bw-before-clk;
+ qcom,smmu-s1-bypass;
+ iommus = <&apps_smmu 0x702 0x1>,
+ <&apps_smmu 0x712 0x1>;
+ };
+
+ qcom_msmhdcp: qcom,msm_hdcp {
+ compatible = "qcom,msm-hdcp";
};
qcom_crypto: qcrypto@1de0000 {
@@ -2734,6 +2767,9 @@
qcom,use-sw-ahash-algo;
qcom,use-sw-aead-algo;
qcom,use-sw-hmac-algo;
+ qcom,smmu-s1-bypass;
+ iommus = <&apps_smmu 0x704 0x3>,
+ <&apps_smmu 0x714 0x3>;
};
qcom,msm_gsi {
@@ -3614,6 +3650,9 @@
&tsif0_sync_active
&tsif1_signals_active
&tsif1_sync_active>; /* dual-tsif-mode2 */
+
+ qcom,smmu-s1-bypass;
+ iommus = <&apps_smmu 0x20 0x0f>;
};
};
@@ -3630,6 +3669,8 @@
interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
qcom,affinity = <1>;
#thermal-sensor-cells = <0>;
+ isens_vref-supply = <&pm8998_l1_ao>;
+ isens-vref-settings = <880000 880000 20000>;
};
wil6210: qcom,wil6210 {
@@ -3764,7 +3805,6 @@
};
#include "pm8998.dtsi"
-#include "pmi8998.dtsi"
#include "pm8005.dtsi"
#include "sdm845-regulator.dtsi"
#include "sdm845-coresight.dtsi"
diff --git a/arch/arm64/configs/sdm670-perf_defconfig b/arch/arm64/configs/sdm670-perf_defconfig
new file mode 100644
index 0000000..1b5eac8
--- /dev/null
+++ b/arch/arm64/configs/sdm670-perf_defconfig
@@ -0,0 +1,579 @@
+CONFIG_LOCALVERSION="-perf"
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_FHANDLE is not set
+CONFIG_AUDIT=y
+# CONFIG_AUDITSYSCALL is not set
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_IRQ_TIME_ACCOUNTING=y
+CONFIG_SCHED_WALT=y
+CONFIG_RCU_EXPERT=y
+CONFIG_RCU_FAST_NO_HZ=y
+CONFIG_RCU_NOCB_CPU=y
+CONFIG_RCU_NOCB_CPU_ALL=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_CPU_MAX_BUF_SHIFT=17
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CPUSETS=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_SCHEDTUNE=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_CGROUP_BPF=y
+CONFIG_SCHED_CORE_CTL=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_SCHED_AUTOGROUP=y
+CONFIG_SCHED_TUNE=y
+CONFIG_DEFAULT_USE_ENERGY_AWARE=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_RD_XZ is not set
+# CONFIG_RD_LZO is not set
+# CONFIG_RD_LZ4 is not set
+CONFIG_KALLSYMS_ALL=y
+CONFIG_BPF_SYSCALL=y
+# CONFIG_AIO is not set
+# CONFIG_MEMBARRIER is not set
+CONFIG_EMBEDDED=y
+# CONFIG_SLUB_DEBUG is not set
+# CONFIG_COMPAT_BRK is not set
+CONFIG_PROFILING=y
+CONFIG_CC_STACKPROTECTOR_STRONG=y
+CONFIG_ARCH_MMAP_RND_COMPAT_BITS=16
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SIG=y
+CONFIG_MODULE_SIG_FORCE=y
+CONFIG_MODULE_SIG_SHA512=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_ARCH_QCOM=y
+CONFIG_ARCH_SDM670=y
+CONFIG_PCI=y
+CONFIG_PCI_MSM=y
+CONFIG_SCHED_MC=y
+CONFIG_NR_CPUS=8
+CONFIG_PREEMPT=y
+CONFIG_HZ_100=y
+CONFIG_CMA=y
+CONFIG_ZSMALLOC=y
+CONFIG_BALANCE_ANON_FILE_RECLAIM=y
+CONFIG_SECCOMP=y
+CONFIG_ARMV8_DEPRECATED=y
+CONFIG_SWP_EMULATION=y
+CONFIG_CP15_BARRIER_EMULATION=y
+CONFIG_SETEND_EMULATION=y
+# CONFIG_ARM64_VHE is not set
+CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_COMPAT=y
+CONFIG_PM_AUTOSLEEP=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+# CONFIG_PM_WAKELOCKS_GC is not set
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_BOOST=y
+CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
+CONFIG_XFRM_STATISTICS=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+CONFIG_INET_IPCOMP=y
+CONFIG_INET_DIAG_DESTROY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_NETFILTER=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_SECMARK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFLOG=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=y
+CONFIG_NETFILTER_XT_TARGET_TEE=y
+CONFIG_NETFILTER_XT_TARGET_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_TRACE=y
+CONFIG_NETFILTER_XT_TARGET_SECMARK=y
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_DSCP=y
+CONFIG_NETFILTER_XT_MATCH_ESP=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+# CONFIG_NETFILTER_XT_MATCH_L2TP is not set
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_RPFILTER=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_SECURITY=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_MATCH_RPFILTER=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+CONFIG_BRIDGE_NF_EBTABLES=y
+CONFIG_BRIDGE_EBT_BROUTE=y
+CONFIG_L2TP=y
+CONFIG_L2TP_V3=y
+CONFIG_L2TP_IP=y
+CONFIG_L2TP_ETH=y
+CONFIG_BRIDGE=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_SCH_MULTIQ=y
+CONFIG_NET_SCH_INGRESS=y
+CONFIG_NET_CLS_FW=y
+CONFIG_NET_CLS_U32=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CMP=y
+CONFIG_NET_EMATCH_NBYTE=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_EMATCH_META=y
+CONFIG_NET_EMATCH_TEXT=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_GACT=y
+CONFIG_NET_ACT_MIRRED=y
+CONFIG_NET_ACT_SKBEDIT=y
+CONFIG_RMNET_DATA=y
+CONFIG_RMNET_DATA_FC=y
+CONFIG_RMNET_DATA_DEBUG_PKT=y
+CONFIG_BT=y
+CONFIG_MSM_BT_POWER=y
+CONFIG_CFG80211=y
+CONFIG_CFG80211_INTERNAL_REGDB=y
+CONFIG_RFKILL=y
+CONFIG_NFC_NQ=y
+CONFIG_IPC_ROUTER=y
+CONFIG_IPC_ROUTER_SECURITY=y
+CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y
+CONFIG_DMA_CMA=y
+CONFIG_ZRAM=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_QSEECOM=y
+CONFIG_MEMORY_STATE_TIME=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_SCSI_UFSHCD=y
+CONFIG_SCSI_UFSHCD_PLATFORM=y
+CONFIG_SCSI_UFS_QCOM=y
+CONFIG_SCSI_UFS_QCOM_ICE=y
+CONFIG_SCSI_UFSHCD_CMD_LOGGING=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_DEBUG=y
+CONFIG_DM_CRYPT=y
+CONFIG_DM_REQ_CRYPT=y
+CONFIG_DM_UEVENT=y
+CONFIG_DM_VERITY=y
+CONFIG_DM_VERITY_FEC=y
+CONFIG_NETDEVICES=y
+CONFIG_BONDING=y
+CONFIG_DUMMY=y
+CONFIG_TUN=y
+CONFIG_SKY2=y
+CONFIG_SMSC911X=y
+CONFIG_PPP=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_MPPE=y
+CONFIG_PPPOLAC=y
+CONFIG_PPPOPNS=y
+CONFIG_USB_USBNET=y
+CONFIG_WIL6210=m
+# CONFIG_WIL6210_TRACING is not set
+CONFIG_WCNSS_MEM_PRE_ALLOC=y
+CONFIG_CLD_LL_CORE=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_KEYBOARD_GPIO=y
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_HBTP_INPUT=y
+CONFIG_INPUT_QPNP_POWER_ON=y
+CONFIG_INPUT_UINPUT=y
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_VT is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_DEVMEM is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_MSM_GENI=y
+CONFIG_DIAG_CHAR=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM_LEGACY=y
+CONFIG_MSM_ADSPRPC=y
+CONFIG_MSM_RDBG=m
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_QCOM_GENI=y
+CONFIG_SOUNDWIRE=y
+CONFIG_SPI=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_QCOM_GENI=y
+CONFIG_SPI_SPIDEV=y
+CONFIG_SLIMBUS_MSM_NGD=y
+CONFIG_SPMI=y
+CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y
+CONFIG_PINCTRL_SDM670=y
+CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_POWER_RESET_QCOM=y
+CONFIG_QCOM_DLOAD_MODE=y
+CONFIG_POWER_RESET_XGENE=y
+CONFIG_POWER_RESET_SYSCON=y
+CONFIG_QPNP_FG_GEN3=y
+CONFIG_SMB1355_SLAVE_CHARGER=y
+CONFIG_QPNP_SMB2=y
+CONFIG_QPNP_QNOVO=y
+CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
+CONFIG_THERMAL=y
+CONFIG_THERMAL_WRITABLE_TRIPS=y
+CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE=y
+CONFIG_THERMAL_GOV_STEP_WISE=y
+CONFIG_THERMAL_GOV_LOW_LIMITS=y
+CONFIG_CPU_THERMAL=y
+CONFIG_DEVFREQ_THERMAL=y
+CONFIG_QCOM_SPMI_TEMP_ALARM=y
+CONFIG_THERMAL_QPNP=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
+CONFIG_THERMAL_TSENS=y
+CONFIG_QTI_THERMAL_LIMITS_DCVS=y
+CONFIG_QTI_VIRTUAL_SENSOR=y
+CONFIG_QTI_AOP_REG_COOLING_DEVICE=y
+CONFIG_QTI_QMI_COOLING_DEVICE=y
+CONFIG_MFD_I2C_PMIC=y
+CONFIG_MFD_SPMI_PMIC=y
+CONFIG_WCD9XXX_CODEC_CORE=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_CPRH_KBSS=y
+CONFIG_REGULATOR_QPNP_LABIBB=y
+CONFIG_REGULATOR_QPNP=y
+CONFIG_REGULATOR_RPMH=y
+CONFIG_REGULATOR_STUB=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_VIDEO_ADV_DEBUG=y
+CONFIG_VIDEO_FIXED_MINOR_RANGES=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_SPECTRA_CAMERA=y
+CONFIG_MSM_VIDC_V4L2=y
+CONFIG_MSM_VIDC_GOVERNORS=y
+CONFIG_MSM_SDE_ROTATOR=y
+CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y
+CONFIG_DVB_MPQ=m
+CONFIG_DVB_MPQ_DEMUX=m
+CONFIG_DVB_MPQ_TSPP1=y
+CONFIG_TSPP=m
+CONFIG_QCOM_KGSL=y
+CONFIG_DRM=y
+CONFIG_DRM_SDE_EVTLOG_DEBUG=y
+CONFIG_DRM_SDE_RSC=y
+CONFIG_FB_VIRTUAL=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_USB_AUDIO=y
+CONFIG_SND_USB_AUDIO_QMI=y
+CONFIG_SND_SOC=y
+CONFIG_UHID=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_ELECOM=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MULTITOUCH=y
+CONFIG_HID_PLANTRONICS=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_HCD_PLATFORM=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PLATFORM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_DWC3=y
+CONFIG_USB_DWC3_MSM=y
+CONFIG_USB_ISP1760=y
+CONFIG_USB_ISP1760_HOST_ROLE=y
+CONFIG_USB_PD_POLICY=y
+CONFIG_QPNP_USB_PDPHY=y
+CONFIG_USB_EHSET_TEST_FIXTURE=y
+CONFIG_NOP_USB_XCEIV=y
+CONFIG_DUAL_ROLE_USB_INTF=y
+CONFIG_USB_MSM_SSPHY_QMP=y
+CONFIG_MSM_QUSB_PHY=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_CONFIGFS=y
+CONFIG_USB_CONFIGFS_NCM=y
+CONFIG_USB_CONFIGFS_MASS_STORAGE=y
+CONFIG_USB_CONFIGFS_F_FS=y
+CONFIG_USB_CONFIGFS_F_MTP=y
+CONFIG_USB_CONFIGFS_F_PTP=y
+CONFIG_USB_CONFIGFS_F_ACC=y
+CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y
+CONFIG_USB_CONFIGFS_UEVENT=y
+CONFIG_USB_CONFIGFS_F_MIDI=y
+CONFIG_USB_CONFIGFS_F_HID=y
+CONFIG_USB_CONFIGFS_F_DIAG=y
+CONFIG_USB_CONFIGFS_F_CDEV=y
+CONFIG_USB_CONFIGFS_F_CCID=y
+CONFIG_USB_CONFIGFS_F_GSI=y
+CONFIG_USB_CONFIGFS_F_QDSS=y
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_BLOCK_DEFERRED_RESUME=y
+CONFIG_MMC_TEST=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_MSM=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_QPNP=y
+CONFIG_LEDS_QPNP_FLASH_V2=y
+CONFIG_LEDS_QPNP_WLED=y
+CONFIG_LEDS_QPNP_HAPTICS=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_QPNP=y
+CONFIG_DMADEVICES=y
+CONFIG_QCOM_GPI_DMA=y
+CONFIG_UIO=y
+CONFIG_UIO_MSM_SHAREDMEM=y
+CONFIG_STAGING=y
+CONFIG_ASHMEM=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_ION=y
+CONFIG_ION_MSM=y
+CONFIG_GSI=y
+CONFIG_IPA3=y
+CONFIG_RMNET_IPA3=y
+CONFIG_RNDIS_IPA=y
+CONFIG_IPA_UT=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_QPNP_COINCELL=y
+CONFIG_QPNP_REVID=y
+CONFIG_USB_BAM=y
+CONFIG_MSM_11AD=m
+CONFIG_SEEMP_CORE=y
+CONFIG_QCOM_GENI_SE=y
+CONFIG_CLOCK_QPNP_DIV=y
+CONFIG_MSM_CLK_RPMH=y
+CONFIG_CLOCK_CPU_OSM=y
+CONFIG_MSM_CLK_AOP_QMP=y
+CONFIG_QCOM_MDSS_PLL=y
+CONFIG_REMOTE_SPINLOCK_MSM=y
+CONFIG_MSM_QMP=y
+CONFIG_IOMMU_IO_PGTABLE_FAST=y
+CONFIG_ARM_SMMU=y
+CONFIG_QCOM_LAZY_MAPPING=y
+CONFIG_IOMMU_DEBUG=y
+CONFIG_IOMMU_DEBUG_TRACKING=y
+CONFIG_IOMMU_TESTS=y
+CONFIG_QCOM_RUN_QUEUE_STATS=y
+CONFIG_QCOM_LLCC=y
+CONFIG_QCOM_SDM670_LLCC=y
+CONFIG_MSM_SERVICE_LOCATOR=y
+CONFIG_MSM_SERVICE_NOTIFIER=y
+CONFIG_MSM_BOOT_STATS=y
+CONFIG_QCOM_EUD=y
+CONFIG_QCOM_WATCHDOG_V2=y
+CONFIG_QCOM_MEMORY_DUMP_V2=y
+CONFIG_QCOM_SECURE_BUFFER=y
+CONFIG_QCOM_EARLY_RANDOM=y
+CONFIG_MSM_SMEM=y
+CONFIG_MSM_GLINK=y
+CONFIG_MSM_GLINK_LOOPBACK_SERVER=y
+CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y
+CONFIG_MSM_GLINK_SPI_XPRT=y
+CONFIG_MSM_SPCOM=y
+CONFIG_MSM_SPSS_UTILS=y
+CONFIG_TRACER_PKT=y
+CONFIG_QTI_RPMH_API=y
+CONFIG_MSM_SMP2P=y
+CONFIG_MSM_SMP2P_TEST=y
+CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y
+CONFIG_MSM_QMI_INTERFACE=y
+CONFIG_MSM_GLINK_PKT=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_PIL=y
+CONFIG_MSM_PIL_SSR_GENERIC=y
+CONFIG_MSM_PIL_MSS_QDSP6V5=y
+CONFIG_ICNSS=y
+CONFIG_QCOM_COMMAND_DB=y
+CONFIG_MSM_PERFORMANCE=y
+CONFIG_MSM_CDSP_LOADER=y
+CONFIG_MSM_EVENT_TIMER=y
+CONFIG_MSM_PM=y
+CONFIG_MSM_QBT1000=y
+CONFIG_APSS_CORE_EA=y
+CONFIG_QTI_RPM_STATS_LOG=y
+CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
+CONFIG_QCOM_BIMC_BWMON=y
+CONFIG_ARM_MEMLAT_MON=y
+CONFIG_QCOMCCI_HWMON=y
+CONFIG_QCOM_M4M_HWMON=y
+CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y
+CONFIG_DEVFREQ_GOV_QCOM_CACHE_HWMON=y
+CONFIG_DEVFREQ_GOV_MEMLAT=y
+CONFIG_DEVFREQ_SIMPLE_DEV=y
+CONFIG_QCOM_DEVFREQ_DEVBW=y
+CONFIG_EXTCON_USB_GPIO=y
+CONFIG_IIO=y
+CONFIG_QCOM_RRADC=y
+CONFIG_PWM=y
+CONFIG_PWM_QPNP=y
+CONFIG_ARM_GIC_V3_ACL=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_SENSORS_SSC=y
+CONFIG_MSM_TZ_LOG=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_QUOTA=y
+CONFIG_QUOTA_NETLINK_INTERFACE=y
+CONFIG_QFMT_V2=y
+CONFIG_FUSE_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_ECRYPT_FS=y
+CONFIG_ECRYPT_FS_MESSAGING=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_INFO=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_SCHEDSTATS=y
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_IPC_LOGGING=y
+CONFIG_CPU_FREQ_SWITCH_PROFILER=y
+CONFIG_DEBUG_ALIGN_RODATA=y
+CONFIG_CORESIGHT=y
+CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y
+CONFIG_CORESIGHT_QCOM_REPLICATOR=y
+CONFIG_CORESIGHT_STM=y
+CONFIG_CORESIGHT_TPDA=y
+CONFIG_CORESIGHT_TPDM=y
+CONFIG_CORESIGHT_CTI=y
+CONFIG_CORESIGHT_HWEVENT=y
+CONFIG_CORESIGHT_DUMMY=y
+CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
+CONFIG_SECURITY=y
+CONFIG_HARDENED_USERCOPY=y
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SMACK=y
+CONFIG_CRYPTO_XCBC=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_ANSI_CPRNG=y
+CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y
+CONFIG_CRYPTO_DEV_QCRYPTO=y
+CONFIG_CRYPTO_DEV_QCEDEV=y
+CONFIG_CRYPTO_DEV_QCOM_ICE=y
+CONFIG_ARM64_CRYPTO=y
+CONFIG_CRYPTO_SHA1_ARM64_CE=y
+CONFIG_CRYPTO_SHA2_ARM64_CE=y
+CONFIG_CRYPTO_GHASH_ARM64_CE=y
+CONFIG_CRYPTO_AES_ARM64_CE_CCM=y
+CONFIG_CRYPTO_AES_ARM64_CE_BLK=y
+CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y
+CONFIG_CRYPTO_CRC32_ARM64=y
+CONFIG_QMI_ENCDEC=y
diff --git a/arch/arm64/configs/sdm670_defconfig b/arch/arm64/configs/sdm670_defconfig
index b8f115b..e2c6474 100644
--- a/arch/arm64/configs/sdm670_defconfig
+++ b/arch/arm64/configs/sdm670_defconfig
@@ -329,6 +329,7 @@
CONFIG_MSM_BCL_PERIPHERAL_CTL=y
CONFIG_QTI_THERMAL_LIMITS_DCVS=y
CONFIG_QTI_VIRTUAL_SENSOR=y
+CONFIG_QTI_AOP_REG_COOLING_DEVICE=y
CONFIG_MFD_I2C_PMIC=y
CONFIG_MFD_SPMI_PMIC=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
@@ -508,10 +509,10 @@
CONFIG_MSM_EVENT_TIMER=y
CONFIG_MSM_PM=y
CONFIG_MSM_QBT1000=y
-CONFIG_APSS_CORE_EA=y
CONFIG_QCOM_DCC_V2=y
CONFIG_QTI_RPM_STATS_LOG=y
CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
+CONFIG_QMP_DEBUGFS_CLIENT=y
CONFIG_QCOM_BIMC_BWMON=y
CONFIG_ARM_MEMLAT_MON=y
CONFIG_QCOMCCI_HWMON=y
diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig
index 5872f88..ff696dd 100644
--- a/arch/arm64/configs/sdm845-perf_defconfig
+++ b/arch/arm64/configs/sdm845-perf_defconfig
@@ -51,7 +51,6 @@
CONFIG_PARTITION_ADVANCED=y
CONFIG_ARCH_QCOM=y
CONFIG_ARCH_SDM845=y
-CONFIG_ARCH_SDM670=y
CONFIG_PCI=y
CONFIG_PCI_MSM=y
CONFIG_SCHED_MC=y
@@ -309,7 +308,6 @@
CONFIG_SPMI=y
CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y
CONFIG_PINCTRL_SDM845=y
-CONFIG_PINCTRL_SDM670=y
CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_SYSFS=y
@@ -336,15 +334,18 @@
CONFIG_MSM_BCL_PERIPHERAL_CTL=y
CONFIG_QTI_THERMAL_LIMITS_DCVS=y
CONFIG_QTI_VIRTUAL_SENSOR=y
-CONFIG_QTI_REG_COOLING_DEVICE=y
+CONFIG_QTI_AOP_REG_COOLING_DEVICE=y
CONFIG_QTI_QMI_COOLING_DEVICE=y
+CONFIG_REGULATOR_COOLING_DEVICE=y
CONFIG_MFD_I2C_PMIC=y
CONFIG_MFD_SPMI_PMIC=y
CONFIG_WCD9XXX_CODEC_CORE=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_PROXY_CONSUMER=y
CONFIG_REGULATOR_CPRH_KBSS=y
CONFIG_REGULATOR_QPNP_LABIBB=y
CONFIG_REGULATOR_QPNP=y
+CONFIG_REGULATOR_REFGEN=y
CONFIG_REGULATOR_RPMH=y
CONFIG_REGULATOR_STUB=y
CONFIG_MEDIA_SUPPORT=y
@@ -403,6 +404,7 @@
CONFIG_USB_PD_POLICY=y
CONFIG_QPNP_USB_PDPHY=y
CONFIG_USB_EHSET_TEST_FIXTURE=y
+CONFIG_USB_LINK_LAYER_TEST=y
CONFIG_NOP_USB_XCEIV=y
CONFIG_DUAL_ROLE_USB_INTF=y
CONFIG_USB_MSM_SSPHY_QMP=y
@@ -513,6 +515,7 @@
CONFIG_MSM_GLINK_PKT=y
CONFIG_MSM_SUBSYSTEM_RESTART=y
CONFIG_MSM_PIL=y
+CONFIG_MSM_SYSMON_GLINK_COMM=y
CONFIG_MSM_PIL_SSR_GENERIC=y
CONFIG_MSM_PIL_MSS_QDSP6V5=y
CONFIG_ICNSS=y
@@ -528,6 +531,7 @@
CONFIG_APSS_CORE_EA=y
CONFIG_QTI_RPM_STATS_LOG=y
CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
+CONFIG_QMP_DEBUGFS_CLIENT=y
CONFIG_QCOM_BIMC_BWMON=y
CONFIG_ARM_MEMLAT_MON=y
CONFIG_QCOMCCI_HWMON=y
@@ -583,8 +587,10 @@
CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
CONFIG_SECURITY=y
CONFIG_HARDENED_USERCOPY=y
+CONFIG_FORTIFY_SOURCE=y
CONFIG_SECURITY_SELINUX=y
CONFIG_SECURITY_SMACK=y
+CONFIG_CRYPTO_CTR=y
CONFIG_CRYPTO_XCBC=y
CONFIG_CRYPTO_MD4=y
CONFIG_CRYPTO_TWOFISH=y
diff --git a/arch/arm64/configs/sdm845_defconfig b/arch/arm64/configs/sdm845_defconfig
index 82455e5..a341dd3 100644
--- a/arch/arm64/configs/sdm845_defconfig
+++ b/arch/arm64/configs/sdm845_defconfig
@@ -341,15 +341,18 @@
CONFIG_MSM_BCL_PERIPHERAL_CTL=y
CONFIG_QTI_THERMAL_LIMITS_DCVS=y
CONFIG_QTI_VIRTUAL_SENSOR=y
-CONFIG_QTI_REG_COOLING_DEVICE=y
+CONFIG_QTI_AOP_REG_COOLING_DEVICE=y
CONFIG_QTI_QMI_COOLING_DEVICE=y
+CONFIG_REGULATOR_COOLING_DEVICE=y
CONFIG_MFD_I2C_PMIC=y
CONFIG_MFD_SPMI_PMIC=y
CONFIG_WCD9XXX_CODEC_CORE=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_PROXY_CONSUMER=y
CONFIG_REGULATOR_CPRH_KBSS=y
CONFIG_REGULATOR_QPNP_LABIBB=y
CONFIG_REGULATOR_QPNP=y
+CONFIG_REGULATOR_REFGEN=y
CONFIG_REGULATOR_RPMH=y
CONFIG_REGULATOR_STUB=y
CONFIG_MEDIA_SUPPORT=y
@@ -407,6 +410,7 @@
CONFIG_USB_PD_POLICY=y
CONFIG_QPNP_USB_PDPHY=y
CONFIG_USB_EHSET_TEST_FIXTURE=y
+CONFIG_USB_LINK_LAYER_TEST=y
CONFIG_NOP_USB_XCEIV=y
CONFIG_DUAL_ROLE_USB_INTF=y
CONFIG_USB_MSM_SSPHY_QMP=y
@@ -530,6 +534,7 @@
CONFIG_MSM_GLINK_PKT=y
CONFIG_MSM_SUBSYSTEM_RESTART=y
CONFIG_MSM_PIL=y
+CONFIG_MSM_SYSMON_GLINK_COMM=y
CONFIG_MSM_PIL_SSR_GENERIC=y
CONFIG_MSM_PIL_MSS_QDSP6V5=y
CONFIG_ICNSS=y
@@ -547,6 +552,7 @@
CONFIG_QCOM_DCC_V2=y
CONFIG_QTI_RPM_STATS_LOG=y
CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
+CONFIG_QMP_DEBUGFS_CLIENT=y
CONFIG_QCOM_BIMC_BWMON=y
CONFIG_ARM_MEMLAT_MON=y
CONFIG_QCOMCCI_HWMON=y
@@ -651,8 +657,10 @@
CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
CONFIG_SECURITY=y
CONFIG_HARDENED_USERCOPY=y
+CONFIG_FORTIFY_SOURCE=y
CONFIG_SECURITY_SELINUX=y
CONFIG_SECURITY_SMACK=y
+CONFIG_CRYPTO_CTR=y
CONFIG_CRYPTO_XCBC=y
CONFIG_CRYPTO_MD4=y
CONFIG_CRYPTO_TWOFISH=y
diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h
index a55384f..afa23b0 100644
--- a/arch/arm64/include/asm/elf.h
+++ b/arch/arm64/include/asm/elf.h
@@ -113,12 +113,11 @@
#define ELF_EXEC_PAGESIZE PAGE_SIZE
/*
- * This is the location that an ET_DYN program is loaded if exec'ed. Typical
- * use of this is to invoke "./ld.so someprog" to test out a new version of
- * the loader. We need to make sure that it is out of the way of the program
- * that it will "exec", and that there is sufficient room for the brk.
+ * This is the base location for PIE (ET_DYN with INTERP) loads. On
+ * 64-bit, this is raised to 4GB to leave the entire 32-bit address
+ * space open for things that want to use the area for 32-bit pointers.
*/
-#define ELF_ET_DYN_BASE (2 * TASK_SIZE_64 / 3)
+#define ELF_ET_DYN_BASE 0x100000000UL
#ifndef __ASSEMBLY__
@@ -169,7 +168,8 @@
#ifdef CONFIG_COMPAT
-#define COMPAT_ELF_ET_DYN_BASE (2 * TASK_SIZE_32 / 3)
+/* PIE load location for compat arm. Must match ARM ELF_ET_DYN_BASE. */
+#define COMPAT_ELF_ET_DYN_BASE 0x000400000UL
/* AArch32 registers. */
#define COMPAT_ELF_NGREG 18
diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
index 6d22017..ef305f8 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -47,7 +47,7 @@
* If the page is in the bottom half, we have to use the top half. If
* the page is in the top half, we have to use the bottom half:
*
- * T = __virt_to_phys(__hyp_idmap_text_start)
+ * T = __pa_symbol(__hyp_idmap_text_start)
* if (T & BIT(VA_BITS - 1))
* HYP_VA_MIN = 0 //idmap in upper half
* else
@@ -270,7 +270,7 @@
kvm_flush_dcache_to_poc(page_address(page), PUD_SIZE);
}
-#define kvm_virt_to_phys(x) __virt_to_phys((unsigned long)(x))
+#define kvm_virt_to_phys(x) __pa_symbol(x)
void kvm_set_way_flush(struct kvm_vcpu *vcpu);
void kvm_toggle_cache(struct kvm_vcpu *vcpu, bool was_enabled);
diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h
index 53211a0..5edb6ed 100644
--- a/arch/arm64/include/asm/memory.h
+++ b/arch/arm64/include/asm/memory.h
@@ -204,7 +204,8 @@
#define __pa(x) __virt_to_phys((unsigned long)(x))
#define __va(x) ((void *)__phys_to_virt((phys_addr_t)(x)))
#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT)
-#define virt_to_pfn(x) __phys_to_pfn(__virt_to_phys(x))
+#define virt_to_pfn(x) __phys_to_pfn(__virt_to_phys((unsigned long)(x)))
+#define sym_to_pfn(x) __phys_to_pfn(__pa_symbol(x))
/*
* virt_to_page(k) convert a _valid_ virtual address to struct page *
diff --git a/arch/arm64/include/asm/mmu_context.h b/arch/arm64/include/asm/mmu_context.h
index dc06a33..88025ba 100644
--- a/arch/arm64/include/asm/mmu_context.h
+++ b/arch/arm64/include/asm/mmu_context.h
@@ -51,7 +51,7 @@
*/
static inline void cpu_set_reserved_ttbr0(void)
{
- unsigned long ttbr = virt_to_phys(empty_zero_page);
+ unsigned long ttbr = __pa_symbol(empty_zero_page);
write_sysreg(ttbr, ttbr0_el1);
isb();
@@ -120,7 +120,7 @@
local_flush_tlb_all();
cpu_set_idmap_tcr_t0sz();
- cpu_switch_mm(idmap_pg_dir, &init_mm);
+ cpu_switch_mm(lm_alias(idmap_pg_dir), &init_mm);
}
/*
@@ -135,7 +135,7 @@
phys_addr_t pgd_phys = virt_to_phys(pgd);
- replace_phys = (void *)virt_to_phys(idmap_cpu_replace_ttbr1);
+ replace_phys = (void *)__pa_symbol(idmap_cpu_replace_ttbr1);
cpu_install_idmap();
replace_phys(pgd_phys);
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 3845f33..c05ee84 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -53,7 +53,7 @@
* for zero-mapped memory areas etc..
*/
extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
-#define ZERO_PAGE(vaddr) pfn_to_page(PHYS_PFN(__pa(empty_zero_page)))
+#define ZERO_PAGE(vaddr) phys_to_page(__pa_symbol(empty_zero_page))
#define pte_ERROR(pte) __pte_error(__FILE__, __LINE__, pte_val(pte))
diff --git a/arch/arm64/include/asm/stackprotector.h b/arch/arm64/include/asm/stackprotector.h
index fe5e287..b86a086 100644
--- a/arch/arm64/include/asm/stackprotector.h
+++ b/arch/arm64/include/asm/stackprotector.h
@@ -30,6 +30,7 @@
/* Try to get a semi random initial value. */
get_random_bytes(&canary, sizeof(canary));
canary ^= LINUX_VERSION_CODE;
+ canary &= CANARY_MASK;
current->stack_canary = canary;
__stack_chk_guard = current->stack_canary;
diff --git a/arch/arm64/include/asm/string.h b/arch/arm64/include/asm/string.h
index 2eb714c..d0aa429 100644
--- a/arch/arm64/include/asm/string.h
+++ b/arch/arm64/include/asm/string.h
@@ -63,6 +63,11 @@
#define memcpy(dst, src, len) __memcpy(dst, src, len)
#define memmove(dst, src, len) __memmove(dst, src, len)
#define memset(s, c, n) __memset(s, c, n)
+
+#ifndef __NO_FORTIFY
+#define __NO_FORTIFY /* FORTIFY_SOURCE uses __builtin_memcpy, etc. */
+#endif
+
#endif
#endif
diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h
index 2df5d5f..4d9222a 100644
--- a/arch/arm64/include/asm/uaccess.h
+++ b/arch/arm64/include/asm/uaccess.h
@@ -383,9 +383,9 @@
{
unsigned long res = n;
kasan_check_write(to, n);
+ check_object_size(to, n, false);
if (access_ok(VERIFY_READ, from, n)) {
- check_object_size(to, n, false);
res = __arch_copy_from_user(to, from, n);
}
if (unlikely(res))
@@ -396,9 +396,9 @@
static inline unsigned long __must_check copy_to_user(void __user *to, const void *from, unsigned long n)
{
kasan_check_read(from, n);
+ check_object_size(from, n, true);
if (access_ok(VERIFY_WRITE, to, n)) {
- check_object_size(from, n, true);
n = __arch_copy_to_user(to, from, n);
}
return n;
diff --git a/arch/arm64/kernel/acpi_parking_protocol.c b/arch/arm64/kernel/acpi_parking_protocol.c
index a32b401..1f5655c 100644
--- a/arch/arm64/kernel/acpi_parking_protocol.c
+++ b/arch/arm64/kernel/acpi_parking_protocol.c
@@ -17,6 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/acpi.h>
+#include <linux/mm.h>
#include <linux/types.h>
#include <asm/cpu_ops.h>
@@ -109,7 +110,7 @@
* that read this address need to convert this address to the
* Boot-Loader's endianness before jumping.
*/
- writeq_relaxed(__pa(secondary_entry), &mailbox->entry_point);
+ writeq_relaxed(__pa_symbol(secondary_entry), &mailbox->entry_point);
writel_relaxed(cpu_entry->gic_cpu_id, &mailbox->cpu_id);
arch_send_wakeup_ipi_mask(cpumask_of(cpu));
diff --git a/arch/arm64/kernel/cpu-reset.h b/arch/arm64/kernel/cpu-reset.h
index d4e9ecb..6c2b1b4 100644
--- a/arch/arm64/kernel/cpu-reset.h
+++ b/arch/arm64/kernel/cpu-reset.h
@@ -24,7 +24,7 @@
el2_switch = el2_switch && !is_kernel_in_hyp_mode() &&
is_hyp_mode_available();
- restart = (void *)virt_to_phys(__cpu_soft_restart);
+ restart = (void *)__pa_symbol(__cpu_soft_restart);
cpu_install_idmap();
restart(el2_switch, entry, arg0, arg1, arg2);
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index af5a1e3..0127e1b 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -23,6 +23,7 @@
#include <linux/sort.h>
#include <linux/stop_machine.h>
#include <linux/types.h>
+#include <linux/mm.h>
#include <asm/cpu.h>
#include <asm/cpufeature.h>
#include <asm/cpu_ops.h>
@@ -737,7 +738,7 @@
static bool hyp_offset_low(const struct arm64_cpu_capabilities *entry,
int __unused)
{
- phys_addr_t idmap_addr = virt_to_phys(__hyp_idmap_text_start);
+ phys_addr_t idmap_addr = __pa_symbol(__hyp_idmap_text_start);
/*
* Activate the lower HYP offset only if:
diff --git a/arch/arm64/kernel/hibernate.c b/arch/arm64/kernel/hibernate.c
index d55a7b0..8bed26a 100644
--- a/arch/arm64/kernel/hibernate.c
+++ b/arch/arm64/kernel/hibernate.c
@@ -50,9 +50,6 @@
*/
extern int in_suspend;
-/* Find a symbols alias in the linear map */
-#define LMADDR(x) phys_to_virt(virt_to_phys(x))
-
/* Do we need to reset el2? */
#define el2_reset_needed() (is_hyp_mode_available() && !is_kernel_in_hyp_mode())
@@ -102,8 +99,8 @@
int pfn_is_nosave(unsigned long pfn)
{
- unsigned long nosave_begin_pfn = virt_to_pfn(&__nosave_begin);
- unsigned long nosave_end_pfn = virt_to_pfn(&__nosave_end - 1);
+ unsigned long nosave_begin_pfn = sym_to_pfn(&__nosave_begin);
+ unsigned long nosave_end_pfn = sym_to_pfn(&__nosave_end - 1);
return (pfn >= nosave_begin_pfn) && (pfn <= nosave_end_pfn);
}
@@ -125,12 +122,12 @@
return -EOVERFLOW;
arch_hdr_invariants(&hdr->invariants);
- hdr->ttbr1_el1 = virt_to_phys(swapper_pg_dir);
+ hdr->ttbr1_el1 = __pa_symbol(swapper_pg_dir);
hdr->reenter_kernel = _cpu_resume;
/* We can't use __hyp_get_vectors() because kvm may still be loaded */
if (el2_reset_needed())
- hdr->__hyp_stub_vectors = virt_to_phys(__hyp_stub_vectors);
+ hdr->__hyp_stub_vectors = __pa_symbol(__hyp_stub_vectors);
else
hdr->__hyp_stub_vectors = 0;
@@ -460,7 +457,6 @@
void *zero_page;
size_t exit_size;
pgd_t *tmp_pg_dir;
- void *lm_restore_pblist;
phys_addr_t phys_hibernate_exit;
void __noreturn (*hibernate_exit)(phys_addr_t, phys_addr_t, void *,
void *, phys_addr_t, phys_addr_t);
@@ -481,12 +477,6 @@
goto out;
/*
- * Since we only copied the linear map, we need to find restore_pblist's
- * linear map address.
- */
- lm_restore_pblist = LMADDR(restore_pblist);
-
- /*
* We need a zero page that is zero before & after resume in order to
* to break before make on the ttbr1 page tables.
*/
@@ -537,7 +527,7 @@
}
hibernate_exit(virt_to_phys(tmp_pg_dir), resume_hdr.ttbr1_el1,
- resume_hdr.reenter_kernel, lm_restore_pblist,
+ resume_hdr.reenter_kernel, restore_pblist,
resume_hdr.__hyp_stub_vectors, virt_to_phys(zero_page));
out:
diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c
index 6f2ac4f..f607b38 100644
--- a/arch/arm64/kernel/insn.c
+++ b/arch/arm64/kernel/insn.c
@@ -97,7 +97,7 @@
if (module && IS_ENABLED(CONFIG_DEBUG_SET_MODULE_RONX))
page = vmalloc_to_page(addr);
else if (!module)
- page = pfn_to_page(PHYS_PFN(__pa(addr)));
+ page = phys_to_page(__pa_symbol(addr));
else
return addr;
diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c
index 81762dd..716a5c2 100644
--- a/arch/arm64/kernel/psci.c
+++ b/arch/arm64/kernel/psci.c
@@ -20,6 +20,7 @@
#include <linux/smp.h>
#include <linux/delay.h>
#include <linux/psci.h>
+#include <linux/mm.h>
#include <uapi/linux/psci.h>
@@ -45,7 +46,7 @@
static int cpu_psci_cpu_boot(unsigned int cpu)
{
- int err = psci_ops.cpu_on(cpu_logical_map(cpu), __pa(secondary_entry));
+ int err = psci_ops.cpu_on(cpu_logical_map(cpu), __pa_symbol(secondary_entry));
if (err)
pr_err("failed to boot CPU%d (%d)\n", cpu, err);
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index ae02756..ba29095 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -44,6 +44,7 @@
#include <linux/psci.h>
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
+#include <linux/mm.h>
#include <asm/acpi.h>
#include <asm/fixmap.h>
@@ -212,10 +213,10 @@
struct memblock_region *region;
struct resource *res;
- kernel_code.start = virt_to_phys(_text);
- kernel_code.end = virt_to_phys(__init_begin - 1);
- kernel_data.start = virt_to_phys(_sdata);
- kernel_data.end = virt_to_phys(_end - 1);
+ kernel_code.start = __pa_symbol(_text);
+ kernel_code.end = __pa_symbol(__init_begin - 1);
+ kernel_data.start = __pa_symbol(_sdata);
+ kernel_data.end = __pa_symbol(_end - 1);
for_each_memblock(memory, region) {
res = alloc_bootmem_low(sizeof(*res));
diff --git a/arch/arm64/kernel/smp_spin_table.c b/arch/arm64/kernel/smp_spin_table.c
index 9a00eee..9303465 100644
--- a/arch/arm64/kernel/smp_spin_table.c
+++ b/arch/arm64/kernel/smp_spin_table.c
@@ -21,6 +21,7 @@
#include <linux/of.h>
#include <linux/smp.h>
#include <linux/types.h>
+#include <linux/mm.h>
#include <asm/cacheflush.h>
#include <asm/cpu_ops.h>
@@ -98,7 +99,7 @@
* boot-loader's endianess before jumping. This is mandated by
* the boot protocol.
*/
- writeq_relaxed(__pa(secondary_holding_pen), release_addr);
+ writeq_relaxed(__pa_symbol(secondary_holding_pen), release_addr);
__flush_dcache_area((__force void *)release_addr,
sizeof(*release_addr));
diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c
index 4bcfe01..ef3bdfd 100644
--- a/arch/arm64/kernel/vdso.c
+++ b/arch/arm64/kernel/vdso.c
@@ -37,7 +37,7 @@
#include <asm/vdso.h>
#include <asm/vdso_datapage.h>
-extern char vdso_start, vdso_end;
+extern char vdso_start[], vdso_end[];
static unsigned long vdso_pages __ro_after_init;
/*
@@ -123,15 +123,16 @@
{
int i;
struct page **vdso_pagelist;
+ unsigned long pfn;
- if (memcmp(&vdso_start, "\177ELF", 4)) {
+ if (memcmp(vdso_start, "\177ELF", 4)) {
pr_err("vDSO is not a valid ELF object!\n");
return -EINVAL;
}
- vdso_pages = (&vdso_end - &vdso_start) >> PAGE_SHIFT;
+ vdso_pages = (vdso_end - vdso_start) >> PAGE_SHIFT;
pr_info("vdso: %ld pages (%ld code @ %p, %ld data @ %p)\n",
- vdso_pages + 1, vdso_pages, &vdso_start, 1L, vdso_data);
+ vdso_pages + 1, vdso_pages, vdso_start, 1L, vdso_data);
/* Allocate the vDSO pagelist, plus a page for the data. */
vdso_pagelist = kcalloc(vdso_pages + 1, sizeof(struct page *),
@@ -140,11 +141,14 @@
return -ENOMEM;
/* Grab the vDSO data page. */
- vdso_pagelist[0] = pfn_to_page(PHYS_PFN(__pa(vdso_data)));
+ vdso_pagelist[0] = phys_to_page(__pa_symbol(vdso_data));
+
/* Grab the vDSO code pages. */
+ pfn = sym_to_pfn(vdso_start);
+
for (i = 0; i < vdso_pages; i++)
- vdso_pagelist[i + 1] = pfn_to_page(PHYS_PFN(__pa(&vdso_start)) + i);
+ vdso_pagelist[i + 1] = pfn_to_page(pfn + i);
vdso_spec[0].pages = &vdso_pagelist[0];
vdso_spec[1].pages = &vdso_pagelist[1];
diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
index acbe515..7f90b7e 100644
--- a/arch/arm64/mm/dma-mapping.c
+++ b/arch/arm64/mm/dma-mapping.c
@@ -157,12 +157,13 @@
dma_addr_t *dma_handle, gfp_t flags,
unsigned long attrs)
{
+ void *addr;
+
if (IS_ENABLED(CONFIG_ZONE_DMA) &&
dev->coherent_dma_mask <= DMA_BIT_MASK(32))
flags |= GFP_DMA;
if (dev_get_cma_area(dev) && gfpflags_allow_blocking(flags)) {
struct page *page;
- void *addr;
page = dma_alloc_from_contiguous(dev, size >> PAGE_SHIFT,
get_order(size));
@@ -172,20 +173,20 @@
*dma_handle = phys_to_dma(dev, page_to_phys(page));
addr = page_address(page);
memset(addr, 0, size);
-
- if ((attrs & DMA_ATTR_NO_KERNEL_MAPPING) ||
- (attrs & DMA_ATTR_STRONGLY_ORDERED)) {
- /*
- * flush the caches here because we can't later
- */
- __dma_flush_area(addr, size);
- __dma_remap(page, size, __pgprot(0), true);
- }
-
- return addr;
} else {
- return swiotlb_alloc_coherent(dev, size, dma_handle, flags);
+ addr = swiotlb_alloc_coherent(dev, size, dma_handle, flags);
}
+
+ if (addr && ((attrs & DMA_ATTR_NO_KERNEL_MAPPING) ||
+ (attrs & DMA_ATTR_STRONGLY_ORDERED))) {
+ /*
+ * flush the caches here because we can't later
+ */
+ __dma_flush_area(addr, size);
+ __dma_remap(virt_to_page(addr), size, __pgprot(0), true);
+ }
+
+ return addr;
}
static void __dma_free_coherent(struct device *dev, size_t size,
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index 0b9492e..f8ef496 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -36,6 +36,7 @@
#include <linux/efi.h>
#include <linux/swiotlb.h>
#include <linux/vmalloc.h>
+#include <linux/mm.h>
#include <asm/boot.h>
#include <asm/fixmap.h>
@@ -211,8 +212,8 @@
* linear mapping. Take care not to clip the kernel which may be
* high in memory.
*/
- memblock_remove(max_t(u64, memstart_addr + linear_region_size, __pa(_end)),
- ULLONG_MAX);
+ memblock_remove(max_t(u64, memstart_addr + linear_region_size,
+ __pa_symbol(_end)), ULLONG_MAX);
if (memstart_addr + linear_region_size < memblock_end_of_DRAM()) {
/* ensure that memstart_addr remains sufficiently aligned */
memstart_addr = round_up(memblock_end_of_DRAM() - linear_region_size,
@@ -227,7 +228,7 @@
*/
if (memory_limit != (phys_addr_t)ULLONG_MAX) {
memblock_mem_limit_remove_map(memory_limit);
- memblock_add(__pa(_text), (u64)(_end - _text));
+ memblock_add(__pa_symbol(_text), (u64)(_end - _text));
}
if (IS_ENABLED(CONFIG_BLK_DEV_INITRD) && initrd_start) {
@@ -280,7 +281,7 @@
* Register the kernel text, kernel data, initrd, and initial
* pagetables with memblock.
*/
- memblock_reserve(__pa(_text), _end - _text);
+ memblock_reserve(__pa_symbol(_text), _end - _text);
#ifdef CONFIG_BLK_DEV_INITRD
if (initrd_start) {
memblock_reserve(initrd_start, initrd_end - initrd_start);
@@ -488,7 +489,8 @@
void free_initmem(void)
{
- free_reserved_area(__va(__pa(__init_begin)), __va(__pa(__init_end)),
+ free_reserved_area(lm_alias(__init_begin),
+ lm_alias(__init_end),
0, "unused kernel");
/*
* Unmap the __init region but leave the VM area in place. This
diff --git a/arch/arm64/mm/kasan_init.c b/arch/arm64/mm/kasan_init.c
index 757009d..201d918 100644
--- a/arch/arm64/mm/kasan_init.c
+++ b/arch/arm64/mm/kasan_init.c
@@ -15,6 +15,7 @@
#include <linux/kernel.h>
#include <linux/memblock.h>
#include <linux/start_kernel.h>
+#include <linux/mm.h>
#include <asm/mmu_context.h>
#include <asm/kernel-pgtable.h>
@@ -26,6 +27,13 @@
static pgd_t tmp_pg_dir[PTRS_PER_PGD] __initdata __aligned(PGD_SIZE);
+/*
+ * The p*d_populate functions call virt_to_phys implicitly so they can't be used
+ * directly on kernel symbols (bm_p*d). All the early functions are called too
+ * early to use lm_alias so __p*d_populate functions must be used to populate
+ * with the physical address from __pa_symbol.
+ */
+
static void __init kasan_early_pte_populate(pmd_t *pmd, unsigned long addr,
unsigned long end)
{
@@ -33,12 +41,12 @@
unsigned long next;
if (pmd_none(*pmd))
- pmd_populate_kernel(&init_mm, pmd, kasan_zero_pte);
+ __pmd_populate(pmd, __pa_symbol(kasan_zero_pte), PMD_TYPE_TABLE);
pte = pte_offset_kimg(pmd, addr);
do {
next = addr + PAGE_SIZE;
- set_pte(pte, pfn_pte(virt_to_pfn(kasan_zero_page),
+ set_pte(pte, pfn_pte(sym_to_pfn(kasan_zero_page),
PAGE_KERNEL));
} while (pte++, addr = next, addr != end && pte_none(*pte));
}
@@ -51,7 +59,7 @@
unsigned long next;
if (pud_none(*pud))
- pud_populate(&init_mm, pud, kasan_zero_pmd);
+ __pud_populate(pud, __pa_symbol(kasan_zero_pmd), PMD_TYPE_TABLE);
pmd = pmd_offset_kimg(pud, addr);
do {
@@ -68,7 +76,7 @@
unsigned long next;
if (pgd_none(*pgd))
- pgd_populate(&init_mm, pgd, kasan_zero_pud);
+ __pgd_populate(pgd, __pa_symbol(kasan_zero_pud), PUD_TYPE_TABLE);
pud = pud_offset_kimg(pgd, addr);
do {
@@ -148,7 +156,7 @@
*/
memcpy(tmp_pg_dir, swapper_pg_dir, sizeof(tmp_pg_dir));
dsb(ishst);
- cpu_replace_ttbr1(tmp_pg_dir);
+ cpu_replace_ttbr1(lm_alias(tmp_pg_dir));
clear_pgds(KASAN_SHADOW_START, KASAN_SHADOW_END);
@@ -199,10 +207,10 @@
*/
for (i = 0; i < PTRS_PER_PTE; i++)
set_pte(&kasan_zero_pte[i],
- pfn_pte(virt_to_pfn(kasan_zero_page), PAGE_KERNEL_RO));
+ pfn_pte(sym_to_pfn(kasan_zero_page), PAGE_KERNEL_RO));
memset(kasan_zero_page, 0, PAGE_SIZE);
- cpu_replace_ttbr1(swapper_pg_dir);
+ cpu_replace_ttbr1(lm_alias(swapper_pg_dir));
/* At this point kasan is fully initialized. Enable error messages */
init_task.kasan_depth = 0;
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index f70b433..41efd5e 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -32,6 +32,7 @@
#include <linux/stop_machine.h>
#include <linux/dma-contiguous.h>
#include <linux/cma.h>
+#include <linux/mm.h>
#include <asm/barrier.h>
#include <asm/cputype.h>
@@ -357,8 +358,8 @@
static void __init __map_memblock(pgd_t *pgd, phys_addr_t start, phys_addr_t end)
{
- unsigned long kernel_start = __pa(_text);
- unsigned long kernel_end = __pa(__init_begin);
+ unsigned long kernel_start = __pa_symbol(_text);
+ unsigned long kernel_end = __pa_symbol(__init_begin);
/*
* Take care not to create a writable alias for the
@@ -425,21 +426,21 @@
unsigned long section_size;
section_size = (unsigned long)_etext - (unsigned long)_text;
- create_mapping_late(__pa(_text), (unsigned long)_text,
+ create_mapping_late(__pa_symbol(_text), (unsigned long)_text,
section_size, PAGE_KERNEL_ROX);
/*
* mark .rodata as read only. Use __init_begin rather than __end_rodata
* to cover NOTES and EXCEPTION_TABLE.
*/
section_size = (unsigned long)__init_begin - (unsigned long)__start_rodata;
- create_mapping_late(__pa(__start_rodata), (unsigned long)__start_rodata,
+ create_mapping_late(__pa_symbol(__start_rodata), (unsigned long)__start_rodata,
section_size, PAGE_KERNEL_RO);
}
static void __init map_kernel_segment(pgd_t *pgd, void *va_start, void *va_end,
pgprot_t prot, struct vm_struct *vma)
{
- phys_addr_t pa_start = __pa(va_start);
+ phys_addr_t pa_start = __pa_symbol(va_start);
unsigned long size = va_end - va_start;
BUG_ON(!PAGE_ALIGNED(pa_start));
@@ -487,7 +488,7 @@
*/
BUG_ON(!IS_ENABLED(CONFIG_ARM64_16K_PAGES));
set_pud(pud_set_fixmap_offset(pgd, FIXADDR_START),
- __pud(__pa(bm_pmd) | PUD_TYPE_TABLE));
+ __pud(__pa_symbol(bm_pmd) | PUD_TYPE_TABLE));
pud_clear_fixmap();
} else {
BUG();
@@ -518,7 +519,7 @@
*/
cpu_replace_ttbr1(__va(pgd_phys));
memcpy(swapper_pg_dir, pgd, PAGE_SIZE);
- cpu_replace_ttbr1(swapper_pg_dir);
+ cpu_replace_ttbr1(lm_alias(swapper_pg_dir));
pgd_clear_fixmap();
memblock_free(pgd_phys, PAGE_SIZE);
@@ -527,7 +528,7 @@
* We only reuse the PGD from the swapper_pg_dir, not the pud + pmd
* allocated with it.
*/
- memblock_free(__pa(swapper_pg_dir) + PAGE_SIZE,
+ memblock_free(__pa_symbol(swapper_pg_dir) + PAGE_SIZE,
SWAPPER_DIR_SIZE - PAGE_SIZE);
}
@@ -638,6 +639,12 @@
return &bm_pte[pte_index(addr)];
}
+/*
+ * The p*d_populate functions call virt_to_phys implicitly so they can't be used
+ * directly on kernel symbols (bm_p*d). This function is called too early to use
+ * lm_alias so __p*d_populate functions must be used to populate with the
+ * physical address from __pa_symbol.
+ */
void __init early_fixmap_init(void)
{
pgd_t *pgd;
@@ -647,7 +654,7 @@
pgd = pgd_offset_k(addr);
if (CONFIG_PGTABLE_LEVELS > 3 &&
- !(pgd_none(*pgd) || pgd_page_paddr(*pgd) == __pa(bm_pud))) {
+ !(pgd_none(*pgd) || pgd_page_paddr(*pgd) == __pa_symbol(bm_pud))) {
/*
* We only end up here if the kernel mapping and the fixmap
* share the top level pgd entry, which should only happen on
@@ -656,12 +663,14 @@
BUG_ON(!IS_ENABLED(CONFIG_ARM64_16K_PAGES));
pud = pud_offset_kimg(pgd, addr);
} else {
- pgd_populate(&init_mm, pgd, bm_pud);
+ if (pgd_none(*pgd))
+ __pgd_populate(pgd, __pa_symbol(bm_pud), PUD_TYPE_TABLE);
pud = fixmap_pud(addr);
}
- pud_populate(&init_mm, pud, bm_pmd);
+ if (pud_none(*pud))
+ __pud_populate(pud, __pa_symbol(bm_pmd), PMD_TYPE_TABLE);
pmd = fixmap_pmd(addr);
- pmd_populate_kernel(&init_mm, pmd, bm_pte);
+ __pmd_populate(pmd, __pa_symbol(bm_pte), PMD_TYPE_TABLE);
/*
* The boot-ioremap range spans multiple pmds, for which
diff --git a/arch/mips/include/asm/branch.h b/arch/mips/include/asm/branch.h
index de781cf..da80878 100644
--- a/arch/mips/include/asm/branch.h
+++ b/arch/mips/include/asm/branch.h
@@ -74,10 +74,7 @@
return __microMIPS_compute_return_epc(regs);
if (cpu_has_mips16)
return __MIPS16e_compute_return_epc(regs);
- return regs->cp0_epc;
- }
-
- if (!delay_slot(regs)) {
+ } else if (!delay_slot(regs)) {
regs->cp0_epc += 4;
return 0;
}
diff --git a/arch/mips/kernel/branch.c b/arch/mips/kernel/branch.c
index c86b66b..c3f2fb3 100644
--- a/arch/mips/kernel/branch.c
+++ b/arch/mips/kernel/branch.c
@@ -399,7 +399,7 @@
*
* @regs: Pointer to pt_regs
* @insn: branch instruction to decode
- * @returns: -EFAULT on error and forces SIGBUS, and on success
+ * @returns: -EFAULT on error and forces SIGILL, and on success
* returns 0 or BRANCH_LIKELY_TAKEN as appropriate after
* evaluating the branch.
*
@@ -431,7 +431,7 @@
/* Fall through */
case jr_op:
if (NO_R6EMU && insn.r_format.func == jr_op)
- goto sigill_r6;
+ goto sigill_r2r6;
regs->cp0_epc = regs->regs[insn.r_format.rs];
break;
}
@@ -446,7 +446,7 @@
switch (insn.i_format.rt) {
case bltzl_op:
if (NO_R6EMU)
- goto sigill_r6;
+ goto sigill_r2r6;
case bltz_op:
if ((long)regs->regs[insn.i_format.rs] < 0) {
epc = epc + 4 + (insn.i_format.simmediate << 2);
@@ -459,7 +459,7 @@
case bgezl_op:
if (NO_R6EMU)
- goto sigill_r6;
+ goto sigill_r2r6;
case bgez_op:
if ((long)regs->regs[insn.i_format.rs] >= 0) {
epc = epc + 4 + (insn.i_format.simmediate << 2);
@@ -473,10 +473,8 @@
case bltzal_op:
case bltzall_op:
if (NO_R6EMU && (insn.i_format.rs ||
- insn.i_format.rt == bltzall_op)) {
- ret = -SIGILL;
- break;
- }
+ insn.i_format.rt == bltzall_op))
+ goto sigill_r2r6;
regs->regs[31] = epc + 8;
/*
* OK we are here either because we hit a NAL
@@ -507,10 +505,8 @@
case bgezal_op:
case bgezall_op:
if (NO_R6EMU && (insn.i_format.rs ||
- insn.i_format.rt == bgezall_op)) {
- ret = -SIGILL;
- break;
- }
+ insn.i_format.rt == bgezall_op))
+ goto sigill_r2r6;
regs->regs[31] = epc + 8;
/*
* OK we are here either because we hit a BAL
@@ -556,6 +552,7 @@
/*
* These are unconditional and in j_format.
*/
+ case jalx_op:
case jal_op:
regs->regs[31] = regs->cp0_epc + 8;
case j_op:
@@ -573,7 +570,7 @@
*/
case beql_op:
if (NO_R6EMU)
- goto sigill_r6;
+ goto sigill_r2r6;
case beq_op:
if (regs->regs[insn.i_format.rs] ==
regs->regs[insn.i_format.rt]) {
@@ -587,7 +584,7 @@
case bnel_op:
if (NO_R6EMU)
- goto sigill_r6;
+ goto sigill_r2r6;
case bne_op:
if (regs->regs[insn.i_format.rs] !=
regs->regs[insn.i_format.rt]) {
@@ -601,7 +598,7 @@
case blezl_op: /* not really i_format */
if (!insn.i_format.rt && NO_R6EMU)
- goto sigill_r6;
+ goto sigill_r2r6;
case blez_op:
/*
* Compact branches for R6 for the
@@ -636,7 +633,7 @@
case bgtzl_op:
if (!insn.i_format.rt && NO_R6EMU)
- goto sigill_r6;
+ goto sigill_r2r6;
case bgtz_op:
/*
* Compact branches for R6 for the
@@ -774,35 +771,27 @@
#else
case bc6_op:
/* Only valid for MIPS R6 */
- if (!cpu_has_mips_r6) {
- ret = -SIGILL;
- break;
- }
+ if (!cpu_has_mips_r6)
+ goto sigill_r6;
regs->cp0_epc += 8;
break;
case balc6_op:
- if (!cpu_has_mips_r6) {
- ret = -SIGILL;
- break;
- }
+ if (!cpu_has_mips_r6)
+ goto sigill_r6;
/* Compact branch: BALC */
regs->regs[31] = epc + 4;
epc += 4 + (insn.i_format.simmediate << 2);
regs->cp0_epc = epc;
break;
case pop66_op:
- if (!cpu_has_mips_r6) {
- ret = -SIGILL;
- break;
- }
+ if (!cpu_has_mips_r6)
+ goto sigill_r6;
/* Compact branch: BEQZC || JIC */
regs->cp0_epc += 8;
break;
case pop76_op:
- if (!cpu_has_mips_r6) {
- ret = -SIGILL;
- break;
- }
+ if (!cpu_has_mips_r6)
+ goto sigill_r6;
/* Compact branch: BNEZC || JIALC */
if (!insn.i_format.rs) {
/* JIALC: set $31/ra */
@@ -814,10 +803,8 @@
case pop10_op:
case pop30_op:
/* Only valid for MIPS R6 */
- if (!cpu_has_mips_r6) {
- ret = -SIGILL;
- break;
- }
+ if (!cpu_has_mips_r6)
+ goto sigill_r6;
/*
* Compact branches:
* bovc, beqc, beqzalc, bnvc, bnec, bnezlac
@@ -831,11 +818,17 @@
return ret;
sigill_dsp:
- printk("%s: DSP branch but not DSP ASE - sending SIGBUS.\n", current->comm);
- force_sig(SIGBUS, current);
+ pr_info("%s: DSP branch but not DSP ASE - sending SIGILL.\n",
+ current->comm);
+ force_sig(SIGILL, current);
+ return -EFAULT;
+sigill_r2r6:
+ pr_info("%s: R2 branch but r2-to-r6 emulator is not present - sending SIGILL.\n",
+ current->comm);
+ force_sig(SIGILL, current);
return -EFAULT;
sigill_r6:
- pr_info("%s: R2 branch but r2-to-r6 emulator is not preset - sending SIGILL.\n",
+ pr_info("%s: R6 branch but no MIPSr6 ISA support - sending SIGILL.\n",
current->comm);
force_sig(SIGILL, current);
return -EFAULT;
diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c
index 4eff2ae..4c01ee5 100644
--- a/arch/mips/kernel/proc.c
+++ b/arch/mips/kernel/proc.c
@@ -83,7 +83,7 @@
}
seq_printf(m, "isa\t\t\t:");
- if (cpu_has_mips_r1)
+ if (cpu_has_mips_1)
seq_printf(m, " mips1");
if (cpu_has_mips_2)
seq_printf(m, "%s", " mips2");
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index bf83dc1..3de0260 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -924,7 +924,7 @@
audit_syscall_exit(regs);
if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
- trace_sys_exit(regs, regs->regs[2]);
+ trace_sys_exit(regs, regs_return_value(regs));
if (test_thread_flag(TIF_SYSCALL_TRACE))
tracehook_report_syscall_exit(regs, 0);
diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S
index c29d397..e6be1f62 100644
--- a/arch/mips/kernel/scall32-o32.S
+++ b/arch/mips/kernel/scall32-o32.S
@@ -371,7 +371,7 @@
PTR sys_writev
PTR sys_cacheflush
PTR sys_cachectl
- PTR sys_sysmips
+ PTR __sys_sysmips
PTR sys_ni_syscall /* 4150 */
PTR sys_getsid
PTR sys_fdatasync
diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S
index 0687f96..aa27daf 100644
--- a/arch/mips/kernel/scall64-64.S
+++ b/arch/mips/kernel/scall64-64.S
@@ -311,7 +311,7 @@
PTR sys_sched_getaffinity
PTR sys_cacheflush
PTR sys_cachectl
- PTR sys_sysmips
+ PTR __sys_sysmips
PTR sys_io_setup /* 5200 */
PTR sys_io_destroy
PTR sys_io_getevents
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index 0331ba3..37f608f 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -302,7 +302,7 @@
PTR compat_sys_sched_getaffinity
PTR sys_cacheflush
PTR sys_cachectl
- PTR sys_sysmips
+ PTR __sys_sysmips
PTR compat_sys_io_setup /* 6200 */
PTR sys_io_destroy
PTR compat_sys_io_getevents
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
index 5a47042..7913a5c 100644
--- a/arch/mips/kernel/scall64-o32.S
+++ b/arch/mips/kernel/scall64-o32.S
@@ -371,7 +371,7 @@
PTR compat_sys_writev
PTR sys_cacheflush
PTR sys_cachectl
- PTR sys_sysmips
+ PTR __sys_sysmips
PTR sys_ni_syscall /* 4150 */
PTR sys_getsid
PTR sys_fdatasync
diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c
index 53a7ef9..4234b2d 100644
--- a/arch/mips/kernel/syscall.c
+++ b/arch/mips/kernel/syscall.c
@@ -28,6 +28,7 @@
#include <linux/elf.h>
#include <asm/asm.h>
+#include <asm/asm-eva.h>
#include <asm/branch.h>
#include <asm/cachectl.h>
#include <asm/cacheflush.h>
@@ -138,10 +139,12 @@
__asm__ __volatile__ (
" .set "MIPS_ISA_ARCH_LEVEL" \n"
" li %[err], 0 \n"
- "1: ll %[old], (%[addr]) \n"
+ "1: \n"
+ user_ll("%[old]", "(%[addr])")
" move %[tmp], %[new] \n"
- "2: sc %[tmp], (%[addr]) \n"
- " bnez %[tmp], 4f \n"
+ "2: \n"
+ user_sc("%[tmp]", "(%[addr])")
+ " beqz %[tmp], 4f \n"
"3: \n"
" .insn \n"
" .subsection 2 \n"
@@ -199,6 +202,12 @@
unreachable();
}
+/*
+ * mips_atomic_set() normally returns directly via syscall_exit potentially
+ * clobbering static registers, so be sure to preserve them.
+ */
+save_static_function(sys_sysmips);
+
SYSCALL_DEFINE3(sysmips, long, cmd, long, arg1, long, arg2)
{
switch (cmd) {
diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c
index f8b7bf8..e9385bc 100644
--- a/arch/mips/math-emu/cp1emu.c
+++ b/arch/mips/math-emu/cp1emu.c
@@ -2522,6 +2522,35 @@
return 0;
}
+/*
+ * Emulate FPU instructions.
+ *
+ * If we use FPU hardware, then we have been typically called to handle
+ * an unimplemented operation, such as where an operand is a NaN or
+ * denormalized. In that case exit the emulation loop after a single
+ * iteration so as to let hardware execute any subsequent instructions.
+ *
+ * If we have no FPU hardware or it has been disabled, then continue
+ * emulating floating-point instructions until one of these conditions
+ * has occurred:
+ *
+ * - a non-FPU instruction has been encountered,
+ *
+ * - an attempt to emulate has ended with a signal,
+ *
+ * - the ISA mode has been switched.
+ *
+ * We need to terminate the emulation loop if we got switched to the
+ * MIPS16 mode, whether supported or not, so that we do not attempt
+ * to emulate a MIPS16 instruction as a regular MIPS FPU instruction.
+ * Similarly if we got switched to the microMIPS mode and only the
+ * regular MIPS mode is supported, so that we do not attempt to emulate
+ * a microMIPS instruction as a regular MIPS FPU instruction. Or if
+ * we got switched to the regular MIPS mode and only the microMIPS mode
+ * is supported, so that we do not attempt to emulate a regular MIPS
+ * instruction that should cause an Address Error exception instead.
+ * For simplicity we always terminate upon an ISA mode switch.
+ */
int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
int has_fpu, void *__user *fault_addr)
{
@@ -2607,6 +2636,15 @@
break;
if (sig)
break;
+ /*
+ * We have to check for the ISA bit explicitly here,
+ * because `get_isa16_mode' may return 0 if support
+ * for code compression has been globally disabled,
+ * or otherwise we may produce the wrong signal or
+ * even proceed successfully where we must not.
+ */
+ if ((xcp->cp0_epc ^ prevepc) & 0x1)
+ break;
cond_resched();
} while (xcp->cp0_epc > prevepc);
diff --git a/arch/parisc/include/asm/dma-mapping.h b/arch/parisc/include/asm/dma-mapping.h
index 16e0246..cb7697d 100644
--- a/arch/parisc/include/asm/dma-mapping.h
+++ b/arch/parisc/include/asm/dma-mapping.h
@@ -20,6 +20,8 @@
** flush/purge and allocate "regular" cacheable pages for everything.
*/
+#define DMA_ERROR_CODE (~(dma_addr_t)0)
+
#ifdef CONFIG_PA11
extern struct dma_map_ops pcxl_dma_ops;
extern struct dma_map_ops pcx_dma_ops;
@@ -54,12 +56,13 @@
break;
}
}
- BUG_ON(!dev->platform_data);
return dev->platform_data;
}
-
-#define GET_IOC(dev) (HBA_DATA(parisc_walk_tree(dev))->iommu)
-
+
+#define GET_IOC(dev) ({ \
+ void *__pdata = parisc_walk_tree(dev); \
+ __pdata ? HBA_DATA(__pdata)->iommu : NULL; \
+})
#ifdef CONFIG_IOMMU_CCIO
struct parisc_device;
diff --git a/arch/parisc/include/asm/mmu_context.h b/arch/parisc/include/asm/mmu_context.h
index 59be257..a812262 100644
--- a/arch/parisc/include/asm/mmu_context.h
+++ b/arch/parisc/include/asm/mmu_context.h
@@ -49,15 +49,26 @@
mtctl(__space_to_prot(context), 8);
}
-static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk)
+static inline void switch_mm_irqs_off(struct mm_struct *prev,
+ struct mm_struct *next, struct task_struct *tsk)
{
-
if (prev != next) {
mtctl(__pa(next->pgd), 25);
load_context(next->context);
}
}
+static inline void switch_mm(struct mm_struct *prev,
+ struct mm_struct *next, struct task_struct *tsk)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ switch_mm_irqs_off(prev, next, tsk);
+ local_irq_restore(flags);
+}
+#define switch_mm_irqs_off switch_mm_irqs_off
+
#define deactivate_mm(tsk,mm) do { } while (0)
static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next)
diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S
index 3cfef1d..8ec2ff8 100644
--- a/arch/parisc/kernel/syscall_table.S
+++ b/arch/parisc/kernel/syscall_table.S
@@ -361,7 +361,7 @@
ENTRY_SAME(ni_syscall) /* 263: reserved for vserver */
ENTRY_SAME(add_key)
ENTRY_SAME(request_key) /* 265 */
- ENTRY_SAME(keyctl)
+ ENTRY_COMP(keyctl)
ENTRY_SAME(ioprio_set)
ENTRY_SAME(ioprio_get)
ENTRY_SAME(inotify_init)
diff --git a/arch/parisc/mm/fault.c b/arch/parisc/mm/fault.c
index 040c48f..b6f3b5e 100644
--- a/arch/parisc/mm/fault.c
+++ b/arch/parisc/mm/fault.c
@@ -366,7 +366,7 @@
case 15: /* Data TLB miss fault/Data page fault */
/* send SIGSEGV when outside of vma */
if (!vma ||
- address < vma->vm_start || address > vma->vm_end) {
+ address < vma->vm_start || address >= vma->vm_end) {
si.si_signo = SIGSEGV;
si.si_code = SEGV_MAPERR;
break;
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 8f01f21..b4758f5 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -84,6 +84,7 @@
select ARCH_MIGHT_HAVE_PC_SERIO
select BINFMT_ELF
select ARCH_HAS_ELF_RANDOMIZE
+ select ARCH_HAS_FORTIFY_SOURCE
select OF
select OF_EARLY_FLATTREE
select OF_RESERVED_MEM
diff --git a/arch/powerpc/include/asm/atomic.h b/arch/powerpc/include/asm/atomic.h
index 2b90335..a2cc801 100644
--- a/arch/powerpc/include/asm/atomic.h
+++ b/arch/powerpc/include/asm/atomic.h
@@ -560,7 +560,7 @@
* Atomically increments @v by 1, so long as @v is non-zero.
* Returns non-zero if @v was non-zero, and zero otherwise.
*/
-static __inline__ long atomic64_inc_not_zero(atomic64_t *v)
+static __inline__ int atomic64_inc_not_zero(atomic64_t *v)
{
long t1, t2;
@@ -579,7 +579,7 @@
: "r" (&v->counter)
: "cc", "xer", "memory");
- return t1;
+ return t1 != 0;
}
#endif /* __powerpc64__ */
diff --git a/arch/powerpc/include/asm/elf.h b/arch/powerpc/include/asm/elf.h
index ee46ffe..743ad7a 100644
--- a/arch/powerpc/include/asm/elf.h
+++ b/arch/powerpc/include/asm/elf.h
@@ -23,12 +23,13 @@
#define CORE_DUMP_USE_REGSET
#define ELF_EXEC_PAGESIZE PAGE_SIZE
-/* This is the location that an ET_DYN program is loaded if exec'ed. Typical
- use of this is to invoke "./ld.so someprog" to test out a new version of
- the loader. We need to make sure that it is out of the way of the program
- that it will "exec", and that there is sufficient room for the brk. */
-
-#define ELF_ET_DYN_BASE 0x20000000
+/*
+ * This is the base location for PIE (ET_DYN with INTERP) loads. On
+ * 64-bit, this is raised to 4GB to leave the entire 32-bit address
+ * space open for things that want to use the area for 32-bit pointers.
+ */
+#define ELF_ET_DYN_BASE (is_32bit_task() ? 0x000400000UL : \
+ 0x100000000UL)
#define ELF_CORE_EFLAGS (is_elf2_task() ? 2 : 0)
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index e7d9eca..ceb168c 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -1283,7 +1283,7 @@
" .llong 0\n" \
".previous" \
: "=r" (rval) \
- : "i" (CPU_FTR_CELL_TB_BUG), "i" (SPRN_TBRL)); \
+ : "i" (CPU_FTR_CELL_TB_BUG), "i" (SPRN_TBRL) : "cr0"); \
rval;})
#else
#define mftb() ({unsigned long rval; \
diff --git a/arch/powerpc/kvm/book3s_hv_builtin.c b/arch/powerpc/kvm/book3s_hv_builtin.c
index 0c84d6b..7e2af42 100644
--- a/arch/powerpc/kvm/book3s_hv_builtin.c
+++ b/arch/powerpc/kvm/book3s_hv_builtin.c
@@ -97,7 +97,8 @@
(unsigned long)selected_size / SZ_1M);
align_size = HPT_ALIGN_PAGES << PAGE_SHIFT;
cma_declare_contiguous(0, selected_size, 0, align_size,
- KVM_CMA_CHUNK_ORDER - PAGE_SHIFT, false, &kvm_cma);
+ KVM_CMA_CHUNK_ORDER - PAGE_SHIFT, false, "kvm_cma",
+ &kvm_cma);
}
}
diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c
index 6ca3b90..776c1a1 100644
--- a/arch/powerpc/lib/sstep.c
+++ b/arch/powerpc/lib/sstep.c
@@ -687,8 +687,10 @@
case 19:
switch ((instr >> 1) & 0x3ff) {
case 0: /* mcrf */
- rd = (instr >> 21) & 0x1c;
- ra = (instr >> 16) & 0x1c;
+ rd = 7 - ((instr >> 23) & 0x7);
+ ra = 7 - ((instr >> 18) & 0x7);
+ rd *= 4;
+ ra *= 4;
val = (regs->ccr >> ra) & 0xf;
regs->ccr = (regs->ccr & ~(0xfUL << rd)) | (val << rd);
goto instr_done;
@@ -968,6 +970,19 @@
#endif
case 19: /* mfcr */
+ if ((instr >> 20) & 1) {
+ imm = 0xf0000000UL;
+ for (sh = 0; sh < 8; ++sh) {
+ if (instr & (0x80000 >> sh)) {
+ regs->gpr[rd] = regs->ccr & imm;
+ break;
+ }
+ imm >>= 4;
+ }
+
+ goto instr_done;
+ }
+
regs->gpr[rd] = regs->ccr;
regs->gpr[rd] &= 0xffffffffUL;
goto instr_done;
diff --git a/arch/powerpc/mm/mmu_context_book3s64.c b/arch/powerpc/mm/mmu_context_book3s64.c
index 73bf6e1..a006f82 100644
--- a/arch/powerpc/mm/mmu_context_book3s64.c
+++ b/arch/powerpc/mm/mmu_context_book3s64.c
@@ -167,9 +167,15 @@
mm->context.cop_lockp = NULL;
#endif /* CONFIG_PPC_ICSWX */
- if (radix_enabled())
- process_tb[mm->context.id].prtb1 = 0;
- else
+ if (radix_enabled()) {
+ /*
+ * Radix doesn't have a valid bit in the process table
+ * entries. However we know that at least P9 implementation
+ * will avoid caching an entry with an invalid RTS field,
+ * and 0 is invalid. So this will do.
+ */
+ process_tb[mm->context.id].prtb0 = 0;
+ } else
subpage_prot_free(mm);
destroy_pagetable_page(mm);
__destroy_context(mm->context.id);
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c
index f2c98f6..a7bb872 100644
--- a/arch/powerpc/platforms/pseries/lpar.c
+++ b/arch/powerpc/platforms/pseries/lpar.c
@@ -279,7 +279,7 @@
int ssize, unsigned long inv_flags)
{
unsigned long lpar_rc;
- unsigned long flags = (newpp & 7) | H_AVPN;
+ unsigned long flags;
unsigned long want_v;
want_v = hpte_encode_avpn(vpn, psize, ssize);
@@ -287,6 +287,11 @@
pr_devel(" update: avpnv=%016lx, hash=%016lx, f=%lx, psize: %d ...",
want_v, slot, flags, psize);
+ flags = (newpp & 7) | H_AVPN;
+ if (mmu_has_feature(MMU_FTR_KERNEL_RO))
+ /* Move pp0 into bit 8 (IBM 55) */
+ flags |= (newpp & HPTE_R_PP0) >> 55;
+
lpar_rc = plpar_pte_protect(flags, slot, want_v);
if (lpar_rc == H_NOT_FOUND) {
@@ -358,6 +363,10 @@
BUG_ON(slot == -1);
flags = newpp & 7;
+ if (mmu_has_feature(MMU_FTR_KERNEL_RO))
+ /* Move pp0 into bit 8 (IBM 55) */
+ flags |= (newpp & HPTE_R_PP0) >> 55;
+
lpar_rc = plpar_pte_protect(flags, slot, 0);
BUG_ON(lpar_rc != H_SUCCESS);
diff --git a/arch/s390/include/asm/elf.h b/arch/s390/include/asm/elf.h
index 1736c7d..8d665f1 100644
--- a/arch/s390/include/asm/elf.h
+++ b/arch/s390/include/asm/elf.h
@@ -158,14 +158,13 @@
#define CORE_DUMP_USE_REGSET
#define ELF_EXEC_PAGESIZE 4096
-/* This is the location that an ET_DYN program is loaded if exec'ed. Typical
- use of this is to invoke "./ld.so someprog" to test out a new version of
- the loader. We need to make sure that it is out of the way of the program
- that it will "exec", and that there is sufficient room for the brk. 64-bit
- tasks are aligned to 4GB. */
-#define ELF_ET_DYN_BASE (is_compat_task() ? \
- (STACK_TOP / 3 * 2) : \
- (STACK_TOP / 3 * 2) & ~((1UL << 32) - 1))
+/*
+ * This is the base location for PIE (ET_DYN with INTERP) loads. On
+ * 64-bit, this is raised to 4GB to leave the entire 32-bit address
+ * space open for things that want to use the area for 32-bit pointers.
+ */
+#define ELF_ET_DYN_BASE (is_compat_task() ? 0x000400000UL : \
+ 0x100000000UL)
/* This yields a mask that user programs can use to figure out what
instruction set this CPU supports. */
diff --git a/arch/s390/include/asm/syscall.h b/arch/s390/include/asm/syscall.h
index 6ba0bf9..6bc941b 100644
--- a/arch/s390/include/asm/syscall.h
+++ b/arch/s390/include/asm/syscall.h
@@ -64,6 +64,12 @@
{
unsigned long mask = -1UL;
+ /*
+ * No arguments for this syscall, there's nothing to do.
+ */
+ if (!n)
+ return;
+
BUG_ON(i + n > 6);
#ifdef CONFIG_COMPAT
if (test_tsk_thread_flag(task, TIF_31BIT))
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index bada636..3735222 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -26,6 +26,7 @@
select ARCH_HAS_DEVMEM_IS_ALLOWED
select ARCH_HAS_ELF_RANDOMIZE
select ARCH_HAS_FAST_MULTIPLIER
+ select ARCH_HAS_FORTIFY_SOURCE
select ARCH_HAS_GCOV_PROFILE_ALL
select ARCH_HAS_GIGANTIC_PAGE if X86_64
select ARCH_HAS_KCOV if X86_64
diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c
index c945acd..5955954 100644
--- a/arch/x86/boot/compressed/misc.c
+++ b/arch/x86/boot/compressed/misc.c
@@ -409,3 +409,8 @@
debug_putstr("done.\nBooting the kernel.\n");
return output;
}
+
+void fortify_panic(const char *name)
+{
+ error("detected buffer overflow");
+}
diff --git a/arch/x86/crypto/sha1_ssse3_glue.c b/arch/x86/crypto/sha1_ssse3_glue.c
index fc61739..f960a04 100644
--- a/arch/x86/crypto/sha1_ssse3_glue.c
+++ b/arch/x86/crypto/sha1_ssse3_glue.c
@@ -201,7 +201,7 @@
static bool avx2_usable(void)
{
- if (avx_usable() && boot_cpu_has(X86_FEATURE_AVX2)
+ if (false && avx_usable() && boot_cpu_has(X86_FEATURE_AVX2)
&& boot_cpu_has(X86_FEATURE_BMI1)
&& boot_cpu_has(X86_FEATURE_BMI2))
return true;
diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h
index 94aad63..c152db2 100644
--- a/arch/x86/include/asm/elf.h
+++ b/arch/x86/include/asm/elf.h
@@ -245,12 +245,13 @@
#define CORE_DUMP_USE_REGSET
#define ELF_EXEC_PAGESIZE 4096
-/* This is the location that an ET_DYN program is loaded if exec'ed. Typical
- use of this is to invoke "./ld.so someprog" to test out a new version of
- the loader. We need to make sure that it is out of the way of the program
- that it will "exec", and that there is sufficient room for the brk. */
-
-#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2)
+/*
+ * This is the base location for PIE (ET_DYN with INTERP) loads. On
+ * 64-bit, this is raised to 4GB to leave the entire 32-bit address
+ * space open for things that want to use the area for 32-bit pointers.
+ */
+#define ELF_ET_DYN_BASE (mmap_is_ia32() ? 0x000400000UL : \
+ 0x100000000UL)
/* This yields a mask that user programs can use to figure out what
instruction set this CPU supports. This could be done in user space,
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index 78f3760..b601dda 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -405,6 +405,8 @@
#define MSR_IA32_TSC_ADJUST 0x0000003b
#define MSR_IA32_BNDCFGS 0x00000d90
+#define MSR_IA32_BNDCFGS_RSVD 0x00000ffc
+
#define MSR_IA32_XSS 0x00000da0
#define FEATURE_CONTROL_LOCKED (1<<0)
diff --git a/arch/x86/include/asm/string_32.h b/arch/x86/include/asm/string_32.h
index 3d3e835..e9ee848 100644
--- a/arch/x86/include/asm/string_32.h
+++ b/arch/x86/include/asm/string_32.h
@@ -142,7 +142,9 @@
}
#define __HAVE_ARCH_MEMCPY
+extern void *memcpy(void *, const void *, size_t);
+#ifndef CONFIG_FORTIFY_SOURCE
#ifdef CONFIG_X86_USE_3DNOW
#include <asm/mmx.h>
@@ -195,11 +197,15 @@
#endif
#endif
+#endif /* !CONFIG_FORTIFY_SOURCE */
#define __HAVE_ARCH_MEMMOVE
void *memmove(void *dest, const void *src, size_t n);
+extern int memcmp(const void *, const void *, size_t);
+#ifndef CONFIG_FORTIFY_SOURCE
#define memcmp __builtin_memcmp
+#endif
#define __HAVE_ARCH_MEMCHR
extern void *memchr(const void *cs, int c, size_t count);
@@ -321,6 +327,8 @@
: __memset_generic((s), (c), (count)))
#define __HAVE_ARCH_MEMSET
+extern void *memset(void *, int, size_t);
+#ifndef CONFIG_FORTIFY_SOURCE
#if (__GNUC__ >= 4)
#define memset(s, c, count) __builtin_memset(s, c, count)
#else
@@ -330,6 +338,7 @@
(count)) \
: __memset((s), (c), (count)))
#endif
+#endif /* !CONFIG_FORTIFY_SOURCE */
/*
* find the first occurrence of byte 'c', or 1 past the area if none
diff --git a/arch/x86/include/asm/string_64.h b/arch/x86/include/asm/string_64.h
index a164862..f942deb 100644
--- a/arch/x86/include/asm/string_64.h
+++ b/arch/x86/include/asm/string_64.h
@@ -31,6 +31,7 @@
extern void *memcpy(void *to, const void *from, size_t len);
extern void *__memcpy(void *to, const void *from, size_t len);
+#ifndef CONFIG_FORTIFY_SOURCE
#ifndef CONFIG_KMEMCHECK
#if (__GNUC__ == 4 && __GNUC_MINOR__ < 3) || __GNUC__ < 4
#define memcpy(dst, src, len) \
@@ -51,6 +52,7 @@
*/
#define memcpy(dst, src, len) __inline_memcpy((dst), (src), (len))
#endif
+#endif /* !CONFIG_FORTIFY_SOURCE */
#define __HAVE_ARCH_MEMSET
void *memset(void *s, int c, size_t n);
@@ -77,6 +79,11 @@
#define memcpy(dst, src, len) __memcpy(dst, src, len)
#define memmove(dst, src, len) __memmove(dst, src, len)
#define memset(s, c, n) __memset(s, c, n)
+
+#ifndef __NO_FORTIFY
+#define __NO_FORTIFY /* FORTIFY_SOURCE uses __builtin_memcpy, etc. */
+#endif
+
#endif
__must_check int memcpy_mcsafe_unrolled(void *dst, const void *src, size_t cnt);
diff --git a/arch/x86/include/asm/xen/hypercall.h b/arch/x86/include/asm/xen/hypercall.h
index a12a047..8b678af 100644
--- a/arch/x86/include/asm/xen/hypercall.h
+++ b/arch/x86/include/asm/xen/hypercall.h
@@ -43,6 +43,7 @@
#include <asm/page.h>
#include <asm/pgtable.h>
+#include <asm/smap.h>
#include <xen/interface/xen.h>
#include <xen/interface/sched.h>
@@ -214,10 +215,12 @@
__HYPERCALL_DECLS;
__HYPERCALL_5ARG(a1, a2, a3, a4, a5);
+ stac();
asm volatile("call *%[call]"
: __HYPERCALL_5PARAM
: [call] "a" (&hypercall_page[call])
: __HYPERCALL_CLOBBER5);
+ clac();
return (long)__res;
}
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index 931ced8..d3e0d04 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -338,6 +338,14 @@
struct mpc_intsrc mp_irq;
/*
+ * Check bus_irq boundary.
+ */
+ if (bus_irq >= NR_IRQS_LEGACY) {
+ pr_warn("Invalid bus_irq %u for legacy override\n", bus_irq);
+ return;
+ }
+
+ /*
* Convert 'gsi' to 'ioapic.pin'.
*/
ioapic = mp_find_ioapic(gsi);
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index 7249f15..cf89928 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -2116,7 +2116,7 @@
int idx;
idx = find_irq_entry(apic1, pin1, mp_INT);
if (idx != -1 && irq_trigger(idx))
- unmask_ioapic_irq(irq_get_chip_data(0));
+ unmask_ioapic_irq(irq_get_irq_data(0));
}
irq_domain_deactivate_irq(irq_data);
irq_domain_activate_irq(irq_data);
diff --git a/arch/x86/kvm/cpuid.h b/arch/x86/kvm/cpuid.h
index 35058c2..9368fec 100644
--- a/arch/x86/kvm/cpuid.h
+++ b/arch/x86/kvm/cpuid.h
@@ -144,6 +144,14 @@
return best && (best->ebx & bit(X86_FEATURE_RTM));
}
+static inline bool guest_cpuid_has_mpx(struct kvm_vcpu *vcpu)
+{
+ struct kvm_cpuid_entry2 *best;
+
+ best = kvm_find_cpuid_entry(vcpu, 7, 0);
+ return best && (best->ebx & bit(X86_FEATURE_MPX));
+}
+
static inline bool guest_cpuid_has_rdtscp(struct kvm_vcpu *vcpu)
{
struct kvm_cpuid_entry2 *best;
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 04e6bbb..3dc6d80 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -2987,7 +2987,8 @@
msr_info->data = vmcs_readl(GUEST_SYSENTER_ESP);
break;
case MSR_IA32_BNDCFGS:
- if (!kvm_mpx_supported())
+ if (!kvm_mpx_supported() ||
+ (!msr_info->host_initiated && !guest_cpuid_has_mpx(vcpu)))
return 1;
msr_info->data = vmcs_read64(GUEST_BNDCFGS);
break;
@@ -3069,7 +3070,11 @@
vmcs_writel(GUEST_SYSENTER_ESP, data);
break;
case MSR_IA32_BNDCFGS:
- if (!kvm_mpx_supported())
+ if (!kvm_mpx_supported() ||
+ (!msr_info->host_initiated && !guest_cpuid_has_mpx(vcpu)))
+ return 1;
+ if (is_noncanonical_address(data & PAGE_MASK) ||
+ (data & MSR_IA32_BNDCFGS_RSVD))
return 1;
vmcs_write64(GUEST_BNDCFGS, data);
break;
@@ -6474,7 +6479,6 @@
vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_CS, false);
vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_ESP, false);
vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_EIP, false);
- vmx_disable_intercept_for_msr(MSR_IA32_BNDCFGS, true);
memcpy(vmx_msr_bitmap_legacy_x2apic,
vmx_msr_bitmap_legacy, PAGE_SIZE);
diff --git a/arch/x86/lib/memcpy_32.c b/arch/x86/lib/memcpy_32.c
index cad1263..2eab7d0 100644
--- a/arch/x86/lib/memcpy_32.c
+++ b/arch/x86/lib/memcpy_32.c
@@ -6,7 +6,7 @@
__visible void *memcpy(void *to, const void *from, size_t n)
{
-#ifdef CONFIG_X86_USE_3DNOW
+#if defined(CONFIG_X86_USE_3DNOW) && !defined(CONFIG_FORTIFY_SOURCE)
return __memcpy3d(to, from, n);
#else
return __memcpy(to, from, n);
diff --git a/arch/x86/pci/fixup.c b/arch/x86/pci/fixup.c
index 6d52b94..20fa7c8 100644
--- a/arch/x86/pci/fixup.c
+++ b/arch/x86/pci/fixup.c
@@ -571,3 +571,35 @@
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6f60, pci_invalid_bar);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6fa0, pci_invalid_bar);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6fc0, pci_invalid_bar);
+
+/*
+ * Apple MacBook Pro: Avoid [mem 0x7fa00000-0x7fbfffff]
+ *
+ * Using the [mem 0x7fa00000-0x7fbfffff] region, e.g., by assigning it to
+ * the 00:1c.0 Root Port, causes a conflict with [io 0x1804], which is used
+ * for soft poweroff and suspend-to-RAM.
+ *
+ * As far as we know, this is related to the address space, not to the Root
+ * Port itself. Attaching the quirk to the Root Port is a convenience, but
+ * it could probably also be a standalone DMI quirk.
+ *
+ * https://bugzilla.kernel.org/show_bug.cgi?id=103211
+ */
+static void quirk_apple_mbp_poweroff(struct pci_dev *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+
+ if ((!dmi_match(DMI_PRODUCT_NAME, "MacBookPro11,4") &&
+ !dmi_match(DMI_PRODUCT_NAME, "MacBookPro11,5")) ||
+ pdev->bus->number != 0 || pdev->devfn != PCI_DEVFN(0x1c, 0))
+ return;
+
+ res = request_mem_region(0x7fa00000, 0x200000,
+ "MacBook Pro poweroff workaround");
+ if (res)
+ dev_info(dev, "claimed %s %pR\n", res->name, res);
+ else
+ dev_info(dev, "can't work around MacBook Pro poweroff issue\n");
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x8c10, quirk_apple_mbp_poweroff);
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 22ca892..79152db 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -147,7 +147,7 @@
module_param(ec_storm_threshold, uint, 0644);
MODULE_PARM_DESC(ec_storm_threshold, "Maxim false GPE numbers not considered as GPE storm");
-static bool ec_freeze_events __read_mostly = true;
+static bool ec_freeze_events __read_mostly = false;
module_param(ec_freeze_events, bool, 0644);
MODULE_PARM_DESC(ec_freeze_events, "Disabling event handling during suspend/resume");
@@ -1865,24 +1865,6 @@
}
#ifdef CONFIG_PM_SLEEP
-static int acpi_ec_suspend_noirq(struct device *dev)
-{
- struct acpi_ec *ec =
- acpi_driver_data(to_acpi_device(dev));
-
- acpi_ec_enter_noirq(ec);
- return 0;
-}
-
-static int acpi_ec_resume_noirq(struct device *dev)
-{
- struct acpi_ec *ec =
- acpi_driver_data(to_acpi_device(dev));
-
- acpi_ec_leave_noirq(ec);
- return 0;
-}
-
static int acpi_ec_suspend(struct device *dev)
{
struct acpi_ec *ec =
@@ -1904,7 +1886,6 @@
#endif
static const struct dev_pm_ops acpi_ec_pm = {
- SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(acpi_ec_suspend_noirq, acpi_ec_resume_noirq)
SET_SYSTEM_SLEEP_PM_OPS(acpi_ec_suspend, acpi_ec_resume)
};
diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c
index 9ef3941..f3bc901 100644
--- a/drivers/acpi/nfit/core.c
+++ b/drivers/acpi/nfit/core.c
@@ -2945,6 +2945,8 @@
static __init int nfit_init(void)
{
+ int ret;
+
BUILD_BUG_ON(sizeof(struct acpi_table_nfit) != 40);
BUILD_BUG_ON(sizeof(struct acpi_nfit_system_address) != 56);
BUILD_BUG_ON(sizeof(struct acpi_nfit_memory_map) != 48);
@@ -2972,8 +2974,14 @@
return -ENOMEM;
nfit_mce_register();
+ ret = acpi_bus_register_driver(&acpi_nfit_driver);
+ if (ret) {
+ nfit_mce_unregister();
+ destroy_workqueue(nfit_wq);
+ }
- return acpi_bus_register_driver(&acpi_nfit_driver);
+ return ret;
+
}
static __exit void nfit_exit(void)
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index b351c85..632c814 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -28,10 +28,10 @@
* binder_node_lock() and binder_node_unlock() are
* used to acq/rel
* 3) proc->inner_lock : protects the thread and node lists
- * (proc->threads, proc->nodes) and all todo lists associated
- * with the binder_proc (proc->todo, thread->todo,
- * proc->delivered_death and node->async_todo), as well as
- * thread->transaction_stack
+ * (proc->threads, proc->waiting_threads, proc->nodes)
+ * and all todo lists associated with the binder_proc
+ * (proc->todo, thread->todo, proc->delivered_death and
+ * node->async_todo), as well as thread->transaction_stack
* binder_inner_proc_lock() and binder_inner_proc_unlock()
* are used to acq/rel
*
@@ -352,10 +352,14 @@
* and by @lock)
* @has_async_transaction: async transaction to node in progress
* (protected by @lock)
+ * @sched_policy: minimum scheduling policy for node
+ * (invariant after initialized)
* @accept_fds: file descriptor operations supported for node
* (invariant after initialized)
* @min_priority: minimum scheduling priority
* (invariant after initialized)
+ * @inherit_rt: inherit RT scheduling policy from caller
+ * (invariant after initialized)
* @async_todo: list of async work items
* (protected by @proc->inner_lock)
*
@@ -391,6 +395,8 @@
/*
* invariant after initialization
*/
+ u8 sched_policy:2;
+ u8 inherit_rt:1;
u8 accept_fds:1;
u8 min_priority;
};
@@ -465,6 +471,22 @@
};
/**
+ * struct binder_priority - scheduler policy and priority
+ * @sched_policy scheduler policy
+ * @prio [100..139] for SCHED_NORMAL, [0..99] for FIFO/RT
+ *
+ * The binder driver supports inheriting the following scheduler policies:
+ * SCHED_NORMAL
+ * SCHED_BATCH
+ * SCHED_FIFO
+ * SCHED_RR
+ */
+struct binder_priority {
+ unsigned int sched_policy;
+ int prio;
+};
+
+/**
* struct binder_proc - binder process bookkeeping
* @proc_node: element for binder_procs list
* @threads: rbtree of binder_threads in this proc
@@ -476,6 +498,8 @@
* (protected by @outer_lock)
* @refs_by_node: rbtree of refs ordered by ref->node
* (protected by @outer_lock)
+ * @waiting_threads: threads currently waiting for proc work
+ * (protected by @inner_lock)
* @pid PID of group_leader of process
* (invariant after initialized)
* @tsk task_struct for group_leader of process
@@ -505,8 +529,6 @@
* (protected by @inner_lock)
* @requested_threads_started: number binder threads started
* (protected by @inner_lock)
- * @ready_threads: number of threads waiting for proc work
- * (protected by @inner_lock)
* @tmp_ref: temporary reference to indicate proc is in use
* (protected by @inner_lock)
* @default_priority: default scheduler priority
@@ -527,6 +549,7 @@
struct rb_root nodes;
struct rb_root refs_by_desc;
struct rb_root refs_by_node;
+ struct list_head waiting_threads;
int pid;
struct task_struct *tsk;
struct files_struct *files;
@@ -541,9 +564,8 @@
int max_threads;
int requested_threads;
int requested_threads_started;
- int ready_threads;
int tmp_ref;
- long default_priority;
+ struct binder_priority default_priority;
struct dentry *debugfs_entry;
struct binder_alloc alloc;
struct binder_context *context;
@@ -557,6 +579,7 @@
BINDER_LOOPER_STATE_EXITED = 0x04,
BINDER_LOOPER_STATE_INVALID = 0x08,
BINDER_LOOPER_STATE_WAITING = 0x10,
+ BINDER_LOOPER_STATE_POLL = 0x20,
};
/**
@@ -565,6 +588,8 @@
* (invariant after initialization)
* @rb_node: element for proc->threads rbtree
* (protected by @proc->inner_lock)
+ * @waiting_thread_node: element for @proc->waiting_threads list
+ * (protected by @proc->inner_lock)
* @pid: PID for this thread
* (invariant after initialization)
* @looper: bitmap of looping state
@@ -588,12 +613,14 @@
* @is_dead: thread is dead and awaiting free
* when outstanding transactions are cleaned up
* (protected by @proc->inner_lock)
+ * @task: struct task_struct for this thread
*
* Bookkeeping structure for binder threads.
*/
struct binder_thread {
struct binder_proc *proc;
struct rb_node rb_node;
+ struct list_head waiting_thread_node;
int pid;
int looper; /* only modified by this thread */
bool looper_need_return; /* can be written by other thread */
@@ -605,6 +632,7 @@
struct binder_stats stats;
atomic_t tmp_ref;
bool is_dead;
+ struct task_struct *task;
};
struct binder_transaction {
@@ -621,8 +649,9 @@
struct binder_buffer *buffer;
unsigned int code;
unsigned int flags;
- long priority;
- long saved_priority;
+ struct binder_priority priority;
+ struct binder_priority saved_priority;
+ bool set_priority_called;
kuid_t sender_euid;
/**
* @lock: protects @from, @to_proc, and @to_thread
@@ -921,22 +950,271 @@
return retval;
}
-static void binder_set_nice(long nice)
+static bool binder_has_work_ilocked(struct binder_thread *thread,
+ bool do_proc_work)
{
- long min_nice;
+ return !binder_worklist_empty_ilocked(&thread->todo) ||
+ thread->looper_need_return ||
+ (do_proc_work &&
+ !binder_worklist_empty_ilocked(&thread->proc->todo));
+}
- if (can_nice(current, nice)) {
- set_user_nice(current, nice);
+static bool binder_has_work(struct binder_thread *thread, bool do_proc_work)
+{
+ bool has_work;
+
+ binder_inner_proc_lock(thread->proc);
+ has_work = binder_has_work_ilocked(thread, do_proc_work);
+ binder_inner_proc_unlock(thread->proc);
+
+ return has_work;
+}
+
+static bool binder_available_for_proc_work_ilocked(struct binder_thread *thread)
+{
+ return !thread->transaction_stack &&
+ binder_worklist_empty_ilocked(&thread->todo) &&
+ (thread->looper & (BINDER_LOOPER_STATE_ENTERED |
+ BINDER_LOOPER_STATE_REGISTERED));
+}
+
+static void binder_wakeup_poll_threads_ilocked(struct binder_proc *proc,
+ bool sync)
+{
+ struct rb_node *n;
+ struct binder_thread *thread;
+
+ for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) {
+ thread = rb_entry(n, struct binder_thread, rb_node);
+ if (thread->looper & BINDER_LOOPER_STATE_POLL &&
+ binder_available_for_proc_work_ilocked(thread)) {
+ if (sync)
+ wake_up_interruptible_sync(&thread->wait);
+ else
+ wake_up_interruptible(&thread->wait);
+ }
+ }
+}
+
+/**
+ * binder_select_thread_ilocked() - selects a thread for doing proc work.
+ * @proc: process to select a thread from
+ *
+ * Note that calling this function moves the thread off the waiting_threads
+ * list, so it can only be woken up by the caller of this function, or a
+ * signal. Therefore, callers *should* always wake up the thread this function
+ * returns.
+ *
+ * Return: If there's a thread currently waiting for process work,
+ * returns that thread. Otherwise returns NULL.
+ */
+static struct binder_thread *
+binder_select_thread_ilocked(struct binder_proc *proc)
+{
+ struct binder_thread *thread;
+
+ BUG_ON(!spin_is_locked(&proc->inner_lock));
+ thread = list_first_entry_or_null(&proc->waiting_threads,
+ struct binder_thread,
+ waiting_thread_node);
+
+ if (thread)
+ list_del_init(&thread->waiting_thread_node);
+
+ return thread;
+}
+
+/**
+ * binder_wakeup_thread_ilocked() - wakes up a thread for doing proc work.
+ * @proc: process to wake up a thread in
+ * @thread: specific thread to wake-up (may be NULL)
+ * @sync: whether to do a synchronous wake-up
+ *
+ * This function wakes up a thread in the @proc process.
+ * The caller may provide a specific thread to wake-up in
+ * the @thread parameter. If @thread is NULL, this function
+ * will wake up threads that have called poll().
+ *
+ * Note that for this function to work as expected, callers
+ * should first call binder_select_thread() to find a thread
+ * to handle the work (if they don't have a thread already),
+ * and pass the result into the @thread parameter.
+ */
+static void binder_wakeup_thread_ilocked(struct binder_proc *proc,
+ struct binder_thread *thread,
+ bool sync)
+{
+ BUG_ON(!spin_is_locked(&proc->inner_lock));
+
+ if (thread) {
+ if (sync)
+ wake_up_interruptible_sync(&thread->wait);
+ else
+ wake_up_interruptible(&thread->wait);
return;
}
- min_nice = rlimit_to_nice(current->signal->rlim[RLIMIT_NICE].rlim_cur);
- binder_debug(BINDER_DEBUG_PRIORITY_CAP,
- "%d: nice value %ld not allowed use %ld instead\n",
- current->pid, nice, min_nice);
- set_user_nice(current, min_nice);
- if (min_nice <= MAX_NICE)
+
+ /* Didn't find a thread waiting for proc work; this can happen
+ * in two scenarios:
+ * 1. All threads are busy handling transactions
+ * In that case, one of those threads should call back into
+ * the kernel driver soon and pick up this work.
+ * 2. Threads are using the (e)poll interface, in which case
+ * they may be blocked on the waitqueue without having been
+ * added to waiting_threads. For this case, we just iterate
+ * over all threads not handling transaction work, and
+ * wake them all up. We wake all because we don't know whether
+ * a thread that called into (e)poll is handling non-binder
+ * work currently.
+ */
+ binder_wakeup_poll_threads_ilocked(proc, sync);
+}
+
+static void binder_wakeup_proc_ilocked(struct binder_proc *proc)
+{
+ struct binder_thread *thread = binder_select_thread_ilocked(proc);
+
+ binder_wakeup_thread_ilocked(proc, thread, /* sync = */false);
+}
+
+static bool is_rt_policy(int policy)
+{
+ return policy == SCHED_FIFO || policy == SCHED_RR;
+}
+
+static bool is_fair_policy(int policy)
+{
+ return policy == SCHED_NORMAL || policy == SCHED_BATCH;
+}
+
+static bool binder_supported_policy(int policy)
+{
+ return is_fair_policy(policy) || is_rt_policy(policy);
+}
+
+static int to_userspace_prio(int policy, int kernel_priority)
+{
+ if (is_fair_policy(policy))
+ return PRIO_TO_NICE(kernel_priority);
+ else
+ return MAX_USER_RT_PRIO - 1 - kernel_priority;
+}
+
+static int to_kernel_prio(int policy, int user_priority)
+{
+ if (is_fair_policy(policy))
+ return NICE_TO_PRIO(user_priority);
+ else
+ return MAX_USER_RT_PRIO - 1 - user_priority;
+}
+
+static void binder_do_set_priority(struct task_struct *task,
+ struct binder_priority desired,
+ bool verify)
+{
+ int priority; /* user-space prio value */
+ bool has_cap_nice;
+ unsigned int policy = desired.sched_policy;
+
+ if (task->policy == policy && task->normal_prio == desired.prio)
return;
- binder_user_error("%d RLIMIT_NICE not set\n", current->pid);
+
+ has_cap_nice = has_capability_noaudit(task, CAP_SYS_NICE);
+
+ priority = to_userspace_prio(policy, desired.prio);
+
+ if (verify && is_rt_policy(policy) && !has_cap_nice) {
+ long max_rtprio = task_rlimit(task, RLIMIT_RTPRIO);
+
+ if (max_rtprio == 0) {
+ policy = SCHED_NORMAL;
+ priority = MIN_NICE;
+ } else if (priority > max_rtprio) {
+ priority = max_rtprio;
+ }
+ }
+
+ if (verify && is_fair_policy(policy) && !has_cap_nice) {
+ long min_nice = rlimit_to_nice(task_rlimit(task, RLIMIT_NICE));
+
+ if (min_nice > MAX_NICE) {
+ binder_user_error("%d RLIMIT_NICE not set\n",
+ task->pid);
+ return;
+ } else if (priority < min_nice) {
+ priority = min_nice;
+ }
+ }
+
+ if (policy != desired.sched_policy ||
+ to_kernel_prio(policy, priority) != desired.prio)
+ binder_debug(BINDER_DEBUG_PRIORITY_CAP,
+ "%d: priority %d not allowed, using %d instead\n",
+ task->pid, desired.prio,
+ to_kernel_prio(policy, priority));
+
+ /* Set the actual priority */
+ if (task->policy != policy || is_rt_policy(policy)) {
+ struct sched_param params;
+
+ params.sched_priority = is_rt_policy(policy) ? priority : 0;
+
+ sched_setscheduler_nocheck(task,
+ policy | SCHED_RESET_ON_FORK,
+ ¶ms);
+ }
+ if (is_fair_policy(policy))
+ set_user_nice(task, priority);
+}
+
+static void binder_set_priority(struct task_struct *task,
+ struct binder_priority desired)
+{
+ binder_do_set_priority(task, desired, /* verify = */ true);
+}
+
+static void binder_restore_priority(struct task_struct *task,
+ struct binder_priority desired)
+{
+ binder_do_set_priority(task, desired, /* verify = */ false);
+}
+
+static void binder_transaction_priority(struct task_struct *task,
+ struct binder_transaction *t,
+ struct binder_priority node_prio,
+ bool inherit_rt)
+{
+ struct binder_priority desired_prio;
+
+ if (t->set_priority_called)
+ return;
+
+ t->set_priority_called = true;
+ t->saved_priority.sched_policy = task->policy;
+ t->saved_priority.prio = task->normal_prio;
+
+ if (!inherit_rt && is_rt_policy(desired_prio.sched_policy)) {
+ desired_prio.prio = NICE_TO_PRIO(0);
+ desired_prio.sched_policy = SCHED_NORMAL;
+ } else {
+ desired_prio.prio = t->priority.prio;
+ desired_prio.sched_policy = t->priority.sched_policy;
+ }
+
+ if (node_prio.prio < t->priority.prio ||
+ (node_prio.prio == t->priority.prio &&
+ node_prio.sched_policy == SCHED_FIFO)) {
+ /*
+ * In case the minimum priority on the node is
+ * higher (lower value), use that priority. If
+ * the priority is the same, but the node uses
+ * SCHED_FIFO, prefer SCHED_FIFO, since it can
+ * run unbounded, unlike SCHED_RR.
+ */
+ desired_prio = node_prio;
+ }
+
+ binder_set_priority(task, desired_prio);
}
static struct binder_node *binder_get_node_ilocked(struct binder_proc *proc,
@@ -989,6 +1267,7 @@
binder_uintptr_t ptr = fp ? fp->binder : 0;
binder_uintptr_t cookie = fp ? fp->cookie : 0;
__u32 flags = fp ? fp->flags : 0;
+ s8 priority;
BUG_ON(!spin_is_locked(&proc->inner_lock));
while (*p) {
@@ -1020,8 +1299,12 @@
node->ptr = ptr;
node->cookie = cookie;
node->work.type = BINDER_WORK_NODE;
- node->min_priority = flags & FLAT_BINDER_FLAG_PRIORITY_MASK;
+ priority = flags & FLAT_BINDER_FLAG_PRIORITY_MASK;
+ node->sched_policy = (flags & FLAT_BINDER_FLAG_PRIORITY_MASK) >>
+ FLAT_BINDER_FLAG_SCHED_POLICY_SHIFT;
+ node->min_priority = to_kernel_prio(node->sched_policy, priority);
node->accept_fds = !!(flags & FLAT_BINDER_FLAG_ACCEPTS_FDS);
+ node->inherit_rt = !!(flags & FLAT_BINDER_FLAG_INHERIT_RT);
spin_lock_init(&node->lock);
INIT_LIST_HEAD(&node->work.entry);
INIT_LIST_HEAD(&node->async_todo);
@@ -1140,7 +1423,7 @@
if (proc && (node->has_strong_ref || node->has_weak_ref)) {
if (list_empty(&node->work.entry)) {
binder_enqueue_work_ilocked(&node->work, &proc->todo);
- wake_up_interruptible(&node->proc->wait);
+ binder_wakeup_proc_ilocked(proc);
}
} else {
if (hlist_empty(&node->refs) && !node->local_strong_refs &&
@@ -2386,6 +2669,80 @@
return 0;
}
+/**
+ * binder_proc_transaction() - sends a transaction to a process and wakes it up
+ * @t: transaction to send
+ * @proc: process to send the transaction to
+ * @thread: thread in @proc to send the transaction to (may be NULL)
+ *
+ * This function queues a transaction to the specified process. It will try
+ * to find a thread in the target process to handle the transaction and
+ * wake it up. If no thread is found, the work is queued to the proc
+ * waitqueue.
+ *
+ * If the @thread parameter is not NULL, the transaction is always queued
+ * to the waitlist of that specific thread.
+ *
+ * Return: true if the transactions was successfully queued
+ * false if the target process or thread is dead
+ */
+static bool binder_proc_transaction(struct binder_transaction *t,
+ struct binder_proc *proc,
+ struct binder_thread *thread)
+{
+ struct list_head *target_list = NULL;
+ struct binder_node *node = t->buffer->target_node;
+ struct binder_priority node_prio;
+ bool oneway = !!(t->flags & TF_ONE_WAY);
+ bool wakeup = true;
+
+ BUG_ON(!node);
+ binder_node_lock(node);
+ node_prio.prio = node->min_priority;
+ node_prio.sched_policy = node->sched_policy;
+
+ if (oneway) {
+ BUG_ON(thread);
+ if (node->has_async_transaction) {
+ target_list = &node->async_todo;
+ wakeup = false;
+ } else {
+ node->has_async_transaction = 1;
+ }
+ }
+
+ binder_inner_proc_lock(proc);
+
+ if (proc->is_dead || (thread && thread->is_dead)) {
+ binder_inner_proc_unlock(proc);
+ binder_node_unlock(node);
+ return false;
+ }
+
+ if (!thread && !target_list)
+ thread = binder_select_thread_ilocked(proc);
+
+ if (thread) {
+ target_list = &thread->todo;
+ binder_transaction_priority(thread->task, t, node_prio,
+ node->inherit_rt);
+ } else if (!target_list) {
+ target_list = &proc->todo;
+ } else {
+ BUG_ON(target_list != &node->async_todo);
+ }
+
+ binder_enqueue_work_ilocked(&t->work, target_list);
+
+ if (wakeup)
+ binder_wakeup_thread_ilocked(proc, thread, !oneway /* sync */);
+
+ binder_inner_proc_unlock(proc);
+ binder_node_unlock(node);
+
+ return true;
+}
+
static void binder_transaction(struct binder_proc *proc,
struct binder_thread *thread,
struct binder_transaction_data *tr, int reply,
@@ -2400,8 +2757,6 @@
struct binder_proc *target_proc = NULL;
struct binder_thread *target_thread = NULL;
struct binder_node *target_node = NULL;
- struct list_head *target_list;
- wait_queue_head_t *target_wait;
struct binder_transaction *in_reply_to = NULL;
struct binder_transaction_log_entry *e;
uint32_t return_error = 0;
@@ -2452,7 +2807,6 @@
}
thread->transaction_stack = in_reply_to->to_parent;
binder_inner_proc_unlock(proc);
- binder_set_nice(in_reply_to->saved_priority);
target_thread = binder_get_txn_from_and_acq_inner(in_reply_to);
if (target_thread == NULL) {
return_error = BR_DEAD_REPLY;
@@ -2571,14 +2925,8 @@
}
binder_inner_proc_unlock(proc);
}
- if (target_thread) {
+ if (target_thread)
e->to_thread = target_thread->pid;
- target_list = &target_thread->todo;
- target_wait = &target_thread->wait;
- } else {
- target_list = &target_proc->todo;
- target_wait = &target_proc->wait;
- }
e->to_proc = target_proc->pid;
/* TODO: reuse incoming transaction for reply */
@@ -2631,7 +2979,15 @@
t->to_thread = target_thread;
t->code = tr->code;
t->flags = tr->flags;
- t->priority = task_nice(current);
+ if (!(t->flags & TF_ONE_WAY) &&
+ binder_supported_policy(current->policy)) {
+ /* Inherit supported policies for synchronous transactions */
+ t->priority.sched_policy = current->policy;
+ t->priority.prio = current->normal_prio;
+ } else {
+ /* Otherwise, fall back to the default priority */
+ t->priority = target_proc->default_priority;
+ }
trace_binder_transaction(reply, t, target_node);
@@ -2857,8 +3213,10 @@
}
BUG_ON(t->buffer->async_transaction != 0);
binder_pop_transaction_ilocked(target_thread, in_reply_to);
- binder_enqueue_work_ilocked(&t->work, target_list);
+ binder_enqueue_work_ilocked(&t->work, &target_thread->todo);
binder_inner_proc_unlock(target_proc);
+ wake_up_interruptible_sync(&target_thread->wait);
+ binder_restore_priority(current, in_reply_to->saved_priority);
binder_free_transaction(in_reply_to);
} else if (!(t->flags & TF_ONE_WAY)) {
BUG_ON(t->buffer->async_transaction != 0);
@@ -2867,47 +3225,17 @@
t->from_parent = thread->transaction_stack;
thread->transaction_stack = t;
binder_inner_proc_unlock(proc);
- binder_inner_proc_lock(target_proc);
- if (target_proc->is_dead ||
- (target_thread && target_thread->is_dead)) {
- binder_inner_proc_unlock(target_proc);
+ if (!binder_proc_transaction(t, target_proc, target_thread)) {
binder_inner_proc_lock(proc);
binder_pop_transaction_ilocked(thread, t);
binder_inner_proc_unlock(proc);
goto err_dead_proc_or_thread;
}
- binder_enqueue_work_ilocked(&t->work, target_list);
- binder_inner_proc_unlock(target_proc);
} else {
BUG_ON(target_node == NULL);
BUG_ON(t->buffer->async_transaction != 1);
- binder_node_lock(target_node);
- if (target_node->has_async_transaction) {
- target_list = &target_node->async_todo;
- target_wait = NULL;
- } else
- target_node->has_async_transaction = 1;
- /*
- * Test/set of has_async_transaction
- * must be atomic with enqueue on
- * async_todo
- */
- binder_inner_proc_lock(target_proc);
- if (target_proc->is_dead ||
- (target_thread && target_thread->is_dead)) {
- binder_inner_proc_unlock(target_proc);
- binder_node_unlock(target_node);
+ if (!binder_proc_transaction(t, target_proc, NULL))
goto err_dead_proc_or_thread;
- }
- binder_enqueue_work_ilocked(&t->work, target_list);
- binder_inner_proc_unlock(target_proc);
- binder_node_unlock(target_node);
- }
- if (target_wait) {
- if (reply || !(tr->flags & TF_ONE_WAY))
- wake_up_interruptible_sync(target_wait);
- else
- wake_up_interruptible(target_wait);
}
if (target_thread)
binder_thread_dec_tmpref(target_thread);
@@ -2977,6 +3305,7 @@
BUG_ON(thread->return_error.cmd != BR_OK);
if (in_reply_to) {
+ binder_restore_priority(current, in_reply_to->saved_priority);
thread->return_error.cmd = BR_TRANSACTION_COMPLETE;
binder_enqueue_work(thread->proc,
&thread->return_error.work,
@@ -3347,12 +3676,13 @@
&ref->death->work,
&thread->todo);
else {
- binder_enqueue_work(
- proc,
+ binder_inner_proc_lock(proc);
+ binder_enqueue_work_ilocked(
&ref->death->work,
&proc->todo);
- wake_up_interruptible(
- &proc->wait);
+ binder_wakeup_proc_ilocked(
+ proc);
+ binder_inner_proc_unlock(proc);
}
}
} else {
@@ -3387,8 +3717,8 @@
binder_enqueue_work_ilocked(
&death->work,
&proc->todo);
- wake_up_interruptible(
- &proc->wait);
+ binder_wakeup_proc_ilocked(
+ proc);
}
} else {
BUG_ON(death->work.type != BINDER_WORK_DEAD_BINDER);
@@ -3443,7 +3773,7 @@
binder_enqueue_work_ilocked(
&death->work,
&proc->todo);
- wake_up_interruptible(&proc->wait);
+ binder_wakeup_proc_ilocked(proc);
}
}
binder_inner_proc_unlock(proc);
@@ -3470,13 +3800,6 @@
}
}
-static int binder_has_proc_work(struct binder_proc *proc,
- struct binder_thread *thread)
-{
- return !binder_worklist_empty(proc, &proc->todo) ||
- thread->looper_need_return;
-}
-
static int binder_has_thread_work(struct binder_thread *thread)
{
return !binder_worklist_empty(thread->proc, &thread->todo) ||
@@ -3514,6 +3837,38 @@
return 0;
}
+static int binder_wait_for_work(struct binder_thread *thread,
+ bool do_proc_work)
+{
+ DEFINE_WAIT(wait);
+ struct binder_proc *proc = thread->proc;
+ int ret = 0;
+
+ freezer_do_not_count();
+ binder_inner_proc_lock(proc);
+ for (;;) {
+ prepare_to_wait(&thread->wait, &wait, TASK_INTERRUPTIBLE);
+ if (binder_has_work_ilocked(thread, do_proc_work))
+ break;
+ if (do_proc_work)
+ list_add(&thread->waiting_thread_node,
+ &proc->waiting_threads);
+ binder_inner_proc_unlock(proc);
+ schedule();
+ binder_inner_proc_lock(proc);
+ list_del_init(&thread->waiting_thread_node);
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+ }
+ finish_wait(&thread->wait, &wait);
+ binder_inner_proc_unlock(proc);
+ freezer_count();
+
+ return ret;
+}
+
static int binder_thread_read(struct binder_proc *proc,
struct binder_thread *thread,
binder_uintptr_t binder_buffer, size_t size,
@@ -3534,10 +3889,7 @@
retry:
binder_inner_proc_lock(proc);
- wait_for_proc_work = thread->transaction_stack == NULL &&
- binder_worklist_empty_ilocked(&thread->todo);
- if (wait_for_proc_work)
- proc->ready_threads++;
+ wait_for_proc_work = binder_available_for_proc_work_ilocked(thread);
binder_inner_proc_unlock(proc);
thread->looper |= BINDER_LOOPER_STATE_WAITING;
@@ -3553,24 +3905,16 @@
wait_event_interruptible(binder_user_error_wait,
binder_stop_on_user_error < 2);
}
- binder_set_nice(proc->default_priority);
- if (non_block) {
- if (!binder_has_proc_work(proc, thread))
- ret = -EAGAIN;
- } else
- ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread));
- } else {
- if (non_block) {
- if (!binder_has_thread_work(thread))
- ret = -EAGAIN;
- } else
- ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread));
+ binder_restore_priority(current, proc->default_priority);
}
- binder_inner_proc_lock(proc);
- if (wait_for_proc_work)
- proc->ready_threads--;
- binder_inner_proc_unlock(proc);
+ if (non_block) {
+ if (!binder_has_work(thread, wait_for_proc_work))
+ ret = -EAGAIN;
+ } else {
+ ret = binder_wait_for_work(thread, wait_for_proc_work);
+ }
+
thread->looper &= ~BINDER_LOOPER_STATE_WAITING;
if (ret)
@@ -3773,16 +4117,14 @@
BUG_ON(t->buffer == NULL);
if (t->buffer->target_node) {
struct binder_node *target_node = t->buffer->target_node;
+ struct binder_priority node_prio;
tr.target.ptr = target_node->ptr;
tr.cookie = target_node->cookie;
- t->saved_priority = task_nice(current);
- if (t->priority < target_node->min_priority &&
- !(t->flags & TF_ONE_WAY))
- binder_set_nice(t->priority);
- else if (!(t->flags & TF_ONE_WAY) ||
- t->saved_priority > target_node->min_priority)
- binder_set_nice(target_node->min_priority);
+ node_prio.sched_policy = target_node->sched_policy;
+ node_prio.prio = target_node->min_priority;
+ binder_transaction_priority(current, t, node_prio,
+ target_node->inherit_rt);
cmd = BR_TRANSACTION;
} else {
tr.target.ptr = 0;
@@ -3856,7 +4198,8 @@
*consumed = ptr - buffer;
binder_inner_proc_lock(proc);
- if (proc->requested_threads + proc->ready_threads == 0 &&
+ if (proc->requested_threads == 0 &&
+ list_empty(&thread->proc->waiting_threads) &&
proc->requested_threads_started < proc->max_threads &&
(thread->looper & (BINDER_LOOPER_STATE_REGISTERED |
BINDER_LOOPER_STATE_ENTERED)) /* the user-space code fails to */
@@ -3957,6 +4300,8 @@
binder_stats_created(BINDER_STAT_THREAD);
thread->proc = proc;
thread->pid = current->pid;
+ get_task_struct(current);
+ thread->task = current;
atomic_set(&thread->tmp_ref, 0);
init_waitqueue_head(&thread->wait);
INIT_LIST_HEAD(&thread->todo);
@@ -3967,7 +4312,7 @@
thread->return_error.cmd = BR_OK;
thread->reply_error.work.type = BINDER_WORK_RETURN_ERROR;
thread->reply_error.cmd = BR_OK;
-
+ INIT_LIST_HEAD(&new_thread->waiting_thread_node);
return thread;
}
@@ -4007,6 +4352,7 @@
BUG_ON(!list_empty(&thread->todo));
binder_stats_deleted(BINDER_STAT_THREAD);
binder_proc_dec_tmpref(thread->proc);
+ put_task_struct(thread->task);
kfree(thread);
}
@@ -4080,28 +4426,24 @@
{
struct binder_proc *proc = filp->private_data;
struct binder_thread *thread = NULL;
- int wait_for_proc_work;
+ bool wait_for_proc_work;
thread = binder_get_thread(proc);
binder_inner_proc_lock(thread->proc);
- wait_for_proc_work = thread->transaction_stack == NULL &&
- binder_worklist_empty_ilocked(&thread->todo);
+ thread->looper |= BINDER_LOOPER_STATE_POLL;
+ wait_for_proc_work = binder_available_for_proc_work_ilocked(thread);
+
binder_inner_proc_unlock(thread->proc);
- if (wait_for_proc_work) {
- if (binder_has_proc_work(proc, thread))
- return POLLIN;
- poll_wait(filp, &proc->wait, wait);
- if (binder_has_proc_work(proc, thread))
- return POLLIN;
- } else {
- if (binder_has_thread_work(thread))
- return POLLIN;
- poll_wait(filp, &thread->wait, wait);
- if (binder_has_thread_work(thread))
- return POLLIN;
- }
+ if (binder_has_work(thread, wait_for_proc_work))
+ return POLLIN;
+
+ poll_wait(filp, &thread->wait, wait);
+
+ if (binder_has_thread_work(thread))
+ return POLLIN;
+
return 0;
}
@@ -4148,8 +4490,10 @@
&bwr.read_consumed,
filp->f_flags & O_NONBLOCK);
trace_binder_read_done(ret);
- if (!binder_worklist_empty(proc, &proc->todo))
- wake_up_interruptible(&proc->wait);
+ binder_inner_proc_lock(proc);
+ if (!binder_worklist_empty_ilocked(&proc->todo))
+ binder_wakeup_proc_ilocked(proc);
+ binder_inner_proc_unlock(proc);
if (ret < 0) {
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
@@ -4216,6 +4560,30 @@
return ret;
}
+static int binder_ioctl_get_node_debug_info(struct binder_proc *proc,
+ struct binder_node_debug_info *info) {
+ struct rb_node *n;
+ binder_uintptr_t ptr = info->ptr;
+
+ memset(info, 0, sizeof(*info));
+
+ binder_inner_proc_lock(proc);
+ for (n = rb_first(&proc->nodes); n != NULL; n = rb_next(n)) {
+ struct binder_node *node = rb_entry(n, struct binder_node,
+ rb_node);
+ if (node->ptr > ptr) {
+ info->ptr = node->ptr;
+ info->cookie = node->cookie;
+ info->has_strong_ref = node->has_strong_ref;
+ info->has_weak_ref = node->has_weak_ref;
+ break;
+ }
+ }
+ binder_inner_proc_unlock(proc);
+
+ return 0;
+}
+
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
@@ -4283,6 +4651,24 @@
}
break;
}
+ case BINDER_GET_NODE_DEBUG_INFO: {
+ struct binder_node_debug_info info;
+
+ if (copy_from_user(&info, ubuf, sizeof(info))) {
+ ret = -EFAULT;
+ goto err;
+ }
+
+ ret = binder_ioctl_get_node_debug_info(proc, &info);
+ if (ret < 0)
+ goto err;
+
+ if (copy_to_user(ubuf, &info, sizeof(info))) {
+ ret = -EFAULT;
+ goto err;
+ }
+ break;
+ }
default:
ret = -EINVAL;
goto err;
@@ -4389,8 +4775,14 @@
get_task_struct(current->group_leader);
proc->tsk = current->group_leader;
INIT_LIST_HEAD(&proc->todo);
- init_waitqueue_head(&proc->wait);
- proc->default_priority = task_nice(current);
+ if (binder_supported_policy(current->policy)) {
+ proc->default_priority.sched_policy = current->policy;
+ proc->default_priority.prio = current->normal_prio;
+ } else {
+ proc->default_priority.sched_policy = SCHED_NORMAL;
+ proc->default_priority.prio = NICE_TO_PRIO(0);
+ }
+
binder_dev = container_of(filp->private_data, struct binder_device,
miscdev);
proc->context = &binder_dev->context;
@@ -4399,6 +4791,7 @@
binder_stats_created(BINDER_STAT_PROC);
proc->pid = current->group_leader->pid;
INIT_LIST_HEAD(&proc->delivered_death);
+ INIT_LIST_HEAD(&proc->waiting_threads);
filp->private_data = proc;
mutex_lock(&binder_procs_lock);
@@ -4450,7 +4843,6 @@
}
}
binder_inner_proc_unlock(proc);
- wake_up_interruptible_all(&proc->wait);
binder_debug(BINDER_DEBUG_OPEN_CLOSE,
"binder_flush: %d woke %d threads\n", proc->pid,
@@ -4519,7 +4911,7 @@
ref->death->work.type = BINDER_WORK_DEAD_BINDER;
binder_enqueue_work_ilocked(&ref->death->work,
&ref->proc->todo);
- wake_up_interruptible(&ref->proc->wait);
+ binder_wakeup_proc_ilocked(ref->proc);
binder_inner_proc_unlock(ref->proc);
}
@@ -4683,13 +5075,14 @@
spin_lock(&t->lock);
to_proc = t->to_proc;
seq_printf(m,
- "%s %d: %p from %d:%d to %d:%d code %x flags %x pri %ld r%d",
+ "%s %d: %p from %d:%d to %d:%d code %x flags %x pri %d:%d r%d",
prefix, t->debug_id, t,
t->from ? t->from->proc->pid : 0,
t->from ? t->from->pid : 0,
to_proc ? to_proc->pid : 0,
t->to_thread ? t->to_thread->pid : 0,
- t->code, t->flags, t->priority, t->need_reply);
+ t->code, t->flags, t->priority.sched_policy,
+ t->priority.prio, t->need_reply);
spin_unlock(&t->lock);
if (proc != to_proc) {
@@ -4812,8 +5205,9 @@
hlist_for_each_entry(ref, &node->refs, node_entry)
count++;
- seq_printf(m, " node %d: u%016llx c%016llx hs %d hw %d ls %d lw %d is %d iw %d tr %d",
+ seq_printf(m, " node %d: u%016llx c%016llx pri %d:%d hs %d hw %d ls %d lw %d is %d iw %d tr %d",
node->debug_id, (u64)node->ptr, (u64)node->cookie,
+ node->sched_policy, node->min_priority,
node->has_strong_ref, node->has_weak_ref,
node->local_strong_refs, node->local_weak_refs,
node->internal_strong_refs, count, node->tmp_refs);
@@ -5007,23 +5401,29 @@
struct binder_proc *proc)
{
struct binder_work *w;
+ struct binder_thread *thread;
struct rb_node *n;
- int count, strong, weak;
+ int count, strong, weak, ready_threads;
size_t free_async_space =
binder_alloc_get_free_async_space(&proc->alloc);
seq_printf(m, "proc %d\n", proc->pid);
seq_printf(m, "context %s\n", proc->context->name);
count = 0;
+ ready_threads = 0;
binder_inner_proc_lock(proc);
for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n))
count++;
+
+ list_for_each_entry(thread, &proc->waiting_threads, waiting_thread_node)
+ ready_threads++;
+
seq_printf(m, " threads: %d\n", count);
seq_printf(m, " requested threads: %d+%d/%d\n"
" ready threads %d\n"
" free async space %zd\n", proc->requested_threads,
proc->requested_threads_started, proc->max_threads,
- proc->ready_threads,
+ ready_threads,
free_async_space);
count = 0;
for (n = rb_first(&proc->nodes); n != NULL; n = rb_next(n))
diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
index e167a1e1..4f638ab 100644
--- a/drivers/base/dma-contiguous.c
+++ b/drivers/base/dma-contiguous.c
@@ -165,7 +165,8 @@
{
int ret;
- ret = cma_declare_contiguous(base, size, limit, 0, 0, fixed, res_cma);
+ ret = cma_declare_contiguous(base, size, limit, 0, 0, fixed,
+ "reserved", res_cma);
if (ret)
return ret;
@@ -257,7 +258,7 @@
return -EINVAL;
}
- err = cma_init_reserved_mem(rmem->base, rmem->size, 0, &cma);
+ err = cma_init_reserved_mem(rmem->base, rmem->size, 0, rmem->name, &cma);
if (err) {
pr_err("Reserved memory: unable to setup CMA region\n");
return err;
diff --git a/drivers/base/dma-mapping.c b/drivers/base/dma-mapping.c
index aa5e22c..7c8f6bf 100644
--- a/drivers/base/dma-mapping.c
+++ b/drivers/base/dma-mapping.c
@@ -306,7 +306,7 @@
unsigned long vm_flags,
pgprot_t prot, const void *caller)
{
- int i;
+ unsigned long i;
struct page **pages;
void *ptr;
unsigned long pfn;
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index e023066..8c7d0f3 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -1029,8 +1029,6 @@
spin_unlock_irq(&dev->power.lock);
- dev_pm_domain_set(dev, &genpd->domain);
-
return gpd_data;
err_free:
@@ -1044,8 +1042,6 @@
static void genpd_free_dev_data(struct device *dev,
struct generic_pm_domain_data *gpd_data)
{
- dev_pm_domain_set(dev, NULL);
-
spin_lock_irq(&dev->power.lock);
dev->power.subsys_data->domain_data = NULL;
@@ -1082,6 +1078,8 @@
if (ret)
goto out;
+ dev_pm_domain_set(dev, &genpd->domain);
+
genpd->device_count++;
genpd->max_off_time_changed = true;
@@ -1143,6 +1141,8 @@
if (genpd->detach_dev)
genpd->detach_dev(genpd, dev);
+ dev_pm_domain_set(dev, NULL);
+
list_del_init(&pdd->list_node);
mutex_unlock(&genpd->lock);
@@ -1244,7 +1244,7 @@
int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
struct generic_pm_domain *subdomain)
{
- struct gpd_link *link;
+ struct gpd_link *l, *link;
int ret = -EINVAL;
if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(subdomain))
@@ -1260,7 +1260,7 @@
goto out;
}
- list_for_each_entry(link, &genpd->master_links, master_node) {
+ list_for_each_entry_safe(link, l, &genpd->master_links, master_node) {
if (link->slave != subdomain)
continue;
@@ -1607,12 +1607,12 @@
*/
void of_genpd_del_provider(struct device_node *np)
{
- struct of_genpd_provider *cp;
+ struct of_genpd_provider *cp, *tmp;
struct generic_pm_domain *gpd;
mutex_lock(&gpd_list_lock);
mutex_lock(&of_genpd_mutex);
- list_for_each_entry(cp, &of_genpd_providers, link) {
+ list_for_each_entry_safe(cp, tmp, &of_genpd_providers, link) {
if (cp->node == np) {
/*
* For each PM domain associated with the
@@ -1752,14 +1752,14 @@
*/
struct generic_pm_domain *of_genpd_remove_last(struct device_node *np)
{
- struct generic_pm_domain *gpd, *genpd = ERR_PTR(-ENOENT);
+ struct generic_pm_domain *gpd, *tmp, *genpd = ERR_PTR(-ENOENT);
int ret;
if (IS_ERR_OR_NULL(np))
return ERR_PTR(-EINVAL);
mutex_lock(&gpd_list_lock);
- list_for_each_entry(gpd, &gpd_list, gpd_list_node) {
+ list_for_each_entry_safe(gpd, tmp, &gpd_list, gpd_list_node) {
if (gpd->provider == &np->fwnode) {
ret = genpd_remove(gpd);
genpd = ret ? ERR_PTR(ret) : gpd;
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c
index a7b4679..39efa7e 100644
--- a/drivers/base/power/sysfs.c
+++ b/drivers/base/power/sysfs.c
@@ -268,6 +268,8 @@
value = PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT;
else if (!strcmp(buf, "any") || !strcmp(buf, "any\n"))
value = PM_QOS_LATENCY_ANY;
+ else
+ return -EINVAL;
}
ret = dev_pm_qos_update_user_latency_tolerance(dev, value);
return ret < 0 ? ret : n;
diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
index 270cdd4..90c16d8 100644
--- a/drivers/base/power/wakeup.c
+++ b/drivers/base/power/wakeup.c
@@ -61,6 +61,8 @@
static DECLARE_WAIT_QUEUE_HEAD(wakeup_count_wait_queue);
+DEFINE_STATIC_SRCU(wakeup_srcu);
+
static struct wakeup_source deleted_ws = {
.name = "deleted",
.lock = __SPIN_LOCK_UNLOCKED(deleted_ws.lock),
@@ -199,7 +201,7 @@
spin_lock_irqsave(&events_lock, flags);
list_del_rcu(&ws->entry);
spin_unlock_irqrestore(&events_lock, flags);
- synchronize_rcu();
+ synchronize_srcu(&wakeup_srcu);
}
EXPORT_SYMBOL_GPL(wakeup_source_remove);
@@ -333,12 +335,12 @@
void device_wakeup_arm_wake_irqs(void)
{
struct wakeup_source *ws;
+ int srcuidx;
- rcu_read_lock();
+ srcuidx = srcu_read_lock(&wakeup_srcu);
list_for_each_entry_rcu(ws, &wakeup_sources, entry)
dev_pm_arm_wake_irq(ws->wakeirq);
-
- rcu_read_unlock();
+ srcu_read_unlock(&wakeup_srcu, srcuidx);
}
/**
@@ -349,12 +351,12 @@
void device_wakeup_disarm_wake_irqs(void)
{
struct wakeup_source *ws;
+ int srcuidx;
- rcu_read_lock();
+ srcuidx = srcu_read_lock(&wakeup_srcu);
list_for_each_entry_rcu(ws, &wakeup_sources, entry)
dev_pm_disarm_wake_irq(ws->wakeirq);
-
- rcu_read_unlock();
+ srcu_read_unlock(&wakeup_srcu, srcuidx);
}
/**
@@ -837,10 +839,10 @@
void pm_print_active_wakeup_sources(void)
{
struct wakeup_source *ws;
- int active = 0;
+ int srcuidx, active = 0;
struct wakeup_source *last_activity_ws = NULL;
- rcu_read_lock();
+ srcuidx = srcu_read_lock(&wakeup_srcu);
list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
if (ws->active) {
pr_info("active wakeup source: %s\n", ws->name);
@@ -856,7 +858,7 @@
if (!active && last_activity_ws)
pr_info("last active wakeup source: %s\n",
last_activity_ws->name);
- rcu_read_unlock();
+ srcu_read_unlock(&wakeup_srcu, srcuidx);
}
EXPORT_SYMBOL_GPL(pm_print_active_wakeup_sources);
@@ -983,8 +985,9 @@
{
struct wakeup_source *ws;
ktime_t now = ktime_get();
+ int srcuidx;
- rcu_read_lock();
+ srcuidx = srcu_read_lock(&wakeup_srcu);
list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
spin_lock_irq(&ws->lock);
if (ws->autosleep_enabled != set) {
@@ -998,7 +1001,7 @@
}
spin_unlock_irq(&ws->lock);
}
- rcu_read_unlock();
+ srcu_read_unlock(&wakeup_srcu, srcuidx);
}
#endif /* CONFIG_PM_AUTOSLEEP */
@@ -1059,15 +1062,16 @@
static int wakeup_sources_stats_show(struct seq_file *m, void *unused)
{
struct wakeup_source *ws;
+ int srcuidx;
seq_puts(m, "name\t\t\t\t\tactive_count\tevent_count\twakeup_count\t"
"expire_count\tactive_since\ttotal_time\tmax_time\t"
"last_change\tprevent_suspend_time\n");
- rcu_read_lock();
+ srcuidx = srcu_read_lock(&wakeup_srcu);
list_for_each_entry_rcu(ws, &wakeup_sources, entry)
print_wakeup_source_stats(m, ws);
- rcu_read_unlock();
+ srcu_read_unlock(&wakeup_srcu, srcuidx);
print_wakeup_source_stats(m, &deleted_ws);
diff --git a/drivers/bluetooth/btfm_slim.c b/drivers/bluetooth/btfm_slim.c
index f50bf6f..8f0e632 100644
--- a/drivers/bluetooth/btfm_slim.c
+++ b/drivers/bluetooth/btfm_slim.c
@@ -496,9 +496,18 @@
/* Driver specific data allocation */
btfm_slim->dev = &slim->dev;
ret = btfm_slim_register_codec(&slim->dev);
+ if (ret) {
+ BTFMSLIM_ERR("error, registering slimbus codec failed");
+ goto free;
+ }
ret = bt_register_slimdev(&slim->dev);
+ if (ret < 0) {
+ btfm_slim_unregister_codec(&slim->dev);
+ goto free;
+ }
return ret;
-
+free:
+ slim_remove_device(&btfm_slim->slim_ifd);
dealloc:
mutex_destroy(&btfm_slim->io_lock);
mutex_destroy(&btfm_slim->xfer_lock);
diff --git a/drivers/bluetooth/btfm_slim.h b/drivers/bluetooth/btfm_slim.h
index ed3a743..cc9d14d 100644
--- a/drivers/bluetooth/btfm_slim.h
+++ b/drivers/bluetooth/btfm_slim.h
@@ -162,4 +162,12 @@
* 0
*/
int btfm_slim_register_codec(struct device *dev);
+
+/**
+ * btfm_slim_unregister_codec: Unregister codec driver in slimbus device node
+ * @dev: device node
+ * Returns:
+ * VOID
+ */
+void btfm_slim_unregister_codec(struct device *dev);
#endif /* BTFM_SLIM_H */
diff --git a/drivers/bluetooth/btfm_slim_codec.c b/drivers/bluetooth/btfm_slim_codec.c
index 791ea29..309648f 100644
--- a/drivers/bluetooth/btfm_slim_codec.c
+++ b/drivers/bluetooth/btfm_slim_codec.c
@@ -26,6 +26,9 @@
#include <sound/tlv.h>
#include <btfm_slim.h>
+static int bt_soc_enable_status;
+
+
static int btfm_slim_codec_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
@@ -38,8 +41,31 @@
return 0;
}
+static int bt_soc_status_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = bt_soc_enable_status;
+ return 1;
+}
+
+static int bt_soc_status_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return 1;
+}
+
+static const struct snd_kcontrol_new status_controls[] = {
+ SOC_SINGLE_EXT("BT SOC status", 0, 0, 1, 0,
+ bt_soc_status_get,
+ bt_soc_status_put)
+
+};
+
+
static int btfm_slim_codec_probe(struct snd_soc_codec *codec)
{
+ snd_soc_add_codec_controls(codec, status_controls,
+ ARRAY_SIZE(status_controls));
return 0;
}
@@ -92,9 +118,6 @@
return;
}
- if (dai->id == BTFM_FM_SLIM_TX)
- goto out;
-
/* Search for dai->id matched port handler */
for (i = 0; (i < BTFM_SLIM_NUM_CODEC_DAIS) &&
(ch->id != BTFM_SLIM_NUM_CODEC_DAIS) &&
@@ -108,7 +131,6 @@
}
btfm_slim_disable_ch(btfmslim, ch, rxport, grp, nchan);
-out:
btfm_slim_hw_deinit(btfmslim);
}
@@ -130,6 +152,7 @@
struct btfmslim *btfmslim = dai->dev->platform_data;
struct btfmslim_ch *ch;
uint8_t rxport, grp = false, nchan = 1;
+ bt_soc_enable_status = 0;
BTFMSLIM_DBG("dai->name: %s, dai->id: %d, dai->rate: %d", dai->name,
dai->id, dai->rate);
@@ -171,61 +194,10 @@
}
ret = btfm_slim_enable_ch(btfmslim, ch, rxport, dai->rate, grp, nchan);
- return ret;
-}
-static int btfm_slim_dai_hw_free(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- int ret = -EINVAL, i;
- struct btfmslim *btfmslim = dai->dev->platform_data;
- struct btfmslim_ch *ch;
- uint8_t rxport, grp = false, nchan = 1;
-
- BTFMSLIM_DBG("dai->name: %s, dai->id: %d, dai->rate: %d", dai->name,
- dai->id, dai->rate);
-
- switch (dai->id) {
- case BTFM_FM_SLIM_TX:
- grp = true; nchan = 2;
- ch = btfmslim->tx_chs;
- rxport = 0;
- break;
- case BTFM_BT_SCO_SLIM_TX:
- ch = btfmslim->tx_chs;
- rxport = 0;
- break;
- case BTFM_BT_SCO_A2DP_SLIM_RX:
- case BTFM_BT_SPLIT_A2DP_SLIM_RX:
- ch = btfmslim->rx_chs;
- rxport = 1;
- break;
- case BTFM_SLIM_NUM_CODEC_DAIS:
- default:
- BTFMSLIM_ERR("dai->id is invalid:%d", dai->id);
- goto out;
- }
-
- if (dai->id != BTFM_FM_SLIM_TX) {
- ret = 0;
- goto out;
- }
-
- /* Search for dai->id matched port handler */
- for (i = 0; (i < BTFM_SLIM_NUM_CODEC_DAIS) &&
- (ch->id != BTFM_SLIM_NUM_CODEC_DAIS) &&
- (ch->id != dai->id); ch++, i++)
- ;
-
- if ((ch->port == BTFM_SLIM_PGD_PORT_LAST) ||
- (ch->id == BTFM_SLIM_NUM_CODEC_DAIS)) {
- BTFMSLIM_ERR("ch is invalid!!");
- goto out;
- }
-
- btfm_slim_disable_ch(btfmslim, ch, rxport, grp, nchan);
-
-out:
+ /* save the enable channel status */
+ if (ret == 0)
+ bt_soc_enable_status = 1;
return ret;
}
@@ -374,7 +346,6 @@
.shutdown = btfm_slim_dai_shutdown,
.hw_params = btfm_slim_dai_hw_params,
.prepare = btfm_slim_dai_prepare,
- .hw_free = btfm_slim_dai_hw_free,
.set_channel_map = btfm_slim_dai_set_channel_map,
.get_channel_map = btfm_slim_dai_get_channel_map,
};
@@ -462,5 +433,12 @@
return ret;
}
+void btfm_slim_unregister_codec(struct device *dev)
+{
+ BTFMSLIM_DBG("");
+ /* Unregister Codec driver */
+ snd_soc_unregister_codec(dev);
+}
+
MODULE_DESCRIPTION("BTFM Slimbus Codec driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/bluetooth/btfm_slim_wcn3990.c b/drivers/bluetooth/btfm_slim_wcn3990.c
index 77e2973..f0a6d9e 100644
--- a/drivers/bluetooth/btfm_slim_wcn3990.c
+++ b/drivers/bluetooth/btfm_slim_wcn3990.c
@@ -82,18 +82,18 @@
uint8_t rxport, uint8_t enable)
{
int ret = 0;
- uint8_t reg_val = 0;
+ uint8_t reg_val = 0, en;
uint8_t port_bit = 0;
uint16_t reg;
BTFMSLIM_DBG("port(%d) enable(%d)", port_num, enable);
if (rxport) {
- if (enable && btfmslim->sample_rate == 48000) {
- /* For A2DP Rx */
+ if (enable) {
+ /* For SCO Rx, A2DP Rx */
reg_val = 0x1;
port_bit = port_num - 0x10;
reg = CHRK_SB_PGD_RX_PORTn_MULTI_CHNL_0(port_bit);
- BTFMSLIM_DBG("writing reg_val (%d) to reg(%x) for A2DP",
+ BTFMSLIM_DBG("writing reg_val (%d) to reg(%x)",
reg_val, reg);
ret = btfm_slim_write(btfmslim, reg, 1, ®_val, IFD);
if (ret) {
@@ -120,6 +120,18 @@
BTFMSLIM_ERR("failed to write (%d) reg 0x%x", ret, reg);
goto error;
}
+ } else if (port_num == CHRK_SB_PGD_PORT_TX_SCO) {
+ /* SCO Tx */
+ reg_val = 0x1 << CHRK_SB_PGD_PORT_TX_SCO;
+ reg = CHRK_SB_PGD_TX_PORTn_MULTI_CHNL_0(port_num);
+ BTFMSLIM_DBG("writing reg_val (%d) to reg(%x)",
+ reg_val, reg);
+ ret = btfm_slim_write(btfmslim, reg, 1, ®_val, IFD);
+ if (ret) {
+ BTFMSLIM_ERR("failed to write (%d) reg 0x%x",
+ ret, reg);
+ goto error;
+ }
}
/* Enable Tx port hw auto recovery for underrun or overrun error */
@@ -137,15 +149,21 @@
reg = CHRK_SB_PGD_PORT_TX_CFGN(port_num);
enable_disable_rxport:
- if (enable) {
- if (is_fm_port(port_num))
- reg_val = CHRK_SB_PGD_PORT_ENABLE |
- CHRK_SB_PGD_PORT_WM_L3;
- else
- reg_val = CHRK_SB_PGD_PORT_ENABLE |
- CHRK_SB_PGD_PORT_WM_LB;
- } else
- reg_val = CHRK_SB_PGD_PORT_DISABLE;
+ if (enable)
+ en = CHRK_SB_PGD_PORT_ENABLE;
+ else
+ en = CHRK_SB_PGD_PORT_DISABLE;
+
+ if (is_fm_port(port_num))
+ reg_val = en | CHRK_SB_PGD_PORT_WM_L8;
+ else if (port_num == CHRK_SB_PGD_PORT_TX_SCO)
+ reg_val = enable ? en | CHRK_SB_PGD_PORT_WM_L1 : en;
+ else
+ reg_val = enable ? en | CHRK_SB_PGD_PORT_WM_LB : en;
+
+ if (enable && port_num == CHRK_SB_PGD_PORT_TX_SCO)
+ BTFMSLIM_INFO("programming SCO Tx with reg_val %d to reg 0x%x",
+ reg_val, reg);
ret = btfm_slim_write(btfmslim, reg, 1, ®_val, IFD);
if (ret)
diff --git a/drivers/bluetooth/btfm_slim_wcn3990.h b/drivers/bluetooth/btfm_slim_wcn3990.h
index 6bbdb6b..b2723ff 100644
--- a/drivers/bluetooth/btfm_slim_wcn3990.h
+++ b/drivers/bluetooth/btfm_slim_wcn3990.h
@@ -68,6 +68,7 @@
#define CHRK_SB_PGD_PORT_WM_L1 (0x1 << 1)
#define CHRK_SB_PGD_PORT_WM_L2 (0x2 << 1)
#define CHRK_SB_PGD_PORT_WM_L3 (0x3 << 1)
+#define CHRK_SB_PGD_PORT_WM_L8 (0x8 << 1)
#define CHRK_SB_PGD_PORT_WM_LB (0xB << 1)
#define CHRK_SB_PGD_PORT_RX_NUM 16
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 7bc263c..636c982 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -45,7 +45,7 @@
#include "adsprpc_compat.h"
#include "adsprpc_shared.h"
#include <linux/debugfs.h>
-
+#include <linux/pm_qos.h>
#define TZ_PIL_PROTECT_MEM_SUBSYS_ID 0x0C
#define TZ_PIL_CLEAR_PROTECT_MEM_SUBSYS_ID 0x0D
#define TZ_PIL_AUTH_QDSP6_PROC 1
@@ -73,6 +73,7 @@
#define PERF_KEYS "count:flush:map:copy:glink:getargs:putargs:invalidate:invoke"
#define FASTRPC_STATIC_HANDLE_LISTENER (3)
#define FASTRPC_STATIC_HANDLE_MAX (20)
+#define FASTRPC_LATENCY_CTRL_ENB (1)
#define PERF_END (void)0
@@ -235,6 +236,7 @@
spinlock_t hlock;
struct ion_client *client;
struct device *dev;
+ unsigned int latency;
};
struct fastrpc_mmap {
@@ -284,9 +286,12 @@
int cid;
int ssrcount;
int pd;
+ int file_close;
struct fastrpc_apps *apps;
struct fastrpc_perf perf;
struct dentry *debugfs_file;
+ struct pm_qos_request pm_qos_req;
+ int qos_request;
};
static struct fastrpc_apps gfa;
@@ -480,7 +485,7 @@
if (!IS_ERR_OR_NULL(map->handle))
ion_free(fl->apps->client, map->handle);
- if (sess->smmu.enabled) {
+ if (sess && sess->smmu.enabled) {
if (map->size || map->phys)
msm_dma_unmap_sg(sess->dev,
map->table->sgl,
@@ -558,7 +563,9 @@
sess = fl->secsctx;
else
sess = fl->sctx;
-
+ VERIFY(err, !IS_ERR_OR_NULL(sess));
+ if (err)
+ goto bail;
VERIFY(err, !IS_ERR_OR_NULL(map->buf = dma_buf_get(fd)));
if (err)
goto bail;
@@ -1399,6 +1406,14 @@
if (fl->profile)
getnstimeofday(&invoket);
+
+ VERIFY(err, fl->sctx != NULL);
+ if (err)
+ goto bail;
+ VERIFY(err, fl->cid >= 0 && fl->cid < NUM_CHANNELS);
+ if (err)
+ goto bail;
+
if (!kernel) {
VERIFY(err, 0 == context_restore_interrupted(fl, inv,
&ctx));
@@ -1888,6 +1903,9 @@
return 0;
}
(void)fastrpc_release_current_dsp_process(fl);
+ spin_lock(&fl->hlock);
+ fl->file_close = 1;
+ spin_unlock(&fl->hlock);
fastrpc_context_list_dtor(fl);
fastrpc_buf_list_free(fl);
hlist_for_each_entry_safe(map, n, &fl->maps, hn) {
@@ -1909,6 +1927,8 @@
struct fastrpc_file *fl = (struct fastrpc_file *)file->private_data;
if (fl) {
+ if (fl->qos_request && pm_qos_request_active(&fl->pm_qos_req))
+ pm_qos_remove_request(&fl->pm_qos_req);
if (fl->debugfs_file != NULL)
debugfs_remove(fl->debugfs_file);
fastrpc_file_free(fl);
@@ -2088,16 +2108,16 @@
spin_lock(&fl->hlock);
hlist_for_each_entry_safe(buf, n, &fl->bufs, hn) {
len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len,
- "%s %p %s %p %s %llx\n", "buf:",
- buf, "buf->virt:", buf->virt,
- "buf->phys:", buf->phys);
+ "%s %pK %s %pK %s %llx\n", "buf:",
+ buf, "buf->virt:", buf->virt,
+ "buf->phys:", buf->phys);
}
len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len,
"\n%s\n",
"LIST OF MAPS:");
hlist_for_each_entry_safe(map, n, &fl->maps, hn) {
len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len,
- "%s %p %s %lx %s %llx\n",
+ "%s %pK %s %lx %s %llx\n",
"map:", map,
"map->va:", map->va,
"map->phys:", map->phys);
@@ -2107,7 +2127,7 @@
"LIST OF PENDING SMQCONTEXTS:");
hlist_for_each_entry_safe(ictx, n, &fl->clst.pending, hn) {
len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len,
- "%s %p %s %u %s %u %s %u\n",
+ "%s %pK %s %u %s %u %s %u\n",
"smqcontext:", ictx,
"sc:", ictx->sc,
"tid:", ictx->pid,
@@ -2118,7 +2138,7 @@
"LIST OF INTERRUPTED SMQCONTEXTS:");
hlist_for_each_entry_safe(ictx, n, &fl->clst.interrupted, hn) {
len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len,
- "%s %p %s %u %s %u %s %u\n",
+ "%s %pK %s %u %s %u %s %u\n",
"smqcontext:", ictx,
"sc:", ictx->sc,
"tid:", ictx->pid,
@@ -2172,6 +2192,11 @@
kref_init(&me->channel[cid].kref);
pr_info("'opened /dev/%s c %d %d'\n", gcinfo[cid].name,
MAJOR(me->dev_no), cid);
+ err = glink_queue_rx_intent(me->channel[cid].chan, NULL, 16);
+ err |= glink_queue_rx_intent(me->channel[cid].chan, NULL, 64);
+ if (err)
+ pr_warn("adsprpc: initial intent fail for %d err %d\n",
+ cid, err);
if (me->channel[cid].ssrcount !=
me->channel[cid].prevssrcount) {
me->channel[cid].prevssrcount =
@@ -2208,6 +2233,7 @@
if (debugfs_file != NULL)
fl->debugfs_file = debugfs_file;
memset(&fl->perf, 0, sizeof(fl->perf));
+ fl->qos_request = 0;
filp->private_data = fl;
spin_lock(&me->hlock);
hlist_add_head(&fl->hn, &me->drivers);
@@ -2235,11 +2261,49 @@
if (err)
goto bail;
}
+ VERIFY(err, fl->sctx != NULL);
+ if (err)
+ goto bail;
*info = (fl->sctx->smmu.enabled ? 1 : 0);
bail:
return err;
}
+static int fastrpc_internal_control(struct fastrpc_file *fl,
+ struct fastrpc_ioctl_control *cp)
+{
+ int err = 0;
+ int latency;
+
+ VERIFY(err, !IS_ERR_OR_NULL(fl) && !IS_ERR_OR_NULL(fl->apps));
+ if (err)
+ goto bail;
+ VERIFY(err, !IS_ERR_OR_NULL(cp));
+ if (err)
+ goto bail;
+
+ switch (cp->req) {
+ case FASTRPC_CONTROL_LATENCY:
+ latency = cp->lp.enable == FASTRPC_LATENCY_CTRL_ENB ?
+ fl->apps->latency : PM_QOS_DEFAULT_VALUE;
+ VERIFY(err, latency != 0);
+ if (err)
+ goto bail;
+ if (!fl->qos_request) {
+ pm_qos_add_request(&fl->pm_qos_req,
+ PM_QOS_CPU_DMA_LATENCY, latency);
+ fl->qos_request = 1;
+ } else
+ pm_qos_update_request(&fl->pm_qos_req, latency);
+ break;
+ default:
+ err = -ENOTTY;
+ break;
+ }
+bail:
+ return err;
+}
+
static long fastrpc_device_ioctl(struct file *file, unsigned int ioctl_num,
unsigned long ioctl_param)
{
@@ -2249,6 +2313,7 @@
struct fastrpc_ioctl_munmap munmap;
struct fastrpc_ioctl_init_attrs init;
struct fastrpc_ioctl_perf perf;
+ struct fastrpc_ioctl_control cp;
} p;
void *param = (char *)ioctl_param;
struct fastrpc_file *fl = (struct fastrpc_file *)file->private_data;
@@ -2258,6 +2323,14 @@
p.inv.fds = 0;
p.inv.attrs = 0;
p.inv.crc = NULL;
+ spin_lock(&fl->hlock);
+ if (fl->file_close == 1) {
+ err = EBADF;
+ pr_warn("ADSPRPC: fastrpc_device_release is happening, So not sending any new requests to DSP");
+ spin_unlock(&fl->hlock);
+ goto bail;
+ }
+ spin_unlock(&fl->hlock);
switch (ioctl_num) {
case FASTRPC_IOCTL_INVOKE:
@@ -2340,6 +2413,15 @@
if (err)
goto bail;
break;
+ case FASTRPC_IOCTL_CONTROL:
+ VERIFY(err, 0 == copy_from_user(&p.cp, (void __user *)param,
+ sizeof(p.cp)));
+ if (err)
+ goto bail;
+ VERIFY(err, 0 == (err = fastrpc_internal_control(fl, &p.cp)));
+ if (err)
+ goto bail;
+ break;
case FASTRPC_IOCTL_GETINFO:
VERIFY(err, 0 == copy_from_user(&info, param, sizeof(info)));
if (err)
@@ -2362,6 +2444,10 @@
VERIFY(err, 0 == copy_from_user(&p.init, param, size));
if (err)
goto bail;
+ VERIFY(err, p.init.init.filelen >= 0 &&
+ p.init.init.memlen >= 0);
+ if (err)
+ goto bail;
VERIFY(err, 0 == fastrpc_init_process(fl, &p.init));
if (err)
goto bail;
@@ -2459,7 +2545,7 @@
start = 0x60000000;
VERIFY(err, !IS_ERR_OR_NULL(sess->smmu.mapping =
arm_iommu_create_mapping(&platform_bus_type,
- start, 0x7fffffff)));
+ start, 0x78000000)));
if (err)
goto bail;
@@ -2535,6 +2621,10 @@
return 0;
}
+ err = of_property_read_u32(dev->of_node, "qcom,rpc-latency-us",
+ &me->latency);
+ if (err)
+ me->latency = 0;
VERIFY(err, !of_platform_populate(pdev->dev.of_node,
fastrpc_match_table,
NULL, &pdev->dev));
diff --git a/drivers/char/adsprpc_compat.c b/drivers/char/adsprpc_compat.c
index 078b4d9..21ad3f9 100644
--- a/drivers/char/adsprpc_compat.c
+++ b/drivers/char/adsprpc_compat.c
@@ -11,7 +11,6 @@
* GNU General Public License for more details.
*
*/
-
#include <linux/compat.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
@@ -38,6 +37,8 @@
_IOWR('R', 10, struct compat_fastrpc_ioctl_init_attrs)
#define COMPAT_FASTRPC_IOCTL_INVOKE_CRC \
_IOWR('R', 11, struct compat_fastrpc_ioctl_invoke_crc)
+#define COMPAT_FASTRPC_IOCTL_CONTROL \
+ _IOWR('R', 12, struct compat_fastrpc_ioctl_control)
struct compat_remote_buf {
compat_uptr_t pv; /* buffer pointer */
@@ -108,6 +109,19 @@
compat_uptr_t keys;
};
+#define FASTRPC_CONTROL_LATENCY (1)
+struct compat_fastrpc_ctrl_latency {
+ compat_uint_t enable; /* latency control enable */
+ compat_uint_t level; /* level of control */
+};
+
+struct compat_fastrpc_ioctl_control {
+ compat_uint_t req;
+ union {
+ struct compat_fastrpc_ctrl_latency lp;
+ };
+};
+
static int compat_get_fastrpc_ioctl_invoke(
struct compat_fastrpc_ioctl_invoke_crc __user *inv32,
struct fastrpc_ioctl_invoke_crc __user **inva,
@@ -236,6 +250,25 @@
return err;
}
+static int compat_get_fastrpc_ioctl_control(
+ struct compat_fastrpc_ioctl_control __user *ctrl32,
+ struct fastrpc_ioctl_control __user *ctrl)
+{
+ compat_uptr_t p;
+ int err;
+
+ err = get_user(p, &ctrl32->req);
+ err |= put_user(p, &ctrl->req);
+ if (p == FASTRPC_CONTROL_LATENCY) {
+ err |= get_user(p, &ctrl32->lp.enable);
+ err |= put_user(p, &ctrl->lp.enable);
+ err |= get_user(p, &ctrl32->lp.level);
+ err |= put_user(p, &ctrl->lp.level);
+ }
+
+ return err;
+}
+
static int compat_get_fastrpc_ioctl_init(
struct compat_fastrpc_ioctl_init_attrs __user *init32,
struct fastrpc_ioctl_init_attrs __user *init,
@@ -385,6 +418,24 @@
case FASTRPC_IOCTL_SETMODE:
return filp->f_op->unlocked_ioctl(filp, cmd,
(unsigned long)compat_ptr(arg));
+ case COMPAT_FASTRPC_IOCTL_CONTROL:
+ {
+ struct compat_fastrpc_ioctl_control __user *ctrl32;
+ struct fastrpc_ioctl_control __user *ctrl;
+
+ ctrl32 = compat_ptr(arg);
+ VERIFY(err, NULL != (ctrl = compat_alloc_user_space(
+ sizeof(*ctrl))));
+ if (err)
+ return -EFAULT;
+ VERIFY(err, 0 == compat_get_fastrpc_ioctl_control(ctrl32,
+ ctrl));
+ if (err)
+ return err;
+ err = filp->f_op->unlocked_ioctl(filp, FASTRPC_IOCTL_CONTROL,
+ (unsigned long)ctrl);
+ return err;
+ }
case COMPAT_FASTRPC_IOCTL_GETPERF:
{
struct compat_fastrpc_ioctl_perf __user *perf32;
diff --git a/drivers/char/adsprpc_shared.h b/drivers/char/adsprpc_shared.h
index e3fe064..9f964d2 100644
--- a/drivers/char/adsprpc_shared.h
+++ b/drivers/char/adsprpc_shared.h
@@ -28,6 +28,7 @@
#define FASTRPC_IOCTL_GETPERF _IOWR('R', 9, struct fastrpc_ioctl_perf)
#define FASTRPC_IOCTL_INIT_ATTRS _IOWR('R', 10, struct fastrpc_ioctl_init_attrs)
#define FASTRPC_IOCTL_INVOKE_CRC _IOWR('R', 11, struct fastrpc_ioctl_invoke_crc)
+#define FASTRPC_IOCTL_CONTROL _IOWR('R', 12, struct fastrpc_ioctl_control)
#define FASTRPC_GLINK_GUID "fastrpcglink-apps-dsp"
#define FASTRPC_SMD_GUID "fastrpcsmd-apps-dsp"
@@ -100,7 +101,7 @@
#define VERIFY(err, val) \
do {\
VERIFY_IPRINTF(__FILE_LINE__"info: calling: " #val "\n");\
- if (0 == (val)) {\
+ if ((val) == 0) {\
(err) = (err) == 0 ? -1 : (err);\
VERIFY_EPRINTF(__FILE_LINE__"error: %d: " #val "\n", (err));\
} else {\
@@ -205,6 +206,19 @@
uintptr_t __user keys;
};
+#define FASTRPC_CONTROL_LATENCY (1)
+struct fastrpc_ctrl_latency {
+ uint32_t enable; //!latency control enable
+ uint32_t level; //!level of control
+};
+
+struct fastrpc_ioctl_control {
+ uint32_t req;
+ union {
+ struct fastrpc_ctrl_latency lp;
+ };
+};
+
struct smq_null_invoke {
uint64_t ctx; /* invoke caller context */
uint32_t handle; /* handle to invoke */
diff --git a/drivers/char/diag/diag_debugfs.c b/drivers/char/diag/diag_debugfs.c
index a0a9ab6..177bbdb 100644
--- a/drivers/char/diag/diag_debugfs.c
+++ b/drivers/char/diag/diag_debugfs.c
@@ -69,6 +69,7 @@
"Uses Device Tree: %d\n"
"Apps Supports Separate CMDRSP: %d\n"
"Apps Supports HDLC Encoding: %d\n"
+ "Apps Supports Header Untagging: %d\n"
"Apps Supports Sockets: %d\n"
"Logging Mode: %d\n"
"RSP Buffer is Busy: %d\n"
@@ -83,6 +84,7 @@
driver->use_device_tree,
driver->supports_separate_cmdrsp,
driver->supports_apps_hdlc_encoding,
+ driver->supports_apps_header_untagging,
driver->supports_sockets,
driver->logging_mode,
driver->rsp_buf_busy,
@@ -94,7 +96,7 @@
for (i = 0; i < NUM_PERIPHERALS; i++) {
ret += scnprintf(buf+ret, buf_size-ret,
- "p: %s Feature: %02x %02x |%c%c%c%c%c%c%c%c|\n",
+ "p: %s Feature: %02x %02x |%c%c%c%c%c%c%c%c%c|\n",
PERIPHERAL_STRING(i),
driver->feature[i].feature_mask[0],
driver->feature[i].feature_mask[1],
@@ -105,7 +107,8 @@
driver->feature[i].mask_centralization ? 'M':'m',
driver->feature[i].stm_support ? 'Q':'q',
driver->feature[i].sockets_enabled ? 'S':'s',
- driver->feature[i].sent_feature_mask ? 'T':'t');
+ driver->feature[i].sent_feature_mask ? 'T':'t',
+ driver->feature[i].untag_header ? 'U':'u');
}
#ifdef CONFIG_DIAG_OVER_USB
diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c
index 8aefb5a1..d734e29 100644
--- a/drivers/char/diag/diag_masks.c
+++ b/drivers/char/diag/diag_masks.c
@@ -28,7 +28,8 @@
#define DIAG_SET_FEATURE_MASK(x) (feature_bytes[(x)/8] |= (1 << (x & 0x7)))
#define diag_check_update(x) \
- (!info || (info && (info->peripheral_mask & MD_PERIPHERAL_MASK(x)))) \
+ (!info || (info && (info->peripheral_mask & MD_PERIPHERAL_MASK(x))) \
+ || (info && (info->peripheral_mask & MD_PERIPHERAL_PD_MASK(x)))) \
struct diag_mask_info msg_mask;
struct diag_mask_info msg_bt_mask;
@@ -90,8 +91,8 @@
int err = 0;
int send_once = 0;
int header_len = sizeof(struct diag_ctrl_log_mask);
- uint8_t *buf = NULL;
- uint8_t *temp = NULL;
+ uint8_t *buf = NULL, *temp = NULL;
+ uint8_t upd = 0;
uint32_t mask_size = 0;
struct diag_ctrl_log_mask ctrl_pkt;
struct diag_mask_info *mask_info = NULL;
@@ -107,11 +108,25 @@
return;
}
- if (driver->md_session_mask != 0 &&
- driver->md_session_mask & MD_PERIPHERAL_MASK(peripheral))
- mask_info = driver->md_session_map[peripheral]->log_mask;
- else
+ if (driver->md_session_mask != 0) {
+ if (driver->md_session_mask & MD_PERIPHERAL_MASK(peripheral)) {
+ if (driver->md_session_map[peripheral])
+ mask_info =
+ driver->md_session_map[peripheral]->log_mask;
+ } else if (driver->md_session_mask &
+ MD_PERIPHERAL_PD_MASK(peripheral)) {
+ upd = diag_mask_to_pd_value(driver->md_session_mask);
+ if (upd && driver->md_session_map[upd])
+ mask_info =
+ driver->md_session_map[upd]->log_mask;
+ } else {
+ DIAG_LOG(DIAG_DEBUG_MASKS,
+ "asking for mask update with unknown session mask\n");
+ return;
+ }
+ } else {
mask_info = &log_mask;
+ }
if (!mask_info || !mask_info->ptr || !mask_info->update_buf)
return;
@@ -196,8 +211,8 @@
static void diag_send_event_mask_update(uint8_t peripheral)
{
- uint8_t *buf = NULL;
- uint8_t *temp = NULL;
+ uint8_t *buf = NULL, *temp = NULL;
+ uint8_t upd = 0;
struct diag_ctrl_event_mask header;
struct diag_mask_info *mask_info = NULL;
int num_bytes = EVENT_COUNT_TO_BYTES(driver->last_event_id);
@@ -221,11 +236,25 @@
return;
}
- if (driver->md_session_mask != 0 &&
- (driver->md_session_mask & MD_PERIPHERAL_MASK(peripheral)))
- mask_info = driver->md_session_map[peripheral]->event_mask;
- else
+ if (driver->md_session_mask != 0) {
+ if (driver->md_session_mask & MD_PERIPHERAL_MASK(peripheral)) {
+ if (driver->md_session_map[peripheral])
+ mask_info =
+ driver->md_session_map[peripheral]->event_mask;
+ } else if (driver->md_session_mask &
+ MD_PERIPHERAL_PD_MASK(peripheral)) {
+ upd = diag_mask_to_pd_value(driver->md_session_mask);
+ if (upd && driver->md_session_map[upd])
+ mask_info =
+ driver->md_session_map[upd]->event_mask;
+ } else {
+ DIAG_LOG(DIAG_DEBUG_MASKS,
+ "asking for mask update with unknown session mask\n");
+ return;
+ }
+ } else {
mask_info = &event_mask;
+ }
if (!mask_info || !mask_info->ptr || !mask_info->update_buf)
return;
@@ -285,8 +314,8 @@
int err = 0;
int header_len = sizeof(struct diag_ctrl_msg_mask);
int temp_len = 0;
- uint8_t *buf = NULL;
- uint8_t *temp = NULL;
+ uint8_t *buf = NULL, *temp = NULL;
+ uint8_t upd = 0;
uint32_t mask_size = 0;
struct diag_mask_info *mask_info = NULL;
struct diag_msg_mask_t *mask = NULL;
@@ -303,11 +332,25 @@
return;
}
- if (driver->md_session_mask != 0 &&
- (driver->md_session_mask & MD_PERIPHERAL_MASK(peripheral)))
- mask_info = driver->md_session_map[peripheral]->msg_mask;
- else
+ if (driver->md_session_mask != 0) {
+ if (driver->md_session_mask & MD_PERIPHERAL_MASK(peripheral)) {
+ if (driver->md_session_map[peripheral])
+ mask_info =
+ driver->md_session_map[peripheral]->msg_mask;
+ } else if (driver->md_session_mask &
+ MD_PERIPHERAL_PD_MASK(peripheral)) {
+ upd = diag_mask_to_pd_value(driver->md_session_mask);
+ if (upd && driver->md_session_map[upd])
+ mask_info =
+ driver->md_session_map[upd]->msg_mask;
+ } else {
+ DIAG_LOG(DIAG_DEBUG_MASKS,
+ "asking for mask update with unknown session mask\n");
+ return;
+ }
+ } else {
mask_info = &msg_mask;
+ }
if (!mask_info || !mask_info->ptr || !mask_info->update_buf)
return;
@@ -466,6 +509,13 @@
DIAG_SET_FEATURE_MASK(F_DIAG_REQ_RSP_SUPPORT);
if (driver->supports_apps_hdlc_encoding)
DIAG_SET_FEATURE_MASK(F_DIAG_APPS_HDLC_ENCODE);
+ if (driver->supports_apps_header_untagging) {
+ if (peripheral == PERIPHERAL_MODEM) {
+ DIAG_SET_FEATURE_MASK(F_DIAG_PKT_HEADER_UNTAG);
+ driver->peripheral_untag[peripheral] =
+ ENABLE_PKT_HEADER_UNTAGGING;
+ }
+ }
DIAG_SET_FEATURE_MASK(F_DIAG_MASK_CENTRALIZATION);
if (driver->supports_sockets)
DIAG_SET_FEATURE_MASK(F_DIAG_SOCKETS_ENABLED);
@@ -1933,17 +1983,27 @@
void diag_send_updates_peripheral(uint8_t peripheral)
{
diag_send_feature_mask_update(peripheral);
- if (driver->time_sync_enabled)
- diag_send_time_sync_update(peripheral);
- mutex_lock(&driver->md_session_lock);
- diag_send_msg_mask_update(peripheral, ALL_SSID, ALL_SSID);
- diag_send_log_mask_update(peripheral, ALL_EQUIP_ID);
- diag_send_event_mask_update(peripheral);
- mutex_unlock(&driver->md_session_lock);
- diag_send_real_time_update(peripheral,
+ /*
+ * Masks (F3, logs and events) will be sent to
+ * peripheral immediately following feature mask update only
+ * if diag_id support is not present or
+ * diag_id support is present and diag_id has been sent to
+ * peripheral.
+ */
+ if (!driver->feature[peripheral].diag_id_support ||
+ driver->diag_id_sent[peripheral]) {
+ if (driver->time_sync_enabled)
+ diag_send_time_sync_update(peripheral);
+ mutex_lock(&driver->md_session_lock);
+ diag_send_msg_mask_update(peripheral, ALL_SSID, ALL_SSID);
+ diag_send_log_mask_update(peripheral, ALL_EQUIP_ID);
+ diag_send_event_mask_update(peripheral);
+ mutex_unlock(&driver->md_session_lock);
+ diag_send_real_time_update(peripheral,
driver->real_time_mode[DIAG_LOCAL_PROC]);
- diag_send_peripheral_buffering_mode(
- &driver->buffering_mode[peripheral]);
+ diag_send_peripheral_buffering_mode(
+ &driver->buffering_mode[peripheral]);
+ }
}
int diag_process_apps_masks(unsigned char *buf, int len,
diff --git a/drivers/char/diag/diag_memorydevice.c b/drivers/char/diag/diag_memorydevice.c
index 13ad402..7e3fe90 100644
--- a/drivers/char/diag/diag_memorydevice.c
+++ b/drivers/char/diag/diag_memorydevice.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, The Linux Foundation. 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 and
@@ -29,6 +29,7 @@
#include "diagmem.h"
#include "diagfwd.h"
#include "diagfwd_peripheral.h"
+#include "diag_ipc_logging.h"
struct diag_md_info diag_md[NUM_DIAG_MD_DEV] = {
{
@@ -132,7 +133,7 @@
uint8_t found = 0;
unsigned long flags;
struct diag_md_info *ch = NULL;
- uint8_t peripheral;
+ int peripheral;
struct diag_md_session_t *session_info = NULL;
if (id < 0 || id >= NUM_DIAG_MD_DEV || id >= DIAG_NUM_PROC)
@@ -141,11 +142,12 @@
if (!buf || len < 0)
return -EINVAL;
- peripheral = GET_BUF_PERIPHERAL(ctx);
- if (peripheral > NUM_PERIPHERALS)
+ peripheral = diag_md_get_peripheral(ctx);
+ if (peripheral < 0)
return -EINVAL;
- session_info = diag_md_session_get_peripheral(peripheral);
+ session_info =
+ diag_md_session_get_peripheral(peripheral);
if (!session_info)
return -EIO;
@@ -214,7 +216,7 @@
struct diag_md_info *ch = NULL;
struct diag_buf_tbl_t *entry = NULL;
uint8_t drain_again = 0;
- uint8_t peripheral = 0;
+ int peripheral = 0;
struct diag_md_session_t *session_info = NULL;
for (i = 0; i < NUM_DIAG_MD_DEV && !err; i++) {
@@ -223,12 +225,15 @@
entry = &ch->tbl[j];
if (entry->len <= 0)
continue;
- peripheral = GET_BUF_PERIPHERAL(entry->ctx);
- /* Account for Apps data as well */
- if (peripheral > NUM_PERIPHERALS)
+
+ peripheral = diag_md_get_peripheral(entry->ctx);
+ if (peripheral < 0)
goto drop_data;
session_info =
diag_md_session_get_peripheral(peripheral);
+ if (!session_info)
+ goto drop_data;
+
if (session_info && info &&
(session_info->pid != info->pid))
continue;
@@ -320,8 +325,15 @@
spin_lock_irqsave(&ch->lock, flags);
for (i = 0; i < ch->num_tbl_entries && !found; i++) {
entry = &ch->tbl[i];
- if (GET_BUF_PERIPHERAL(entry->ctx) != peripheral)
- continue;
+
+ if (peripheral > NUM_PERIPHERALS) {
+ if (GET_PD_CTXT(entry->ctx) != peripheral)
+ continue;
+ } else {
+ if (GET_BUF_PERIPHERAL(entry->ctx) !=
+ peripheral)
+ continue;
+ }
found = 1;
if (ch->ops && ch->ops->write_done) {
ch->ops->write_done(entry->buf, entry->len,
diff --git a/drivers/char/diag/diag_mux.c b/drivers/char/diag/diag_mux.c
index 8f5a002..e65b493 100644
--- a/drivers/char/diag/diag_mux.c
+++ b/drivers/char/diag/diag_mux.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, The Linux Foundation. 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 and
@@ -27,7 +27,8 @@
#include "diag_mux.h"
#include "diag_usb.h"
#include "diag_memorydevice.h"
-
+#include "diagfwd_peripheral.h"
+#include "diag_ipc_logging.h"
struct diag_mux_state_t *diag_mux;
static struct diag_logger_t usb_logger;
@@ -141,9 +142,13 @@
if (!diag_mux)
return -EIO;
- peripheral = GET_BUF_PERIPHERAL(ctx);
- if (peripheral > NUM_PERIPHERALS)
+ peripheral = diag_md_get_peripheral(ctx);
+ if (peripheral < 0) {
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+ "diag:%s:%d invalid peripheral = %d\n",
+ __func__, __LINE__, peripheral);
return -EINVAL;
+ }
if (MD_PERIPHERAL_MASK(peripheral) & diag_mux->mux_mask)
logger = diag_mux->md_ptr;
@@ -162,8 +167,13 @@
if (proc < 0 || proc >= NUM_MUX_PROC)
return -EINVAL;
/* Peripheral should account for Apps data as well */
- if (peripheral > NUM_PERIPHERALS)
- return -EINVAL;
+ if (peripheral > NUM_PERIPHERALS) {
+ if (!driver->num_pd_session)
+ return -EINVAL;
+ if (peripheral > NUM_MD_SESSIONS)
+ return -EINVAL;
+ }
+
if (!diag_mux)
return -EIO;
@@ -184,7 +194,8 @@
if (!req_mode)
return -EINVAL;
- if (*peripheral_mask <= 0 || *peripheral_mask > DIAG_CON_ALL) {
+ if (*peripheral_mask <= 0 ||
+ (*peripheral_mask > (DIAG_CON_ALL | DIAG_CON_UPD_ALL))) {
pr_err("diag: mask %d in %s\n", *peripheral_mask, __func__);
return -EINVAL;
}
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 26e91f9..ac3c1fd 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -58,19 +58,23 @@
#define DIAG_CTRL_MSG_F3_MASK 11
#define CONTROL_CHAR 0x7E
+#define DIAG_ID_ROOT_STRING "root"
+
#define DIAG_CON_APSS (0x0001) /* Bit mask for APSS */
#define DIAG_CON_MPSS (0x0002) /* Bit mask for MPSS */
#define DIAG_CON_LPASS (0x0004) /* Bit mask for LPASS */
#define DIAG_CON_WCNSS (0x0008) /* Bit mask for WCNSS */
#define DIAG_CON_SENSORS (0x0010) /* Bit mask for Sensors */
-#define DIAG_CON_WDSP (0x0020) /* Bit mask for WDSP */
-#define DIAG_CON_CDSP (0x0040)
+#define DIAG_CON_WDSP (0x0020) /* Bit mask for WDSP */
+#define DIAG_CON_CDSP (0x0040) /* Bit mask for CDSP */
+#define DIAG_CON_UPD_WLAN (0x1000) /*Bit mask for WLAN PD*/
#define DIAG_CON_NONE (0x0000) /* Bit mask for No SS*/
#define DIAG_CON_ALL (DIAG_CON_APSS | DIAG_CON_MPSS \
| DIAG_CON_LPASS | DIAG_CON_WCNSS \
| DIAG_CON_SENSORS | DIAG_CON_WDSP \
| DIAG_CON_CDSP)
+#define DIAG_CON_UPD_ALL (DIAG_CON_UPD_WLAN)
#define DIAG_STM_MODEM 0x01
#define DIAG_STM_LPASS 0x02
@@ -165,7 +169,7 @@
#define PKT_ALLOC 1
#define PKT_RESET 2
-#define FEATURE_MASK_LEN 2
+#define FEATURE_MASK_LEN 4
#define DIAG_MD_NONE 0
#define DIAG_MD_PERIPHERAL 1
@@ -209,11 +213,18 @@
#define NUM_PERIPHERALS 6
#define APPS_DATA (NUM_PERIPHERALS)
+#define UPD_WLAN 7
+#define NUM_UPD 1
+#define MAX_PERIPHERAL_UPD 1
/* Number of sessions possible in Memory Device Mode. +1 for Apps data */
-#define NUM_MD_SESSIONS (NUM_PERIPHERALS + 1)
+#define NUM_MD_SESSIONS (NUM_PERIPHERALS \
+ + NUM_UPD + 1)
#define MD_PERIPHERAL_MASK(x) (1 << x)
+#define MD_PERIPHERAL_PD_MASK(x) \
+ ((x == PERIPHERAL_MODEM) ? (1 << UPD_WLAN) : 0)\
+
/*
* Number of stm processors includes all the peripherals and
* apps.Added 1 below to indicate apps
@@ -439,6 +450,7 @@
struct diag_logging_mode_param_t {
uint32_t req_mode;
uint32_t peripheral_mask;
+ uint32_t pd_mask;
uint8_t mode_param;
} __packed;
@@ -485,11 +497,13 @@
uint8_t log_on_demand;
uint8_t separate_cmd_rsp;
uint8_t encode_hdlc;
+ uint8_t untag_header;
uint8_t peripheral_buffering;
uint8_t mask_centralization;
uint8_t stm_support;
uint8_t sockets_enabled;
uint8_t sent_feature_mask;
+ uint8_t diag_id_support;
};
struct diagchar_dev {
@@ -516,6 +530,8 @@
int use_device_tree;
int supports_separate_cmdrsp;
int supports_apps_hdlc_encoding;
+ int supports_apps_header_untagging;
+ int peripheral_untag[NUM_PERIPHERALS];
int supports_sockets;
/* The state requested in the STM command */
int stm_state_requested[NUM_STM_PROCESSORS];
@@ -580,6 +596,7 @@
unsigned char *buf_feature_mask_update;
uint8_t hdlc_disabled;
struct mutex hdlc_disable_mutex;
+ struct mutex hdlc_recovery_mutex;
struct timer_list hdlc_reset_timer;
struct mutex diag_hdlc_mutex;
unsigned char *hdlc_buf;
@@ -611,6 +628,10 @@
int in_busy_dcipktdata;
int logging_mode;
int logging_mask;
+ int pd_logging_mode[NUM_UPD];
+ int pd_session_clear[NUM_UPD];
+ int num_pd_session;
+ int diag_id_sent[NUM_PERIPHERALS];
int mask_check;
uint32_t md_session_mask;
uint8_t md_session_mode;
@@ -671,6 +692,7 @@
int diag_cmd_chk_polling(struct diag_cmd_reg_entry_t *entry);
int diag_mask_param(void);
void diag_clear_masks(struct diag_md_session_t *info);
+uint8_t diag_mask_to_pd_value(uint32_t peripheral_mask);
void diag_record_stats(int type, int flag);
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 5b507df..18f941d 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -393,9 +393,28 @@
ret |= DIAG_CON_WDSP;
if (peripheral_mask & MD_PERIPHERAL_MASK(PERIPHERAL_CDSP))
ret |= DIAG_CON_CDSP;
-
+ if (peripheral_mask & MD_PERIPHERAL_MASK(UPD_WLAN))
+ ret |= DIAG_CON_UPD_WLAN;
return ret;
}
+
+uint8_t diag_mask_to_pd_value(uint32_t peripheral_mask)
+{
+ uint8_t upd = 0;
+ uint32_t pd_mask = 0;
+
+ pd_mask = diag_translate_kernel_to_user_mask(peripheral_mask);
+ switch (pd_mask) {
+ case DIAG_CON_UPD_WLAN:
+ upd = UPD_WLAN;
+ break;
+ default:
+ DIAG_LOG(DIAG_DEBUG_MASKS,
+ "asking for mask update with no pd mask set\n");
+ }
+ return upd;
+}
+
int diag_mask_param(void)
{
return diag_mask_clear_param;
@@ -423,8 +442,9 @@
static void diag_close_logging_process(const int pid)
{
- int i;
- int session_peripheral_mask;
+ int i, j;
+ int session_mask;
+ uint32_t p_mask;
struct diag_md_session_t *session_info = NULL;
struct diag_logging_mode_param_t params;
@@ -440,18 +460,33 @@
mutex_unlock(&driver->diag_maskclear_mutex);
mutex_lock(&driver->diagchar_mutex);
- session_peripheral_mask = session_info->peripheral_mask;
+ session_mask = session_info->peripheral_mask;
diag_md_session_close(session_info);
- mutex_unlock(&driver->diagchar_mutex);
+
+ p_mask =
+ diag_translate_kernel_to_user_mask(session_mask);
+
for (i = 0; i < NUM_MD_SESSIONS; i++)
- if (MD_PERIPHERAL_MASK(i) & session_peripheral_mask)
+ if (MD_PERIPHERAL_MASK(i) & session_mask)
diag_mux_close_peripheral(DIAG_LOCAL_PROC, i);
params.req_mode = USB_MODE;
params.mode_param = 0;
- params.peripheral_mask =
- diag_translate_kernel_to_user_mask(session_peripheral_mask);
- mutex_lock(&driver->diagchar_mutex);
+ params.pd_mask = 0;
+ params.peripheral_mask = p_mask;
+
+ if (driver->num_pd_session > 0) {
+ for (i = UPD_WLAN; (i < NUM_MD_SESSIONS); i++) {
+ if (session_mask & MD_PERIPHERAL_MASK(i)) {
+ j = i - UPD_WLAN;
+ driver->pd_session_clear[j] = 1;
+ driver->pd_logging_mode[j] = 0;
+ driver->num_pd_session -= 1;
+ params.pd_mask = p_mask;
+ }
+ }
+ }
+
diag_switch_logging(¶ms);
mutex_unlock(&driver->diagchar_mutex);
}
@@ -654,6 +689,11 @@
driver->polling_reg_flag = 0;
list_for_each_safe(start, temp, &driver->cmd_reg_list) {
item = list_entry(start, struct diag_cmd_reg_t, link);
+ if (&item->entry == NULL) {
+ pr_err("diag: In %s, unable to search command\n",
+ __func__);
+ return;
+ }
polling = diag_cmd_chk_polling(&item->entry);
if (polling == DIAG_CMD_POLLING) {
driver->polling_reg_flag = 1;
@@ -793,6 +833,12 @@
mutex_lock(&driver->cmd_reg_mutex);
list_for_each_safe(start, temp, &driver->cmd_reg_list) {
item = list_entry(start, struct diag_cmd_reg_t, link);
+ if (&item->entry == NULL) {
+ pr_err("diag: In %s, unable to search command\n",
+ __func__);
+ mutex_unlock(&driver->cmd_reg_mutex);
+ return;
+ }
if (item->pid == pid) {
list_del(&item->link);
kfree(item);
@@ -811,6 +857,12 @@
mutex_lock(&driver->cmd_reg_mutex);
list_for_each_safe(start, temp, &driver->cmd_reg_list) {
item = list_entry(start, struct diag_cmd_reg_t, link);
+ if (&item->entry == NULL) {
+ pr_err("diag: In %s, unable to search command\n",
+ __func__);
+ mutex_unlock(&driver->cmd_reg_mutex);
+ return;
+ }
if (item->proc == proc) {
list_del(&item->link);
kfree(item);
@@ -975,14 +1027,34 @@
else
hdlc_disabled = driver->hdlc_disabled;
if (hdlc_disabled) {
+ if (len < 4) {
+ pr_err("diag: In %s, invalid len: %d of non_hdlc pkt",
+ __func__, len);
+ return -EBADMSG;
+ }
payload = *(uint16_t *)(buf + 2);
+ if (payload > DIAG_MAX_HDLC_BUF_SIZE) {
+ pr_err("diag: Dropping packet, payload size is %d\n",
+ payload);
+ return -EBADMSG;
+ }
driver->hdlc_encode_buf_len = payload;
/*
- * Adding 4 bytes for start (1 byte), version (1 byte) and
- * payload (2 bytes)
+ * Adding 5 bytes for start (1 byte), version (1 byte),
+ * payload (2 bytes) and end (1 byte)
*/
- memcpy(driver->hdlc_encode_buf, buf + 4, payload);
- goto send_data;
+ if (len == (payload + 5)) {
+ /*
+ * Adding 4 bytes for start (1 byte), version (1 byte)
+ * and payload (2 bytes)
+ */
+ memcpy(driver->hdlc_encode_buf, buf + 4, payload);
+ goto send_data;
+ } else {
+ pr_err("diag: In %s, invalid len: %d of non_hdlc pkt",
+ __func__, len);
+ return -EBADMSG;
+ }
}
if (hdlc_flag) {
@@ -1543,17 +1615,20 @@
ret |= (1 << PERIPHERAL_WDSP);
if (peripheral_mask & DIAG_CON_CDSP)
ret |= (1 << PERIPHERAL_CDSP);
+ if (peripheral_mask & DIAG_CON_UPD_WLAN)
+ ret |= (1 << UPD_WLAN);
return ret;
}
static int diag_switch_logging(struct diag_logging_mode_param_t *param)
{
- int new_mode;
+ int new_mode, i = 0;
int curr_mode;
int err = 0;
uint8_t do_switch = 1;
uint32_t peripheral_mask = 0;
+ uint8_t peripheral, upd;
if (!param)
return -EINVAL;
@@ -1564,8 +1639,41 @@
return -EINVAL;
}
- peripheral_mask = diag_translate_mask(param->peripheral_mask);
- param->peripheral_mask = peripheral_mask;
+ if (param->pd_mask) {
+ switch (param->pd_mask) {
+ case DIAG_CON_UPD_WLAN:
+ peripheral = PERIPHERAL_MODEM;
+ upd = UPD_WLAN;
+ break;
+ default:
+ DIAG_LOG(DIAG_DEBUG_USERSPACE,
+ "asking for mode switch with no pd mask set\n");
+ return -EINVAL;
+ }
+
+ if (driver->md_session_map[peripheral] &&
+ (MD_PERIPHERAL_MASK(peripheral) &
+ diag_mux->mux_mask)) {
+ DIAG_LOG(DIAG_DEBUG_USERSPACE,
+ "diag_fr: User PD is already logging onto active peripheral logging\n");
+ i = upd - UPD_WLAN;
+ driver->pd_session_clear[i] = 0;
+ return -EINVAL;
+ }
+ peripheral_mask =
+ diag_translate_mask(param->pd_mask);
+ param->peripheral_mask = peripheral_mask;
+ i = upd - UPD_WLAN;
+ if (!driver->pd_session_clear[i]) {
+ driver->pd_logging_mode[i] = 1;
+ driver->num_pd_session += 1;
+ }
+ driver->pd_session_clear[i] = 0;
+ } else {
+ peripheral_mask =
+ diag_translate_mask(param->peripheral_mask);
+ param->peripheral_mask = peripheral_mask;
+ }
switch (param->req_mode) {
case CALLBACK_MODE:
@@ -1585,7 +1693,7 @@
curr_mode = driver->logging_mode;
DIAG_LOG(DIAG_DEBUG_USERSPACE,
- "request to switch logging from %d mask:%0x to %d mask:%0x\n",
+ "request to switch logging from %d mask:%0x to new_mode %d mask:%0x\n",
curr_mode, driver->md_session_mask, new_mode, peripheral_mask);
err = diag_md_session_check(curr_mode, new_mode, param, &do_switch);
@@ -1909,6 +2017,52 @@
return 0;
}
+static int diag_ioctl_query_pd_logging(struct diag_logging_mode_param_t *param)
+{
+ int ret = -EINVAL;
+ int peripheral;
+ char *p_str = NULL;
+
+ if (!param)
+ return -EINVAL;
+
+ if (!param->pd_mask) {
+ DIAG_LOG(DIAG_DEBUG_USERSPACE,
+ "query with no pd mask set, returning error\n");
+ return -EINVAL;
+ }
+
+ switch (param->pd_mask) {
+ case DIAG_CON_UPD_WLAN:
+ peripheral = PERIPHERAL_MODEM;
+ p_str = "MODEM";
+ break;
+ default:
+ DIAG_LOG(DIAG_DEBUG_USERSPACE,
+ "Invalid pd mask, returning EINVAL\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&driver->diag_cntl_mutex);
+ DIAG_LOG(DIAG_DEBUG_USERSPACE,
+ "diag: %s: Untagging support on APPS is %s\n", __func__,
+ ((driver->supports_apps_header_untagging) ?
+ "present" : "absent"));
+
+ DIAG_LOG(DIAG_DEBUG_USERSPACE,
+ "diag: %s: Tagging support on %s is %s\n",
+ __func__, p_str,
+ (driver->feature[peripheral].untag_header ?
+ "present" : "absent"));
+
+ if (driver->supports_apps_header_untagging &&
+ driver->feature[peripheral].untag_header)
+ ret = 0;
+
+ mutex_unlock(&driver->diag_cntl_mutex);
+ return ret;
+}
+
static int diag_ioctl_register_callback(unsigned long ioarg)
{
int err = 0;
@@ -2146,6 +2300,12 @@
case DIAG_IOCTL_HDLC_TOGGLE:
result = diag_ioctl_hdlc_toggle(ioarg);
break;
+ case DIAG_IOCTL_QUERY_PD_LOGGING:
+ if (copy_from_user((void *)&mode_param, (void __user *)ioarg,
+ sizeof(mode_param)))
+ return -EFAULT;
+ result = diag_ioctl_query_pd_logging(&mode_param);
+ break;
}
return result;
}
@@ -2269,6 +2429,12 @@
case DIAG_IOCTL_HDLC_TOGGLE:
result = diag_ioctl_hdlc_toggle(ioarg);
break;
+ case DIAG_IOCTL_QUERY_PD_LOGGING:
+ if (copy_from_user((void *)&mode_param, (void __user *)ioarg,
+ sizeof(mode_param)))
+ return -EFAULT;
+ result = diag_ioctl_query_pd_logging(&mode_param);
+ break;
}
return result;
}
@@ -2790,6 +2956,16 @@
return 0;
}
+static int check_data_ready(int index)
+{
+ int data_type = 0;
+
+ mutex_lock(&driver->diagchar_mutex);
+ data_type = driver->data_ready[index];
+ mutex_unlock(&driver->diagchar_mutex);
+ return data_type;
+}
+
static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count,
loff_t *ppos)
{
@@ -2802,9 +2978,11 @@
int write_len = 0;
struct diag_md_session_t *session_info = NULL;
+ mutex_lock(&driver->diagchar_mutex);
for (i = 0; i < driver->num_clients; i++)
if (driver->client_map[i].pid == current->tgid)
index = i;
+ mutex_unlock(&driver->diagchar_mutex);
if (index == -1) {
pr_err("diag: Client PID not found in table");
@@ -2814,7 +2992,7 @@
pr_err("diag: bad address from user side\n");
return -EFAULT;
}
- wait_event_interruptible(driver->wait_q, driver->data_ready[index]);
+ wait_event_interruptible(driver->wait_q, (check_data_ready(index)) > 0);
mutex_lock(&driver->diagchar_mutex);
@@ -3002,11 +3180,11 @@
}
exit:
- mutex_unlock(&driver->diagchar_mutex);
if (driver->data_ready[index] & DCI_DATA_TYPE) {
- mutex_lock(&driver->dci_mutex);
- /* Copy the type of data being passed */
data_type = driver->data_ready[index] & DCI_DATA_TYPE;
+ mutex_unlock(&driver->diagchar_mutex);
+ /* Copy the type of data being passed */
+ mutex_lock(&driver->dci_mutex);
list_for_each_safe(start, temp, &driver->dci_client_list) {
entry = list_entry(start, struct diag_dci_client_tbl,
track);
@@ -3038,6 +3216,7 @@
mutex_unlock(&driver->dci_mutex);
goto end;
}
+ mutex_unlock(&driver->diagchar_mutex);
end:
/*
* Flush any read that is currently pending on DCI data and
@@ -3322,7 +3501,7 @@
* to be logged to IPC
*/
diag_debug_mask = DIAG_DEBUG_PERIPHERALS | DIAG_DEBUG_DCI |
- DIAG_DEBUG_BRIDGE;
+ DIAG_DEBUG_USERSPACE | DIAG_DEBUG_BRIDGE;
}
#else
static void diag_debug_init(void)
@@ -3452,6 +3631,11 @@
poolsize_usb_apps + 1 + (NUM_PERIPHERALS * 6));
driver->num_clients = max_clients;
driver->logging_mode = DIAG_USB_MODE;
+ for (i = 0; i < NUM_UPD; i++) {
+ driver->pd_logging_mode[i] = 0;
+ driver->pd_session_clear[i] = 0;
+ }
+ driver->num_pd_session = 0;
driver->mask_check = 0;
driver->in_busy_pktdata = 0;
driver->in_busy_dcipktdata = 0;
@@ -3468,8 +3652,11 @@
mutex_init(&driver->delayed_rsp_mutex);
mutex_init(&apps_data_mutex);
mutex_init(&driver->msg_mask_lock);
- for (i = 0; i < NUM_PERIPHERALS; i++)
+ mutex_init(&driver->hdlc_recovery_mutex);
+ for (i = 0; i < NUM_PERIPHERALS; i++) {
mutex_init(&driver->diagfwd_channel_mutex[i]);
+ driver->diag_id_sent[i] = 0;
+ }
init_waitqueue_head(&driver->wait_q);
INIT_WORK(&(driver->diag_drain_work), diag_drain_work_fn);
INIT_WORK(&(driver->update_user_clients),
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index cd49f00..b59f245 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -38,6 +38,7 @@
#include "diag_masks.h"
#include "diag_usb.h"
#include "diag_mux.h"
+#include "diag_ipc_logging.h"
#define STM_CMD_VERSION_OFFSET 4
#define STM_CMD_MASK_OFFSET 5
@@ -1443,7 +1444,9 @@
if (start_ptr) {
/* Discard any partial packet reads */
+ mutex_lock(&driver->hdlc_recovery_mutex);
driver->incoming_pkt.processing = 0;
+ mutex_unlock(&driver->hdlc_recovery_mutex);
diag_process_non_hdlc_pkt(start_ptr, len - i, info);
}
}
@@ -1457,18 +1460,24 @@
const uint32_t header_len = sizeof(struct diag_pkt_frame_t);
struct diag_pkt_frame_t *actual_pkt = NULL;
unsigned char *data_ptr = NULL;
- struct diag_partial_pkt_t *partial_pkt = &driver->incoming_pkt;
+ struct diag_partial_pkt_t *partial_pkt = NULL;
- if (!buf || len <= 0)
+ mutex_lock(&driver->hdlc_recovery_mutex);
+ if (!buf || len <= 0) {
+ mutex_unlock(&driver->hdlc_recovery_mutex);
return;
-
- if (!partial_pkt->processing)
+ }
+ partial_pkt = &driver->incoming_pkt;
+ if (!partial_pkt->processing) {
+ mutex_unlock(&driver->hdlc_recovery_mutex);
goto start;
+ }
if (partial_pkt->remaining > len) {
if ((partial_pkt->read_len + len) > partial_pkt->capacity) {
pr_err("diag: Invalid length %d, %d received in %s\n",
partial_pkt->read_len, len, __func__);
+ mutex_unlock(&driver->hdlc_recovery_mutex);
goto end;
}
memcpy(partial_pkt->data + partial_pkt->read_len, buf, len);
@@ -1482,6 +1491,7 @@
pr_err("diag: Invalid length during partial read %d, %d received in %s\n",
partial_pkt->read_len,
partial_pkt->remaining, __func__);
+ mutex_unlock(&driver->hdlc_recovery_mutex);
goto end;
}
memcpy(partial_pkt->data + partial_pkt->read_len, buf,
@@ -1495,20 +1505,27 @@
if (partial_pkt->remaining == 0) {
actual_pkt = (struct diag_pkt_frame_t *)(partial_pkt->data);
data_ptr = partial_pkt->data + header_len;
- if (*(uint8_t *)(data_ptr + actual_pkt->length) != CONTROL_CHAR)
+ if (*(uint8_t *)(data_ptr + actual_pkt->length) !=
+ CONTROL_CHAR) {
+ mutex_unlock(&driver->hdlc_recovery_mutex);
diag_hdlc_start_recovery(buf, len, info);
+ mutex_lock(&driver->hdlc_recovery_mutex);
+ }
err = diag_process_apps_pkt(data_ptr,
actual_pkt->length, info);
if (err) {
pr_err("diag: In %s, unable to process incoming data packet, err: %d\n",
__func__, err);
+ mutex_unlock(&driver->hdlc_recovery_mutex);
goto end;
}
partial_pkt->read_len = 0;
partial_pkt->total_len = 0;
partial_pkt->processing = 0;
+ mutex_unlock(&driver->hdlc_recovery_mutex);
goto start;
}
+ mutex_unlock(&driver->hdlc_recovery_mutex);
goto end;
start:
@@ -1521,14 +1538,14 @@
diag_send_error_rsp(buf, len);
goto end;
}
-
+ mutex_lock(&driver->hdlc_recovery_mutex);
if (pkt_len + header_len > partial_pkt->capacity) {
pr_err("diag: In %s, incoming data is too large for the request buffer %d\n",
__func__, pkt_len);
+ mutex_unlock(&driver->hdlc_recovery_mutex);
diag_hdlc_start_recovery(buf, len, info);
break;
}
-
if ((pkt_len + header_len) > (len - read_bytes)) {
partial_pkt->read_len = len - read_bytes;
partial_pkt->total_len = pkt_len + header_len;
@@ -1536,19 +1553,27 @@
partial_pkt->read_len;
partial_pkt->processing = 1;
memcpy(partial_pkt->data, buf, partial_pkt->read_len);
+ mutex_unlock(&driver->hdlc_recovery_mutex);
break;
}
data_ptr = buf + header_len;
- if (*(uint8_t *)(data_ptr + actual_pkt->length) != CONTROL_CHAR)
+ if (*(uint8_t *)(data_ptr + actual_pkt->length) !=
+ CONTROL_CHAR) {
+ mutex_unlock(&driver->hdlc_recovery_mutex);
diag_hdlc_start_recovery(buf, len, info);
+ mutex_lock(&driver->hdlc_recovery_mutex);
+ }
else
hdlc_reset = 0;
err = diag_process_apps_pkt(data_ptr,
actual_pkt->length, info);
- if (err)
+ if (err) {
+ mutex_unlock(&driver->hdlc_recovery_mutex);
break;
+ }
read_bytes += header_len + pkt_len + 1;
buf += header_len + pkt_len + 1; /* advance to next pkt */
+ mutex_unlock(&driver->hdlc_recovery_mutex);
}
end:
return;
@@ -1639,6 +1664,9 @@
driver->real_time_mode[i] = 1;
driver->supports_separate_cmdrsp = 1;
driver->supports_apps_hdlc_encoding = 1;
+ driver->supports_apps_header_untagging = 1;
+ for (i = 0; i < NUM_PERIPHERALS; i++)
+ driver->peripheral_untag[i] = 0;
mutex_init(&driver->diag_hdlc_mutex);
mutex_init(&driver->diag_cntl_mutex);
mutex_init(&driver->mode_lock);
@@ -1668,9 +1696,12 @@
driver->feature[i].rcvd_feature_mask = 0;
driver->feature[i].peripheral_buffering = 0;
driver->feature[i].encode_hdlc = 0;
+ driver->feature[i].untag_header =
+ DISABLE_PKT_HEADER_UNTAGGING;
driver->feature[i].mask_centralization = 0;
driver->feature[i].log_on_demand = 0;
driver->feature[i].sent_feature_mask = 0;
+ driver->feature[i].diag_id_support = 0;
driver->buffering_mode[i].peripheral = i;
driver->buffering_mode[i].mode = DIAG_BUFFERING_MODE_STREAMING;
driver->buffering_mode[i].high_wm_val = DEFAULT_HIGH_WM_VAL;
diff --git a/drivers/char/diag/diagfwd.h b/drivers/char/diag/diagfwd.h
index 47c8555..677099f 100644
--- a/drivers/char/diag/diagfwd.h
+++ b/drivers/char/diag/diagfwd.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2017, The Linux Foundation. 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 and
@@ -19,9 +19,11 @@
*/
#define SET_BUF_CTXT(p, d, n) \
(((p & 0xFF) << 16) | ((d & 0xFF) << 8) | (n & 0xFF))
+#define SET_PD_CTXT(u) ((u & 0xFF) << 24)
#define GET_BUF_PERIPHERAL(p) ((p & 0xFF0000) >> 16)
#define GET_BUF_TYPE(d) ((d & 0x00FF00) >> 8)
#define GET_BUF_NUM(n) ((n & 0x0000FF))
+#define GET_PD_CTXT(u) ((u & 0xFF000000) >> 24)
#define CHK_OVERFLOW(bufStart, start, end, length) \
((((bufStart) <= (start)) && ((end) - (start) >= (length))) ? 1 : 0)
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index c975654..d7e24fc 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -68,9 +68,9 @@
driver->feature[peripheral].sent_feature_mask = 0;
driver->feature[peripheral].rcvd_feature_mask = 0;
- flush_workqueue(driver->cntl_wq);
reg_dirty |= PERIPHERAL_MASK(peripheral);
diag_cmd_remove_reg_by_proc(peripheral);
+ driver->diag_id_sent[peripheral] = 0;
driver->feature[peripheral].stm_support = DISABLE_STM;
driver->feature[peripheral].log_on_demand = 0;
driver->stm_state[peripheral] = DISABLE_STM;
@@ -199,6 +199,20 @@
}
}
+static void process_upd_header_untagging_feature(uint8_t peripheral)
+{
+ if (peripheral >= NUM_PERIPHERALS)
+ return;
+
+ if (driver->supports_apps_header_untagging) {
+ driver->feature[peripheral].untag_header =
+ ENABLE_PKT_HEADER_UNTAGGING;
+ } else {
+ driver->feature[peripheral].untag_header =
+ DISABLE_PKT_HEADER_UNTAGGING;
+ }
+}
+
static void process_command_deregistration(uint8_t *buf, uint32_t len,
uint8_t peripheral)
{
@@ -375,6 +389,8 @@
driver->feature[peripheral].separate_cmd_rsp = 1;
if (FEATURE_SUPPORTED(F_DIAG_APPS_HDLC_ENCODE))
process_hdlc_encoding_feature(peripheral);
+ if (FEATURE_SUPPORTED(F_DIAG_PKT_HEADER_UNTAG))
+ process_upd_header_untagging_feature(peripheral);
if (FEATURE_SUPPORTED(F_DIAG_STM))
enable_stm_feature(peripheral);
if (FEATURE_SUPPORTED(F_DIAG_MASK_CENTRALIZATION))
@@ -383,6 +399,8 @@
driver->feature[peripheral].peripheral_buffering = 1;
if (FEATURE_SUPPORTED(F_DIAG_SOCKETS_ENABLED))
enable_socket_feature(peripheral);
+ if (FEATURE_SUPPORTED(F_DIAG_DIAGID_SUPPORT))
+ driver->feature[peripheral].diag_id_support = 1;
}
process_socket_feature(peripheral);
@@ -707,12 +725,24 @@
{
struct diag_ctrl_diagid *header = NULL;
struct diag_ctrl_diagid ctrl_pkt;
+ struct diagfwd_info *fwd_info_data = NULL;
+ struct diagfwd_info *fwd_info_cmd = NULL;
char *process_name = NULL;
int err = 0;
uint8_t local_diag_id = 0;
+ uint8_t new_request = 0;
if (!buf || len == 0 || peripheral >= NUM_PERIPHERALS)
return;
+
+ fwd_info_data = &peripheral_info[TYPE_DATA][peripheral];
+ if (!fwd_info_data)
+ return;
+
+ fwd_info_cmd = &peripheral_info[TYPE_CMD][peripheral];
+ if (!fwd_info_cmd)
+ return;
+
header = (struct diag_ctrl_diagid *)buf;
process_name = (char *)&header->process_name;
if (diag_query_diag_id(process_name, &local_diag_id))
@@ -721,7 +751,27 @@
diag_id++;
diag_add_diag_id_to_list(diag_id, process_name);
ctrl_pkt.diag_id = diag_id;
+ new_request = 1;
}
+
+ if (new_request) {
+ fwd_info_data->num_pd++;
+ fwd_info_cmd->num_pd++;
+ }
+
+ if (strnstr(process_name, DIAG_ID_ROOT_STRING, strlen(process_name))) {
+ fwd_info_cmd->diagid_root = diag_id;
+ fwd_info_data->diagid_root = diag_id;
+ driver->diag_id_sent[peripheral] = 0;
+ } else {
+ fwd_info_cmd->diagid_user[fwd_info_cmd->num_pd - 2] = diag_id;
+ fwd_info_data->diagid_user[fwd_info_data->num_pd - 2] = diag_id;
+ }
+
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+ "diag: peripheral = %d: diag_id string = %s,diag_id = %d\n",
+ peripheral, process_name, ctrl_pkt.diag_id);
+
ctrl_pkt.pkt_id = DIAG_CTRL_MSG_DIAGID;
ctrl_pkt.version = 1;
strlcpy((char *)&ctrl_pkt.process_name, process_name,
@@ -731,8 +781,21 @@
err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt, ctrl_pkt.len +
sizeof(ctrl_pkt.pkt_id) + sizeof(ctrl_pkt.len));
if (err && err != -ENODEV) {
- pr_err("diag: Unable to send diag id ctrl packet to peripheral %d, err: %d\n",
+ pr_err("diag: Unable to send diag id ctrl packet to peripheral %d, err: %d\n",
peripheral, err);
+ } else {
+ /*
+ * Masks (F3, logs and events) will be sent to
+ * peripheral immediately following feature mask update only
+ * if diag_id support is not present or
+ * diag_id support is present and diag_id has been sent to
+ * peripheral.
+ * With diag_id being sent now, mask will be updated
+ * to peripherals.
+ */
+ driver->diag_id_sent[peripheral] = 1;
+ diag_send_updates_peripheral(peripheral);
+ diagfwd_buffers_init(fwd_info_data);
}
}
diff --git a/drivers/char/diag/diagfwd_cntl.h b/drivers/char/diag/diagfwd_cntl.h
index 7823040..8b22d7e 100644
--- a/drivers/char/diag/diagfwd_cntl.h
+++ b/drivers/char/diag/diagfwd_cntl.h
@@ -68,6 +68,7 @@
#define F_DIAG_SOCKETS_ENABLED 13
#define F_DIAG_DCI_EXTENDED_HEADER_SUPPORT 14
#define F_DIAG_DIAGID_SUPPORT 15
+#define F_DIAG_PKT_HEADER_UNTAG 16
#define ENABLE_SEPARATE_CMDRSP 1
#define DISABLE_SEPARATE_CMDRSP 0
@@ -82,6 +83,9 @@
#define ENABLE_APPS_HDLC_ENCODING 1
#define DISABLE_APPS_HDLC_ENCODING 0
+#define ENABLE_PKT_HEADER_UNTAGGING 1
+#define DISABLE_PKT_HEADER_UNTAGGING 0
+
#define DIAG_MODE_PKT_LEN 36
struct diag_ctrl_pkt_header_t {
@@ -279,6 +283,7 @@
void diag_cntl_process_read_data(struct diagfwd_info *p_info, void *buf,
int len);
int diag_send_real_time_update(uint8_t peripheral, int real_time);
+void diag_map_pd_to_diagid(uint8_t pd, uint8_t *diag_id, int *peripheral);
int diag_send_peripheral_buffering_mode(struct diag_buffering_mode_t *params);
void diag_update_proc_vote(uint16_t proc, uint8_t vote, int index);
void diag_update_real_time_vote(uint16_t proc, uint8_t real_time, int index);
diff --git a/drivers/char/diag/diagfwd_glink.c b/drivers/char/diag/diagfwd_glink.c
index 6476684..e9683e0 100644
--- a/drivers/char/diag/diagfwd_glink.c
+++ b/drivers/char/diag/diagfwd_glink.c
@@ -375,8 +375,10 @@
struct diag_glink_read_work, work);
struct diag_glink_info *glink_info = read_work->glink_info;
- if (!glink_info || !glink_info->hdl)
+ if (!glink_info || !glink_info->hdl) {
+ kfree(read_work);
return;
+ }
diagfwd_channel_read_done(glink_info->fwd_ctxt,
(unsigned char *)(read_work->ptr_read_done),
@@ -388,6 +390,7 @@
"diag: Rx done for packet %pK of len: %d periph: %d ch: %d\n",
read_work->ptr_rx_done, (int)read_work->ptr_read_size,
glink_info->peripheral, glink_info->type);
+ kfree(read_work);
}
static void diag_glink_notify_rx(void *hdl, const void *priv,
@@ -411,6 +414,7 @@
if (!read_work) {
DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
"diag: Could not allocate read_work\n");
+ glink_rx_done(glink_info->hdl, ptr, true);
return;
}
diff --git a/drivers/char/diag/diagfwd_peripheral.c b/drivers/char/diag/diagfwd_peripheral.c
index 3b8203f..955d81f 100644
--- a/drivers/char/diag/diagfwd_peripheral.c
+++ b/drivers/char/diag/diagfwd_peripheral.c
@@ -45,6 +45,8 @@
static void diagfwd_cntl_close(struct diagfwd_info *fwd_info);
static void diagfwd_dci_open(struct diagfwd_info *fwd_info);
static void diagfwd_dci_close(struct diagfwd_info *fwd_info);
+static void diagfwd_data_read_untag_done(struct diagfwd_info *fwd_info,
+ unsigned char *buf, int len);
static void diagfwd_data_read_done(struct diagfwd_info *fwd_info,
unsigned char *buf, int len);
static void diagfwd_cntl_read_done(struct diagfwd_info *fwd_info,
@@ -58,7 +60,7 @@
static struct diag_channel_ops data_ch_ops = {
.open = NULL,
.close = NULL,
- .read_done = diagfwd_data_read_done
+ .read_done = diagfwd_data_read_untag_done
};
static struct diag_channel_ops cntl_ch_ops = {
@@ -213,6 +215,317 @@
return buf->len;
}
+int diag_md_get_peripheral(int ctxt)
+{
+ int pd = 0, i = 0;
+ int type = 0, peripheral = -EINVAL;
+ struct diagfwd_info *fwd_info = NULL;
+
+ peripheral = GET_BUF_PERIPHERAL(ctxt);
+ if (peripheral < 0 || peripheral > NUM_PERIPHERALS)
+ return -EINVAL;
+
+ if (peripheral == APPS_DATA)
+ return peripheral;
+
+ type = GET_BUF_TYPE(ctxt);
+ if (type < 0 || type >= NUM_TYPES)
+ return -EINVAL;
+
+ fwd_info = &peripheral_info[type][peripheral];
+ if (!fwd_info)
+ return -EINVAL;
+
+ pd = GET_PD_CTXT(ctxt);
+
+ if (driver->num_pd_session) {
+ if (pd == fwd_info->diagid_root) {
+ if (peripheral > NUM_PERIPHERALS)
+ peripheral = -EINVAL;
+ } else {
+ for (i = 0; i <= (fwd_info->num_pd - 2); i++) {
+ if (pd == fwd_info->diagid_user[i]) {
+ switch (peripheral) {
+ case PERIPHERAL_MODEM:
+ if (driver->pd_logging_mode[0])
+ peripheral = UPD_WLAN;
+ break;
+ default:
+ peripheral = -EINVAL;
+ break;
+ }
+ }
+ }
+ }
+ }
+ return peripheral;
+}
+
+static void diagfwd_data_process_done(struct diagfwd_info *fwd_info,
+ struct diagfwd_buf_t *buf, int len)
+{
+ int err = 0;
+ int write_len = 0, peripheral = 0;
+ unsigned char *write_buf = NULL;
+ struct diag_md_session_t *session_info = NULL;
+ uint8_t hdlc_disabled = 0;
+
+ if (!fwd_info || !buf || len <= 0) {
+ diag_ws_release();
+ return;
+ }
+
+ switch (fwd_info->type) {
+ case TYPE_DATA:
+ case TYPE_CMD:
+ break;
+ default:
+ pr_err_ratelimited("diag: In %s, invalid type %d for peripheral %d\n",
+ __func__, fwd_info->type,
+ fwd_info->peripheral);
+ diag_ws_release();
+ return;
+ }
+
+ mutex_lock(&driver->hdlc_disable_mutex);
+ mutex_lock(&fwd_info->data_mutex);
+
+ peripheral =
+ diag_md_get_peripheral(buf->ctxt);
+ if (peripheral < 0) {
+ pr_err("diag:%s:%d invalid peripheral = %d\n",
+ __func__, __LINE__, peripheral);
+ mutex_unlock(&fwd_info->data_mutex);
+ mutex_unlock(&driver->hdlc_disable_mutex);
+ diag_ws_release();
+ return;
+ }
+
+ session_info =
+ diag_md_session_get_peripheral(peripheral);
+ if (session_info)
+ hdlc_disabled = session_info->hdlc_disabled;
+ else
+ hdlc_disabled = driver->hdlc_disabled;
+
+ if (hdlc_disabled) {
+ /* The data is raw and and on APPS side HDLC is disabled */
+ if (!buf) {
+ pr_err("diag: In %s, no match for non encode buffer %pK, peripheral %d, type: %d\n",
+ __func__, buf, fwd_info->peripheral,
+ fwd_info->type);
+ goto end;
+ }
+ if (len > PERIPHERAL_BUF_SZ) {
+ pr_err("diag: In %s, Incoming buffer too large %d, peripheral %d, type: %d\n",
+ __func__, len, fwd_info->peripheral,
+ fwd_info->type);
+ goto end;
+ }
+ write_len = len;
+ if (write_len <= 0)
+ goto end;
+ write_buf = buf->data_raw;
+ } else {
+ if (!buf) {
+ pr_err("diag: In %s, no match for non encode buffer %pK, peripheral %d, type: %d\n",
+ __func__, buf, fwd_info->peripheral,
+ fwd_info->type);
+ goto end;
+ }
+
+ write_len = check_bufsize_for_encoding(buf, len);
+ if (write_len <= 0) {
+ pr_err("diag: error in checking buf for encoding\n");
+ goto end;
+ }
+ write_buf = buf->data;
+ err = diag_add_hdlc_encoding(write_buf, &write_len,
+ buf->data_raw, len);
+ if (err) {
+ pr_err("diag: error in adding hdlc encoding\n");
+ goto end;
+ }
+ }
+
+ if (write_len > 0) {
+ err = diag_mux_write(DIAG_LOCAL_PROC, write_buf, write_len,
+ buf->ctxt);
+ if (err) {
+ pr_err_ratelimited("diag: In %s, unable to write to mux error: %d\n",
+ __func__, err);
+ goto end;
+ }
+ }
+ mutex_unlock(&fwd_info->data_mutex);
+ mutex_unlock(&driver->hdlc_disable_mutex);
+ diagfwd_queue_read(fwd_info);
+ return;
+
+end:
+ diag_ws_release();
+ mutex_unlock(&fwd_info->data_mutex);
+ mutex_unlock(&driver->hdlc_disable_mutex);
+ if (buf) {
+ diagfwd_write_done(fwd_info->peripheral, fwd_info->type,
+ GET_BUF_NUM(buf->ctxt));
+ }
+ diagfwd_queue_read(fwd_info);
+}
+
+static void diagfwd_data_read_untag_done(struct diagfwd_info *fwd_info,
+ unsigned char *buf, int len)
+{
+ int i = 0;
+ int len_cpd = 0;
+ int ctxt_cpd = 0;
+ int len_upd[MAX_PERIPHERAL_UPD] = {0};
+ int ctxt_upd[MAX_PERIPHERAL_UPD] = {0};
+ int packet_len = 0, processed = 0;
+ unsigned char *temp_buf_main = NULL;
+ unsigned char *temp_buf_cpd = NULL;
+ unsigned char *temp_buf_upd[MAX_PERIPHERAL_UPD] = {NULL};
+ struct diagfwd_buf_t *temp_fwdinfo_cpd = NULL;
+ struct diagfwd_buf_t *temp_fwdinfo_upd = NULL;
+ int flag_buf_1 = 0, flag_buf_2 = 0;
+ uint8_t peripheral;
+
+ if (!fwd_info || !buf || len <= 0) {
+ diag_ws_release();
+ return;
+ }
+
+ switch (fwd_info->type) {
+ case TYPE_DATA:
+ case TYPE_CMD:
+ break;
+ default:
+ pr_err_ratelimited("diag: In %s, invalid type %d for peripheral %d\n",
+ __func__, fwd_info->type,
+ fwd_info->peripheral);
+ diag_ws_release();
+ return;
+ }
+ peripheral = fwd_info->peripheral;
+ if (peripheral >= NUM_PERIPHERALS)
+ return;
+
+ if (driver->feature[peripheral].encode_hdlc &&
+ driver->feature[peripheral].untag_header &&
+ driver->peripheral_untag[peripheral]) {
+ temp_buf_cpd = buf;
+ temp_buf_main = buf;
+ if (fwd_info->buf_1 &&
+ fwd_info->buf_1->data_raw == buf) {
+ flag_buf_1 = 1;
+ temp_fwdinfo_cpd = fwd_info->buf_1;
+ if (fwd_info->type == TYPE_DATA) {
+ for (i = 0; i <= (fwd_info->num_pd - 2); i++)
+ temp_buf_upd[i] =
+ fwd_info->buf_upd[i][0]->data_raw;
+ }
+ } else if (fwd_info->buf_2 &&
+ fwd_info->buf_2->data_raw == buf) {
+ flag_buf_2 = 1;
+ temp_fwdinfo_cpd = fwd_info->buf_2;
+ if (fwd_info->type == TYPE_DATA) {
+ for (i = 0; i <= (fwd_info->num_pd - 2); i++)
+ temp_buf_upd[i] =
+ fwd_info->buf_upd[i][1]->data_raw;
+ }
+ } else {
+ pr_err("diag: In %s, no match for buffer %pK, peripheral %d, type: %d\n",
+ __func__, buf, peripheral,
+ fwd_info->type);
+ goto end;
+ }
+
+ while (processed < len) {
+ pr_debug("diag_fr:untagged packet buf contents: %02x %02x %02x %02x\n",
+ *temp_buf_main, *(temp_buf_main+1),
+ *(temp_buf_main+2), *(temp_buf_main+3));
+ packet_len =
+ *(uint16_t *) (temp_buf_main + 2);
+ if (packet_len > PERIPHERAL_BUF_SZ)
+ goto end;
+ if ((*temp_buf_main) == fwd_info->diagid_root) {
+ ctxt_cpd = fwd_info->diagid_root;
+ len_cpd += packet_len;
+ if (temp_buf_cpd) {
+ memcpy(temp_buf_cpd,
+ (temp_buf_main + 4), packet_len);
+ temp_buf_cpd += packet_len;
+ }
+ } else {
+ for (i = 0; i <= (fwd_info->num_pd - 2); i++)
+ if ((*temp_buf_main) ==
+ fwd_info->diagid_user[i])
+ break;
+ ctxt_upd[i] = fwd_info->diagid_user[i];
+ if (temp_buf_upd[i]) {
+ memcpy(temp_buf_upd[i],
+ (temp_buf_main + 4), packet_len);
+ temp_buf_upd[i] += packet_len;
+ }
+ len_upd[i] += packet_len;
+ }
+ len = len - 4;
+ temp_buf_main += (packet_len + 4);
+ processed += packet_len;
+ }
+ for (i = 0; i <= (fwd_info->num_pd - 2); i++) {
+ if (fwd_info->type == TYPE_DATA && len_upd[i]) {
+ if (flag_buf_1) {
+ fwd_info->upd_len[i][0] = len_upd[i];
+ temp_fwdinfo_upd =
+ fwd_info->buf_upd[i][0];
+ } else {
+ fwd_info->upd_len[i][1] = len_upd[i];
+ temp_fwdinfo_upd =
+ fwd_info->buf_upd[i][1];
+ }
+ temp_fwdinfo_upd->ctxt &= 0x00FFFFFF;
+ temp_fwdinfo_upd->ctxt |=
+ (SET_PD_CTXT(ctxt_upd[i]));
+ atomic_set(&temp_fwdinfo_upd->in_busy, 1);
+ diagfwd_data_process_done(fwd_info,
+ temp_fwdinfo_upd, len_upd[i]);
+ } else {
+ if (flag_buf_1)
+ fwd_info->upd_len[i][0] = 0;
+ if (flag_buf_2)
+ fwd_info->upd_len[i][1] = 0;
+ }
+ }
+ if (len_cpd) {
+ if (flag_buf_1)
+ fwd_info->cpd_len_1 = len_cpd;
+ else
+ fwd_info->cpd_len_2 = len_cpd;
+ temp_fwdinfo_cpd->ctxt &= 0x00FFFFFF;
+ temp_fwdinfo_cpd->ctxt |=
+ (SET_PD_CTXT(ctxt_cpd));
+ diagfwd_data_process_done(fwd_info,
+ temp_fwdinfo_cpd, len_cpd);
+ } else {
+ if (flag_buf_1)
+ fwd_info->cpd_len_1 = 0;
+ if (flag_buf_2)
+ fwd_info->cpd_len_2 = 0;
+ }
+ } else {
+ diagfwd_data_read_done(fwd_info, buf, len);
+ }
+ return;
+end:
+ diag_ws_release();
+ if (temp_fwdinfo_cpd) {
+ diagfwd_write_done(fwd_info->peripheral, fwd_info->type,
+ GET_BUF_NUM(temp_fwdinfo_cpd->ctxt));
+ }
+ diagfwd_queue_read(fwd_info);
+}
+
static void diagfwd_data_read_done(struct diagfwd_info *fwd_info,
unsigned char *buf, int len)
{
@@ -413,6 +726,7 @@
uint8_t peripheral;
uint8_t transport;
uint8_t type;
+ int i = 0;
struct diagfwd_info *fwd_info = NULL;
for (transport = 0; transport < NUM_TRANSPORT; transport++) {
@@ -436,9 +750,20 @@
fwd_info->inited = 1;
fwd_info->read_bytes = 0;
fwd_info->write_bytes = 0;
+ fwd_info->cpd_len_1 = 0;
+ fwd_info->cpd_len_2 = 0;
+ fwd_info->num_pd = 0;
mutex_init(&fwd_info->buf_mutex);
mutex_init(&fwd_info->data_mutex);
spin_lock_init(&fwd_info->write_buf_lock);
+
+ for (i = 0; i < MAX_PERIPHERAL_UPD; i++) {
+ fwd_info->diagid_user[i] = 0;
+ fwd_info->upd_len[i][0] = 0;
+ fwd_info->upd_len[i][1] = 0;
+ fwd_info->buf_upd[i][0] = NULL;
+ fwd_info->buf_upd[i][1] = NULL;
+ }
}
}
@@ -452,9 +777,20 @@
fwd_info->ch_open = 0;
fwd_info->read_bytes = 0;
fwd_info->write_bytes = 0;
+ fwd_info->num_pd = 0;
+ fwd_info->cpd_len_1 = 0;
+ fwd_info->cpd_len_2 = 0;
spin_lock_init(&fwd_info->write_buf_lock);
mutex_init(&fwd_info->buf_mutex);
mutex_init(&fwd_info->data_mutex);
+
+ for (i = 0; i < MAX_PERIPHERAL_UPD; i++) {
+ fwd_info->diagid_user[i] = 0;
+ fwd_info->upd_len[i][0] = 0;
+ fwd_info->upd_len[i][1] = 0;
+ fwd_info->buf_upd[i][0] = NULL;
+ fwd_info->buf_upd[i][1] = NULL;
+ }
/*
* This state shouldn't be set for Control channels
* during initialization. This is set when the feature
@@ -730,6 +1066,16 @@
if (!fwd_info->inited || !atomic_read(&fwd_info->opened))
return -ENODEV;
+ if (type == TYPE_CMD) {
+ if (driver->feature[peripheral].untag_header)
+ if (!fwd_info->diagid_root ||
+ (!driver->diag_id_sent[peripheral])) {
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+ "diag: diag_id is not assigned yet\n");
+ return 0;
+ }
+ }
+
if (!(fwd_info->p_ops && fwd_info->p_ops->write && fwd_info->ctxt))
return -EIO;
@@ -897,6 +1243,9 @@
if (!fwd_info)
return -EIO;
+ if (fwd_info->type == TYPE_CNTL)
+ flush_workqueue(driver->cntl_wq);
+
mutex_lock(&driver->diagfwd_channel_mutex[fwd_info->peripheral]);
fwd_info->ch_open = 0;
if (fwd_info && fwd_info->c_ops && fwd_info->c_ops->close)
@@ -945,17 +1294,45 @@
void diagfwd_write_done(uint8_t peripheral, uint8_t type, int ctxt)
{
+ int i = 0;
struct diagfwd_info *fwd_info = NULL;
if (peripheral >= NUM_PERIPHERALS || type >= NUM_TYPES)
return;
fwd_info = &peripheral_info[type][peripheral];
- if (ctxt == 1 && fwd_info->buf_1)
+ if (!fwd_info)
+ return;
+
+ if (ctxt == 1 && fwd_info->buf_1) {
+ /* Buffer 1 for core PD is freed */
atomic_set(&fwd_info->buf_1->in_busy, 0);
- else if (ctxt == 2 && fwd_info->buf_2)
+ fwd_info->cpd_len_1 = 0;
+ } else if (ctxt == 2 && fwd_info->buf_2) {
+ /* Buffer 2 for core PD is freed */
atomic_set(&fwd_info->buf_2->in_busy, 0);
- else
+ fwd_info->cpd_len_2 = 0;
+ } else if (ctxt >= 3 && (ctxt % 2)) {
+ for (i = 0; i <= (fwd_info->num_pd - 2); i++) {
+ if (fwd_info->buf_upd[i][0]) {
+ /* Buffer 1 for ith user PD is freed */
+ atomic_set(&fwd_info->buf_upd[i][0]->in_busy, 0);
+ fwd_info->upd_len[i][0] = 0;
+ }
+ if (!fwd_info->cpd_len_1)
+ atomic_set(&fwd_info->buf_1->in_busy, 0);
+ }
+ } else if (ctxt >= 4 && !(ctxt % 2)) {
+ for (i = 0; i <= (fwd_info->num_pd - 2); i++) {
+ if (fwd_info->buf_upd[i][1]) {
+ /* Buffer 2 for ith user PD is freed */
+ atomic_set(&fwd_info->buf_upd[i][0]->in_busy, 0);
+ fwd_info->upd_len[i][1] = 0;
+ }
+ if (!fwd_info->cpd_len_2)
+ atomic_set(&fwd_info->buf_2->in_busy, 0);
+ }
+ } else
pr_err("diag: In %s, invalid ctxt %d\n", __func__, ctxt);
diagfwd_queue_read(fwd_info);
@@ -1084,8 +1461,65 @@
fwd_info->p_ops->queue_read(fwd_info->ctxt);
}
+static int diagfwd_buffers_allocate(struct diagfwd_info *fwd_info)
+{
+ int i, j;
+
+ for (i = 0; ((fwd_info->num_pd > 1) &&
+ (i <= (fwd_info->num_pd - 2))); i++) {
+ for (j = 0; j < NUM_WRITE_BUFFERS; j++) {
+ if (!fwd_info->buf_upd[i][j]) {
+ fwd_info->buf_upd[i][j] =
+ kzalloc(sizeof(struct diagfwd_buf_t),
+ GFP_KERNEL);
+ if (ZERO_OR_NULL_PTR(fwd_info->buf_upd[i][j]))
+ return -ENOMEM;
+ kmemleak_not_leak(fwd_info->buf_upd[i][j]);
+ }
+
+ if (fwd_info->buf_upd[i][j] &&
+ !fwd_info->buf_upd[i][j]->data) {
+ fwd_info->buf_upd[i][j]->data =
+ kzalloc(PERIPHERAL_BUF_SZ +
+ APF_DIAG_PADDING,
+ GFP_KERNEL);
+ if (ZERO_OR_NULL_PTR(
+ fwd_info->buf_upd[i][j]->data))
+ return -ENOMEM;
+ fwd_info->buf_upd[i][j]->len =
+ PERIPHERAL_BUF_SZ;
+ kmemleak_not_leak(
+ fwd_info->buf_upd[i][j]->data);
+ fwd_info->buf_upd[i][j]->ctxt =
+ SET_BUF_CTXT(fwd_info->peripheral,
+ fwd_info->type, ((2 * i) + (j + 3)));
+ }
+
+ if (driver->supports_apps_hdlc_encoding) {
+ if (fwd_info->buf_upd[i][j] &&
+ !fwd_info->buf_upd[i][j]->data_raw) {
+ fwd_info->buf_upd[i][j]->data_raw =
+ kzalloc(PERIPHERAL_BUF_SZ +
+ APF_DIAG_PADDING,
+ GFP_KERNEL);
+ if (ZERO_OR_NULL_PTR(
+ fwd_info->buf_upd[i][j]->data_raw))
+ return -ENOMEM;
+ fwd_info->buf_upd[i][j]->len_raw =
+ PERIPHERAL_BUF_SZ;
+ kmemleak_not_leak(
+ fwd_info->buf_upd[i][j]->data_raw);
+ }
+ }
+ }
+ }
+ return 0;
+}
+
void diagfwd_buffers_init(struct diagfwd_info *fwd_info)
{
+ int ret = 0;
+ unsigned char *temp_char_buf;
if (!fwd_info)
return;
@@ -1097,18 +1531,20 @@
}
mutex_lock(&fwd_info->buf_mutex);
+
if (!fwd_info->buf_1) {
fwd_info->buf_1 = kzalloc(sizeof(struct diagfwd_buf_t),
GFP_KERNEL);
- if (!fwd_info->buf_1)
+ if (ZERO_OR_NULL_PTR(fwd_info->buf_1))
goto err;
kmemleak_not_leak(fwd_info->buf_1);
}
+
if (!fwd_info->buf_1->data) {
fwd_info->buf_1->data = kzalloc(PERIPHERAL_BUF_SZ +
APF_DIAG_PADDING,
GFP_KERNEL);
- if (!fwd_info->buf_1->data)
+ if (ZERO_OR_NULL_PTR(fwd_info->buf_1->data))
goto err;
fwd_info->buf_1->len = PERIPHERAL_BUF_SZ;
kmemleak_not_leak(fwd_info->buf_1->data);
@@ -1120,7 +1556,7 @@
if (!fwd_info->buf_2) {
fwd_info->buf_2 = kzalloc(sizeof(struct diagfwd_buf_t),
GFP_KERNEL);
- if (!fwd_info->buf_2)
+ if (ZERO_OR_NULL_PTR(fwd_info->buf_2))
goto err;
kmemleak_not_leak(fwd_info->buf_2);
}
@@ -1129,7 +1565,7 @@
fwd_info->buf_2->data = kzalloc(PERIPHERAL_BUF_SZ +
APF_DIAG_PADDING,
GFP_KERNEL);
- if (!fwd_info->buf_2->data)
+ if (ZERO_OR_NULL_PTR(fwd_info->buf_2->data))
goto err;
fwd_info->buf_2->len = PERIPHERAL_BUF_SZ;
kmemleak_not_leak(fwd_info->buf_2->data);
@@ -1138,6 +1574,11 @@
fwd_info->type, 2);
}
+ if (driver->feature[fwd_info->peripheral].untag_header)
+ ret = diagfwd_buffers_allocate(fwd_info);
+ if (ret)
+ goto err;
+
if (driver->supports_apps_hdlc_encoding) {
/* In support of hdlc encoding */
if (!fwd_info->buf_1->data_raw) {
@@ -1145,34 +1586,44 @@
kzalloc(PERIPHERAL_BUF_SZ +
APF_DIAG_PADDING,
GFP_KERNEL);
- if (!fwd_info->buf_1->data_raw)
+ temp_char_buf =
+ fwd_info->buf_1->data_raw;
+ if (ZERO_OR_NULL_PTR(temp_char_buf))
goto err;
- fwd_info->buf_1->len_raw = PERIPHERAL_BUF_SZ;
- kmemleak_not_leak(fwd_info->buf_1->data_raw);
+ fwd_info->buf_1->len_raw =
+ PERIPHERAL_BUF_SZ;
+ kmemleak_not_leak(temp_char_buf);
}
+
if (!fwd_info->buf_2->data_raw) {
fwd_info->buf_2->data_raw =
kzalloc(PERIPHERAL_BUF_SZ +
APF_DIAG_PADDING,
GFP_KERNEL);
- if (!fwd_info->buf_2->data_raw)
+ temp_char_buf =
+ fwd_info->buf_2->data_raw;
+ if (ZERO_OR_NULL_PTR(temp_char_buf))
goto err;
- fwd_info->buf_2->len_raw = PERIPHERAL_BUF_SZ;
- kmemleak_not_leak(fwd_info->buf_2->data_raw);
+ fwd_info->buf_2->len_raw =
+ PERIPHERAL_BUF_SZ;
+ kmemleak_not_leak(temp_char_buf);
}
}
}
- if (fwd_info->type == TYPE_CMD && driver->supports_apps_hdlc_encoding) {
+ if (fwd_info->type == TYPE_CMD &&
+ driver->supports_apps_hdlc_encoding) {
/* In support of hdlc encoding */
if (!fwd_info->buf_1->data_raw) {
fwd_info->buf_1->data_raw = kzalloc(PERIPHERAL_BUF_SZ +
APF_DIAG_PADDING,
GFP_KERNEL);
- if (!fwd_info->buf_1->data_raw)
+ temp_char_buf =
+ fwd_info->buf_1->data_raw;
+ if (ZERO_OR_NULL_PTR(temp_char_buf))
goto err;
fwd_info->buf_1->len_raw = PERIPHERAL_BUF_SZ;
- kmemleak_not_leak(fwd_info->buf_1->data_raw);
+ kmemleak_not_leak(temp_char_buf);
}
}
@@ -1182,10 +1633,12 @@
err:
mutex_unlock(&fwd_info->buf_mutex);
diagfwd_buffers_exit(fwd_info);
+ return;
}
static void diagfwd_buffers_exit(struct diagfwd_info *fwd_info)
{
+ int i = 0;
if (!fwd_info)
return;
@@ -1207,6 +1660,24 @@
kfree(fwd_info->buf_2);
fwd_info->buf_2 = NULL;
}
+ for (i = 0; i <= (fwd_info->num_pd - 2); i++) {
+ if (fwd_info->buf_upd[i][0]) {
+ kfree(fwd_info->buf_upd[i][0]->data);
+ fwd_info->buf_upd[i][0]->data = NULL;
+ kfree(fwd_info->buf_upd[i][0]->data_raw);
+ fwd_info->buf_upd[i][0]->data_raw = NULL;
+ kfree(fwd_info->buf_upd[i][0]);
+ fwd_info->buf_upd[i][0] = NULL;
+ }
+ if (fwd_info->buf_upd[i][1]) {
+ kfree(fwd_info->buf_upd[i][1]->data);
+ fwd_info->buf_upd[i][1]->data = NULL;
+ kfree(fwd_info->buf_upd[i][1]->data_raw);
+ fwd_info->buf_upd[i][1]->data_raw = NULL;
+ kfree(fwd_info->buf_upd[i][1]);
+ fwd_info->buf_upd[i][1] = NULL;
+ }
+ }
mutex_unlock(&fwd_info->buf_mutex);
}
diff --git a/drivers/char/diag/diagfwd_peripheral.h b/drivers/char/diag/diagfwd_peripheral.h
index 5884a12..b16670e 100644
--- a/drivers/char/diag/diagfwd_peripheral.h
+++ b/drivers/char/diag/diagfwd_peripheral.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. 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 and
@@ -68,6 +68,12 @@
uint8_t transport;
uint8_t inited;
uint8_t ch_open;
+ uint8_t num_pd;
+ uint8_t diagid_root;
+ uint8_t diagid_user[MAX_PERIPHERAL_UPD];
+ int cpd_len_1;
+ int cpd_len_2;
+ int upd_len[MAX_PERIPHERAL_UPD][2];
atomic_t opened;
unsigned long read_bytes;
unsigned long write_bytes;
@@ -77,6 +83,7 @@
void *ctxt;
struct diagfwd_buf_t *buf_1;
struct diagfwd_buf_t *buf_2;
+ struct diagfwd_buf_t *buf_upd[MAX_PERIPHERAL_UPD][2];
struct diagfwd_buf_t *buf_ptr[NUM_WRITE_BUFFERS];
struct diag_peripheral_ops *p_ops;
struct diag_channel_ops *c_ops;
@@ -94,6 +101,9 @@
void diagfwd_late_open(struct diagfwd_info *fwd_info);
void diagfwd_close(uint8_t peripheral, uint8_t type);
+
+int diag_md_get_peripheral(int ctxt);
+
int diagfwd_register(uint8_t transport, uint8_t peripheral, uint8_t type,
void *ctxt, struct diag_peripheral_ops *ops,
struct diagfwd_info **fwd_ctxt);
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index fcdd886..172a9dc 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -3877,6 +3877,9 @@
* because the lower layer is allowed to hold locks while calling
* message delivery.
*/
+
+ rcu_read_lock();
+
if (!run_to_completion)
spin_lock_irqsave(&intf->xmit_msgs_lock, flags);
if (intf->curr_msg == NULL && !intf->in_shutdown) {
@@ -3899,6 +3902,8 @@
if (newmsg)
intf->handlers->sender(intf->send_info, newmsg);
+ rcu_read_unlock();
+
handle_new_recv_msgs(intf);
}
diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c
index 6958b5c..510fc10 100644
--- a/drivers/char/ipmi/ipmi_ssif.c
+++ b/drivers/char/ipmi/ipmi_ssif.c
@@ -762,6 +762,11 @@
result, len, data[2]);
} else if (data[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2
|| data[1] != IPMI_GET_MSG_FLAGS_CMD) {
+ /*
+ * Don't abort here, maybe it was a queued
+ * response to a previous command.
+ */
+ ipmi_ssif_unlock_cond(ssif_info, flags);
pr_warn(PFX "Invalid response getting flags: %x %x\n",
data[0], data[1]);
} else {
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 08d1dd5..ee737ef 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -2044,8 +2044,8 @@
struct batched_entropy {
union {
- unsigned long entropy_long[CHACHA20_BLOCK_SIZE / sizeof(unsigned long)];
- unsigned int entropy_int[CHACHA20_BLOCK_SIZE / sizeof(unsigned int)];
+ u64 entropy_u64[CHACHA20_BLOCK_SIZE / sizeof(u64)];
+ u32 entropy_u32[CHACHA20_BLOCK_SIZE / sizeof(u32)];
};
unsigned int position;
};
@@ -2055,52 +2055,51 @@
* number is either as good as RDRAND or as good as /dev/urandom, with the
* goal of being quite fast and not depleting entropy.
*/
-static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_long);
-unsigned long get_random_long(void)
+static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_u64);
+u64 get_random_u64(void)
{
- unsigned long ret;
+ u64 ret;
struct batched_entropy *batch;
- if (arch_get_random_long(&ret))
+#if BITS_PER_LONG == 64
+ if (arch_get_random_long((unsigned long *)&ret))
return ret;
+#else
+ if (arch_get_random_long((unsigned long *)&ret) &&
+ arch_get_random_long((unsigned long *)&ret + 1))
+ return ret;
+#endif
- batch = &get_cpu_var(batched_entropy_long);
- if (batch->position % ARRAY_SIZE(batch->entropy_long) == 0) {
- extract_crng((u8 *)batch->entropy_long);
+ batch = &get_cpu_var(batched_entropy_u64);
+ if (batch->position % ARRAY_SIZE(batch->entropy_u64) == 0) {
+ extract_crng((u8 *)batch->entropy_u64);
batch->position = 0;
}
- ret = batch->entropy_long[batch->position++];
- put_cpu_var(batched_entropy_long);
+ ret = batch->entropy_u64[batch->position++];
+ put_cpu_var(batched_entropy_u64);
return ret;
}
-EXPORT_SYMBOL(get_random_long);
+EXPORT_SYMBOL(get_random_u64);
-#if BITS_PER_LONG == 32
-unsigned int get_random_int(void)
+static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_u32);
+u32 get_random_u32(void)
{
- return get_random_long();
-}
-#else
-static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_int);
-unsigned int get_random_int(void)
-{
- unsigned int ret;
+ u32 ret;
struct batched_entropy *batch;
if (arch_get_random_int(&ret))
return ret;
- batch = &get_cpu_var(batched_entropy_int);
- if (batch->position % ARRAY_SIZE(batch->entropy_int) == 0) {
- extract_crng((u8 *)batch->entropy_int);
+ batch = &get_cpu_var(batched_entropy_u32);
+ if (batch->position % ARRAY_SIZE(batch->entropy_u32) == 0) {
+ extract_crng((u8 *)batch->entropy_u32);
batch->position = 0;
}
- ret = batch->entropy_int[batch->position++];
- put_cpu_var(batched_entropy_int);
+ ret = batch->entropy_u32[batch->position++];
+ put_cpu_var(batched_entropy_u32);
return ret;
}
-#endif
-EXPORT_SYMBOL(get_random_int);
+EXPORT_SYMBOL(get_random_u32);
/**
* randomize_page - Generate a random, page aligned address
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index bb7c862..3e13186 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -283,10 +283,14 @@
const struct clk_div_table *table, u8 width,
unsigned long flags)
{
+ struct clk_hw *parent = clk_hw_get_parent(hw);
int i, bestdiv = 0;
unsigned long parent_rate, best = 0, now, maxdiv;
unsigned long parent_rate_saved = *best_parent_rate;
+ if (!parent)
+ return -EINVAL;
+
if (!rate)
rate = 1;
@@ -317,8 +321,7 @@
*best_parent_rate = parent_rate_saved;
return i;
}
- parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw),
- rate * i);
+ parent_rate = clk_hw_round_rate(parent, rate * i);
now = DIV_ROUND_UP_ULL((u64)parent_rate, i);
if (_is_best_div(rate, now, best, flags)) {
bestdiv = i;
@@ -329,7 +332,7 @@
if (!bestdiv) {
bestdiv = _get_maxdiv(table, width, flags);
- *best_parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), 1);
+ *best_parent_rate = clk_hw_round_rate(parent, 1);
}
return bestdiv;
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 7cdf45b..5638333 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -2631,7 +2631,46 @@
pr_info(fmt, ##__VA_ARGS__); \
} while (0)
-int clock_debug_print_clock(struct clk_core *c, struct seq_file *s)
+/*
+ * clock_debug_print_enabled_debug_suspend() - Print names of enabled clocks
+ * during suspend.
+ */
+static void clock_debug_print_enabled_debug_suspend(struct seq_file *s)
+{
+ struct clk_core *core;
+ int cnt = 0;
+
+ if (!mutex_trylock(&clk_debug_lock))
+ return;
+
+ clock_debug_output(s, 0, "Enabled clocks:\n");
+
+ hlist_for_each_entry(core, &clk_debug_list, debug_node) {
+ if (!core || !core->prepare_count)
+ continue;
+
+ if (core->vdd_class)
+ clock_debug_output(s, 0, " %s:%u:%u [%ld, %d]",
+ core->name, core->prepare_count,
+ core->enable_count, core->rate,
+ clk_find_vdd_level(core, core->rate));
+
+ else
+ clock_debug_output(s, 0, " %s:%u:%u [%ld]",
+ core->name, core->prepare_count,
+ core->enable_count, core->rate);
+ cnt++;
+ }
+
+ mutex_unlock(&clk_debug_lock);
+
+ if (cnt)
+ clock_debug_output(s, 0, "Enabled clock count: %d\n", cnt);
+ else
+ clock_debug_output(s, 0, "No clocks enabled.\n");
+}
+
+static int clock_debug_print_clock(struct clk_core *c, struct seq_file *s)
{
char *start = "";
struct clk *clk;
@@ -3005,7 +3044,7 @@
if (likely(!debug_suspend))
return;
- clock_debug_print_enabled_clocks(NULL);
+ clock_debug_print_enabled_debug_suspend(NULL);
}
EXPORT_SYMBOL_GPL(clock_debug_print_enabled);
diff --git a/drivers/clk/clk.h b/drivers/clk/clk.h
index f0db049..b52aa25 100644
--- a/drivers/clk/clk.h
+++ b/drivers/clk/clk.h
@@ -10,6 +10,7 @@
*/
struct clk_hw;
+struct clk_core;
#if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK)
struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec,
diff --git a/drivers/clk/qcom/clk-aop-qmp.c b/drivers/clk/qcom/clk-aop-qmp.c
index f6aeb19..ff229fb 100644
--- a/drivers/clk/qcom/clk-aop-qmp.c
+++ b/drivers/clk/qcom/clk-aop-qmp.c
@@ -30,7 +30,7 @@
void *data;
};
-#define DEFINE_CLK_AOP_QMP(_name, _class, _res, _estate, _dstate) \
+#define DEFINE_CLK_AOP_QMP(_name, _class, _res, _estate, _dstate, _flags) \
static struct clk_aop_qmp _name = { \
.msg.class = #_class, \
.msg.res = #_res, \
@@ -40,7 +40,7 @@
.ops = &aop_qmp_clk_ops, \
.name = #_name, \
.num_parents = 0, \
- .flags = CLK_ENABLE_HAND_OFF, \
+ .flags = _flags, \
}, \
}
@@ -214,13 +214,25 @@
.is_enabled = clk_aop_qmp_is_enabled,
};
-DEFINE_CLK_AOP_QMP(qdss_qmp_clk, clock, qdss,
- QDSS_CLK_LEVEL_DYNAMIC, QDSS_CLK_LEVEL_OFF);
+DEFINE_CLK_AOP_QMP(qdss_qmp_clk, clock, qdss, QDSS_CLK_LEVEL_DYNAMIC,
+ QDSS_CLK_LEVEL_OFF, CLK_ENABLE_HAND_OFF);
+DEFINE_CLK_AOP_QMP(qdss_ao_qmp_clk, clock, qdss_ao, QDSS_CLK_LEVEL_DYNAMIC,
+ QDSS_CLK_LEVEL_OFF, 0);
static struct clk_hw *aop_qmp_clk_hws[] = {
[QDSS_CLK] = &qdss_qmp_clk.hw,
+ [QDSS_AO_CLK] = &qdss_ao_qmp_clk.hw,
};
+/*
+ * Due to HW limitations on v1, the qdss_ao clock was not supported by the clock
+ * driver on AOP.
+ */
+static void aop_qmp_fixup_v1(void)
+{
+ aop_qmp_clk_hws[QDSS_AO_CLK] = NULL;
+}
+
static int qmp_update_client(struct clk_hw *hw, struct device *dev,
struct mbox_chan *mbox)
{
@@ -250,7 +262,7 @@
static int aop_qmp_clk_probe(struct platform_device *pdev)
{
- struct clk *clk;
+ struct clk *clk = NULL;
struct device_node *np = pdev->dev.of_node;
struct mbox_chan *mbox = NULL;
int num_clks = ARRAY_SIZE(aop_qmp_clk_hws);
@@ -264,7 +276,12 @@
if (ret < 0)
return ret;
+ if (of_device_is_compatible(pdev->dev.of_node, "qcom,aop-qmp-clk-v1"))
+ aop_qmp_fixup_v1();
+
for (i = 1; i < num_clks; i++) {
+ if (!aop_qmp_clk_hws[i])
+ continue;
ret = qmp_update_client(aop_qmp_clk_hws[i], &pdev->dev, mbox);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to update QMP client %d\n",
@@ -273,13 +290,17 @@
}
}
- for (i = 0; i < num_clks; i++) {
- ret = clk_aop_qmp_prepare(aop_qmp_clk_hws[i]);
- if (ret < 0)
- goto fail;
- }
+ /*
+ * Proxy vote on the QDSS clock. This is needed to avoid issues with
+ * excessive requests on the QMP layer during the QDSS driver probe.
+ */
+ ret = clk_aop_qmp_prepare(&qdss_qmp_clk.hw);
+ if (ret < 0)
+ goto fail;
for (i = 0; i < num_clks; i++) {
+ if (!aop_qmp_clk_hws[i])
+ continue;
clk = devm_clk_register(&pdev->dev, aop_qmp_clk_hws[i]);
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
@@ -303,7 +324,8 @@
}
static const struct of_device_id aop_qmp_clk_of_match[] = {
- { .compatible = "qcom,aop-qmp-clk", },
+ { .compatible = "qcom,aop-qmp-clk-v1" },
+ { .compatible = "qcom,aop-qmp-clk-v2" },
{}
};
diff --git a/drivers/clk/qcom/clk-branch.c b/drivers/clk/qcom/clk-branch.c
index 46ced08..fa0ca36 100644
--- a/drivers/clk/qcom/clk-branch.c
+++ b/drivers/clk/qcom/clk-branch.c
@@ -287,20 +287,30 @@
static int clk_branch2_prepare(struct clk_hw *hw)
{
- struct clk_branch *branch = to_clk_branch(hw);
- struct clk_hw *parent = clk_hw_get_parent(hw);
- unsigned long curr_rate, branch_rate = branch->rate;
+ struct clk_branch *branch;
+ struct clk_hw *parent;
+ unsigned long curr_rate;
int ret = 0;
+ if (!hw)
+ return -EINVAL;
+
+ branch = to_clk_branch(hw);
+ parent = clk_hw_get_parent(hw);
+ if (!branch)
+ return -EINVAL;
+
/*
* Do the rate aggregation and scaling of the RCG in the prepare/
* unprepare functions to avoid potential RPM(/h) communication due to
* votes on the voltage rails.
*/
if (branch->aggr_sibling_rates) {
+ if (!parent)
+ return -EINVAL;
curr_rate = clk_aggregate_rate(hw, parent->core);
- if (branch_rate > curr_rate) {
- ret = clk_set_rate(parent->clk, branch_rate);
+ if (branch->rate > curr_rate) {
+ ret = clk_set_rate(parent->clk, branch->rate);
if (ret)
goto exit;
}
@@ -316,13 +326,23 @@
static void clk_branch2_unprepare(struct clk_hw *hw)
{
- struct clk_branch *branch = to_clk_branch(hw);
- struct clk_hw *parent = clk_hw_get_parent(hw);
- unsigned long curr_rate, new_rate, branch_rate = branch->rate;
+ struct clk_branch *branch;
+ struct clk_hw *parent;
+ unsigned long curr_rate, new_rate;
+
+ if (!hw)
+ return;
+
+ branch = to_clk_branch(hw);
+ parent = clk_hw_get_parent(hw);
+ if (!branch)
+ return;
if (branch->aggr_sibling_rates) {
+ if (!parent)
+ return;
new_rate = clk_aggregate_rate(hw, parent->core);
- curr_rate = max(new_rate, branch_rate);
+ curr_rate = max(new_rate, branch->rate);
if (new_rate < curr_rate)
if (clk_set_rate(parent->clk, new_rate))
pr_err("Failed to scale %s to %lu\n",
diff --git a/drivers/clk/qcom/clk-cpu-osm.c b/drivers/clk/qcom/clk-cpu-osm.c
index 1d63a86..3a1a8e1 100644
--- a/drivers/clk/qcom/clk-cpu-osm.c
+++ b/drivers/clk/qcom/clk-cpu-osm.c
@@ -45,6 +45,7 @@
#include "clk-debug.h"
#define OSM_INIT_RATE 300000000UL
+#define XO_RATE 19200000UL
#define OSM_TABLE_SIZE 40
#define SINGLE_CORE 1
#define MAX_CLUSTER_CNT 3
@@ -65,6 +66,7 @@
#define PERFCL_EFUSE_MASK 0x7
#define ENABLE_REG 0x0
+#define ENABLE_OSM BIT(0)
#define FREQ_REG 0x110
#define VOLT_REG 0x114
#define OVERRIDE_REG 0x118
@@ -111,8 +113,8 @@
#define PLL_MIN_LVAL 0x21
#define PLL_MIN_FREQ_REG 0x94
-#define PLL_POST_DIV1 0x1F
-#define PLL_POST_DIV2 0x11F
+#define PLL_POST_DIV1 0x09
+#define PLL_POST_DIV2 0x109
#define PLL_MODE 0x0
#define PLL_L_VAL 0x4
#define PLL_USER_CTRL 0xc
@@ -121,6 +123,7 @@
#define MIN_VCO_VAL 0x2b
#define MAX_VC 63
+#define MEM_ACC_LEVELS_LUT 2
#define MAX_MEM_ACC_LEVELS 3
#define MAX_MEM_ACC_VAL_PER_LEVEL 3
#define MAX_MEM_ACC_VALUES (MAX_MEM_ACC_LEVELS * \
@@ -131,8 +134,8 @@
#define ISENSE_OFF_DATA 0x0
#define CONSTANT_32 0x20
-#define APM_MX_MODE 0x0
-#define APM_APC_MODE 0x2
+#define APM_MX_MODE 0x4100000
+#define APM_APC_MODE 0x4100002
#define APM_READ_DATA_MASK 0xc
#define APM_MX_MODE_VAL 0x4
#define APM_APC_READ_VAL 0x8
@@ -265,6 +268,7 @@
u32 speedbin;
u32 mem_acc_crossover_vc_addr;
u32 mem_acc_addr[MEM_ACC_ADDRS];
+ u32 mem_acc_level_vc[MEM_ACC_LEVELS_LUT];
u32 ramp_ctl_addr;
u32 apm_mode_ctl;
u32 apm_status_ctl;
@@ -450,6 +454,7 @@
}
static bool is_v2;
+static bool osm_tz_enabled;
static inline struct clk_osm *to_clk_osm(struct clk_hw *_hw)
{
@@ -518,6 +523,9 @@
int i;
unsigned long rrate = 0;
+ if (!hw)
+ return -EINVAL;
+
/*
* If the rate passed in is 0, return the first frequency in the
* FMAX table.
@@ -541,23 +549,12 @@
static int clk_osm_search_table(struct osm_entry *table, int entries, long rate)
{
- int quad_core_index, single_core_index = 0;
- int core_count;
+ int index = 0;
- for (quad_core_index = 0; quad_core_index < entries;
- quad_core_index++) {
- core_count = CORE_COUNT_VAL(table[quad_core_index].freq_data);
- if (rate == table[quad_core_index].frequency &&
- core_count == SINGLE_CORE) {
- single_core_index = quad_core_index;
- continue;
- }
- if (rate == table[quad_core_index].frequency &&
- core_count == MAX_CORE_COUNT)
- return quad_core_index;
+ for (index = 0; index < entries; index++) {
+ if (rate == table[index].frequency)
+ return index;
}
- if (single_core_index)
- return single_core_index;
return -EINVAL;
}
@@ -639,7 +636,7 @@
}
-const struct clk_ops clk_ops_l3_osm = {
+static struct clk_ops clk_ops_l3_osm = {
.enable = clk_osm_enable,
.round_rate = clk_osm_round_rate,
.list_rate = clk_osm_list_rate,
@@ -1051,21 +1048,6 @@
static void clk_osm_program_mem_acc_regs(struct clk_osm *c)
{
- int curr_level, i, j = 0;
- int mem_acc_level_map[MAX_MEM_ACC_LEVELS] = {MAX_VC, MAX_VC, MAX_VC};
-
- curr_level = c->osm_table[0].mem_acc_level;
- for (i = 0; i < c->num_entries; i++) {
- if (curr_level == MAX_MEM_ACC_LEVELS)
- break;
-
- if (c->osm_table[i].mem_acc_level != curr_level) {
- mem_acc_level_map[j++] =
- c->osm_table[i].virtual_corner;
- curr_level = c->osm_table[i].mem_acc_level;
- }
- }
-
if (c->secure_init) {
clk_osm_write_seq_reg(c,
c->pbases[OSM_BASE] + MEMACC_CROSSOVER_VC,
@@ -1075,13 +1057,8 @@
clk_osm_write_seq_reg(c, c->mem_acc_addr[2], DATA_MEM(50));
clk_osm_write_seq_reg(c, c->mem_acc_crossover_vc,
DATA_MEM(78));
- clk_osm_write_seq_reg(c, mem_acc_level_map[0], DATA_MEM(79));
- if (c == &perfcl_clk)
- clk_osm_write_seq_reg(c, c->mem_acc_threshold_vc,
- DATA_MEM(80));
- else
- clk_osm_write_seq_reg(c, mem_acc_level_map[1],
- DATA_MEM(80));
+ clk_osm_write_seq_reg(c, c->mem_acc_level_vc[0], DATA_MEM(79));
+ clk_osm_write_seq_reg(c, c->mem_acc_level_vc[1], DATA_MEM(80));
/*
* Note that DATA_MEM[81] -> DATA_MEM[89] values will be
* confirmed post-si. Use a value of 1 for DATA_MEM[89] and
@@ -1092,13 +1069,9 @@
scm_io_write(c->pbases[SEQ_BASE] + DATA_MEM(78),
c->mem_acc_crossover_vc);
scm_io_write(c->pbases[SEQ_BASE] + DATA_MEM(79),
- mem_acc_level_map[0]);
- if (c == &perfcl_clk)
- scm_io_write(c->pbases[SEQ_BASE] + DATA_MEM(80),
- c->mem_acc_threshold_vc);
- else
- scm_io_write(c->pbases[SEQ_BASE] + DATA_MEM(80),
- mem_acc_level_map[1]);
+ c->mem_acc_level_vc[0]);
+ scm_io_write(c->pbases[SEQ_BASE] + DATA_MEM(80),
+ c->mem_acc_level_vc[1]);
}
}
@@ -1675,7 +1648,8 @@
/* Program LVAL corresponding to first turbo VC */
for (i = 0; i < c->num_entries; i++) {
- if (c->osm_table[i].mem_acc_level == MAX_MEM_ACC_LEVELS) {
+ if (c->osm_table[i].virtual_corner ==
+ c->mem_acc_level_vc[1]) {
lval = c->osm_table[i].freq_data & GENMASK(7, 0);
break;
}
@@ -1882,6 +1856,7 @@
u32 val;
int core_num;
unsigned long flags;
+ u64 cycle_counter_ret;
struct clk_osm *parent, *c = logical_cpu_to_clk(cpu);
if (IS_ERR_OR_NULL(c)) {
@@ -1909,9 +1884,10 @@
c->total_cycle_counter += val - c->prev_cycle_counter;
c->prev_cycle_counter = val;
}
+ cycle_counter_ret = c->total_cycle_counter;
spin_unlock_irqrestore(&parent->lock, flags);
- return c->total_cycle_counter;
+ return cycle_counter_ret;
}
static void clk_osm_setup_cycle_counters(struct clk_osm *c)
@@ -2104,6 +2080,49 @@
return rc;
}
+static int clk_osm_read_lut(struct platform_device *pdev, struct clk_osm *c)
+{
+ u32 data, src, lval, i, j = OSM_TABLE_SIZE;
+
+ for (i = 0; i < OSM_TABLE_SIZE; i++) {
+ data = clk_osm_read_reg(c, FREQ_REG + i * OSM_REG_SIZE);
+ src = ((data & GENMASK(31, 30)) >> 30);
+ lval = (data & GENMASK(7, 0));
+
+ if (!src)
+ c->osm_table[i].frequency = OSM_INIT_RATE;
+ else
+ c->osm_table[i].frequency = XO_RATE * lval;
+
+ data = clk_osm_read_reg(c, VOLT_REG + i * OSM_REG_SIZE);
+ c->osm_table[i].virtual_corner =
+ ((data & GENMASK(21, 16)) >> 16);
+ c->osm_table[i].open_loop_volt = (data & GENMASK(11, 0));
+
+ pr_debug("index=%d freq=%ld virtual_corner=%d open_loop_voltage=%u\n",
+ i, c->osm_table[i].frequency,
+ c->osm_table[i].virtual_corner,
+ c->osm_table[i].open_loop_volt);
+
+ if (i > 0 && j == OSM_TABLE_SIZE && c->osm_table[i].frequency ==
+ c->osm_table[i - 1].frequency)
+ j = i;
+ }
+
+ osm_clks_init[c->cluster_num].rate_max = devm_kcalloc(&pdev->dev,
+ j, sizeof(unsigned long),
+ GFP_KERNEL);
+ if (!osm_clks_init[c->cluster_num].rate_max)
+ return -ENOMEM;
+
+ for (i = 0; i < j; i++)
+ osm_clks_init[c->cluster_num].rate_max[i] =
+ c->osm_table[i].frequency;
+
+ c->num_entries = osm_clks_init[c->cluster_num].num_rate_max = j;
+ return 0;
+}
+
static int clk_osm_parse_acd_dt_configs(struct platform_device *pdev)
{
struct device_node *of = pdev->dev.of_node;
@@ -2251,6 +2270,7 @@
{
struct device_node *of = pdev->dev.of_node;
u32 *array;
+ char memacc_str[40];
int rc = 0;
struct resource *res;
@@ -2470,6 +2490,36 @@
return -ENOMEM;
}
+ snprintf(memacc_str, ARRAY_SIZE(memacc_str),
+ "qcom,l3-memacc-level-vc-bin%d", l3_clk.speedbin);
+ rc = of_property_read_u32_array(of, memacc_str, l3_clk.mem_acc_level_vc,
+ MEM_ACC_LEVELS_LUT);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find %s property, rc=%d\n",
+ memacc_str, rc);
+ return rc;
+ }
+
+ snprintf(memacc_str, ARRAY_SIZE(memacc_str),
+ "qcom,pwrcl-memacc-level-vc-bin%d", pwrcl_clk.speedbin);
+ rc = of_property_read_u32_array(of, memacc_str,
+ pwrcl_clk.mem_acc_level_vc, MEM_ACC_LEVELS_LUT);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find %s property, rc=%d\n",
+ memacc_str, rc);
+ return rc;
+ }
+
+ snprintf(memacc_str, ARRAY_SIZE(memacc_str),
+ "qcom,perfcl-memacc-level-vc-bin%d", pwrcl_clk.speedbin);
+ rc = of_property_read_u32_array(of, memacc_str,
+ perfcl_clk.mem_acc_level_vc, MEM_ACC_LEVELS_LUT);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find %s property, rc=%d\n",
+ memacc_str, rc);
+ return rc;
+ }
+
l3_clk.secure_init = perfcl_clk.secure_init = pwrcl_clk.secure_init =
of_property_read_bool(pdev->dev.of_node, "qcom,osm-no-tz");
@@ -2579,6 +2629,12 @@
return -ENOMEM;
}
+ /* Check if OSM has been enabled already by trustzone. */
+ if (readl_relaxed(l3_clk.vbases[OSM_BASE] + ENABLE_REG) & ENABLE_OSM) {
+ dev_info(&pdev->dev, "OSM has been initialized and enabled by TZ software\n");
+ osm_tz_enabled = true;
+ }
+
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"osm_pwrcl_base");
if (!res) {
@@ -2612,6 +2668,9 @@
return -ENOMEM;
}
+ if (osm_tz_enabled)
+ return rc;
+
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "l3_pll");
if (!res) {
dev_err(&pdev->dev,
@@ -3018,77 +3077,6 @@
clk_data->clk_num = num_clks;
- if (l3_clk.vbases[EFUSE_BASE]) {
- /* Multiple speed-bins are supported */
- pte_efuse = readl_relaxed(l3_clk.vbases[EFUSE_BASE]);
- l3_clk.speedbin = ((pte_efuse >> L3_EFUSE_SHIFT) &
- L3_EFUSE_MASK);
- snprintf(l3speedbinstr, ARRAY_SIZE(l3speedbinstr),
- "qcom,l3-speedbin%d-v%d", l3_clk.speedbin, pvs_ver);
- }
-
- dev_info(&pdev->dev, "using L3 speed bin %u and pvs_ver %d\n",
- l3_clk.speedbin, pvs_ver);
-
- rc = clk_osm_get_lut(pdev, &l3_clk, l3speedbinstr);
- if (rc) {
- dev_err(&pdev->dev, "Unable to get OSM LUT for L3, rc=%d\n",
- rc);
- return rc;
- }
-
- if (pwrcl_clk.vbases[EFUSE_BASE]) {
- /* Multiple speed-bins are supported */
- pte_efuse = readl_relaxed(pwrcl_clk.vbases[EFUSE_BASE]);
- pwrcl_clk.speedbin = ((pte_efuse >> PWRCL_EFUSE_SHIFT) &
- PWRCL_EFUSE_MASK);
- snprintf(pwrclspeedbinstr, ARRAY_SIZE(pwrclspeedbinstr),
- "qcom,pwrcl-speedbin%d-v%d", pwrcl_clk.speedbin,
- pvs_ver);
- }
-
- dev_info(&pdev->dev, "using pwrcl speed bin %u and pvs_ver %d\n",
- pwrcl_clk.speedbin, pvs_ver);
-
- rc = clk_osm_get_lut(pdev, &pwrcl_clk, pwrclspeedbinstr);
- if (rc) {
- dev_err(&pdev->dev, "Unable to get OSM LUT for power cluster, rc=%d\n",
- rc);
- return rc;
- }
-
- if (perfcl_clk.vbases[EFUSE_BASE]) {
- /* Multiple speed-bins are supported */
- pte_efuse = readl_relaxed(perfcl_clk.vbases[EFUSE_BASE]);
- perfcl_clk.speedbin = ((pte_efuse >> PERFCL_EFUSE_SHIFT) &
- PERFCL_EFUSE_MASK);
- snprintf(perfclspeedbinstr, ARRAY_SIZE(perfclspeedbinstr),
- "qcom,perfcl-speedbin%d-v%d", perfcl_clk.speedbin,
- pvs_ver);
- }
-
- dev_info(&pdev->dev, "using perfcl speed bin %u and pvs_ver %d\n",
- perfcl_clk.speedbin, pvs_ver);
-
- rc = clk_osm_get_lut(pdev, &perfcl_clk, perfclspeedbinstr);
- if (rc) {
- dev_err(&pdev->dev, "Unable to get OSM LUT for perf cluster, rc=%d\n",
- rc);
- return rc;
- }
-
- rc = clk_osm_parse_dt_configs(pdev);
- if (rc) {
- dev_err(&pdev->dev, "Unable to parse OSM device tree configurations\n");
- return rc;
- }
-
- rc = clk_osm_parse_acd_dt_configs(pdev);
- if (rc) {
- dev_err(&pdev->dev, "Unable to parse ACD device tree configurations\n");
- return rc;
- }
-
rc = clk_osm_resources_init(pdev);
if (rc) {
if (rc != -EPROBE_DEFER)
@@ -3097,170 +3085,282 @@
return rc;
}
- rc = clk_osm_acd_resources_init(pdev);
- if (rc) {
- dev_err(&pdev->dev, "ACD resources init failed, rc=%d\n",
- rc);
- return rc;
- }
+ if (!osm_tz_enabled) {
+ if (l3_clk.vbases[EFUSE_BASE]) {
+ /* Multiple speed-bins are supported */
+ pte_efuse = readl_relaxed(l3_clk.vbases[EFUSE_BASE]);
+ l3_clk.speedbin = ((pte_efuse >> L3_EFUSE_SHIFT) &
+ L3_EFUSE_MASK);
+ snprintf(l3speedbinstr, ARRAY_SIZE(l3speedbinstr),
+ "qcom,l3-speedbin%d-v%d", l3_clk.speedbin, pvs_ver);
+ }
- rc = clk_osm_resolve_open_loop_voltages(&l3_clk);
- if (rc) {
- if (rc == -EPROBE_DEFER)
+ dev_info(&pdev->dev, "using L3 speed bin %u and pvs_ver %d\n",
+ l3_clk.speedbin, pvs_ver);
+
+ rc = clk_osm_get_lut(pdev, &l3_clk, l3speedbinstr);
+ if (rc) {
+ dev_err(&pdev->dev, "Unable to get OSM LUT for L3, rc=%d\n",
+ rc);
return rc;
- dev_err(&pdev->dev, "Unable to determine open-loop voltages for L3, rc=%d\n",
- rc);
- return rc;
- }
+ }
- rc = clk_osm_resolve_open_loop_voltages(&pwrcl_clk);
- if (rc) {
- if (rc == -EPROBE_DEFER)
+ if (pwrcl_clk.vbases[EFUSE_BASE]) {
+ /* Multiple speed-bins are supported */
+ pte_efuse = readl_relaxed(pwrcl_clk.vbases[EFUSE_BASE]);
+ pwrcl_clk.speedbin = ((pte_efuse >> PWRCL_EFUSE_SHIFT) &
+ PWRCL_EFUSE_MASK);
+ snprintf(pwrclspeedbinstr, ARRAY_SIZE(pwrclspeedbinstr),
+ "qcom,pwrcl-speedbin%d-v%d", pwrcl_clk.speedbin,
+ pvs_ver);
+ }
+
+ dev_info(&pdev->dev, "using pwrcl speed bin %u and pvs_ver %d\n",
+ pwrcl_clk.speedbin, pvs_ver);
+
+ rc = clk_osm_get_lut(pdev, &pwrcl_clk, pwrclspeedbinstr);
+ if (rc) {
+ dev_err(&pdev->dev, "Unable to get OSM LUT for power cluster, rc=%d\n",
+ rc);
return rc;
- dev_err(&pdev->dev, "Unable to determine open-loop voltages for power cluster, rc=%d\n",
- rc);
- return rc;
- }
+ }
- rc = clk_osm_resolve_open_loop_voltages(&perfcl_clk);
- if (rc) {
- if (rc == -EPROBE_DEFER)
+ if (perfcl_clk.vbases[EFUSE_BASE]) {
+ /* Multiple speed-bins are supported */
+ pte_efuse =
+ readl_relaxed(perfcl_clk.vbases[EFUSE_BASE]);
+ perfcl_clk.speedbin = ((pte_efuse >> PERFCL_EFUSE_SHIFT)
+ & PERFCL_EFUSE_MASK);
+ snprintf(perfclspeedbinstr,
+ ARRAY_SIZE(perfclspeedbinstr),
+ "qcom,perfcl-speedbin%d-v%d",
+ perfcl_clk.speedbin, pvs_ver);
+ }
+
+ dev_info(&pdev->dev, "using perfcl speed bin %u and pvs_ver %d\n",
+ perfcl_clk.speedbin, pvs_ver);
+
+ rc = clk_osm_get_lut(pdev, &perfcl_clk, perfclspeedbinstr);
+ if (rc) {
+ dev_err(&pdev->dev, "Unable to get OSM LUT for perf cluster, rc=%d\n",
+ rc);
return rc;
- dev_err(&pdev->dev, "Unable to determine open-loop voltages for perf cluster, rc=%d\n",
- rc);
- return rc;
- }
+ }
- rc = clk_osm_resolve_crossover_corners(&l3_clk, pdev);
- if (rc)
- dev_info(&pdev->dev,
- "No APM crossover corner programmed for L3\n");
+ rc = clk_osm_parse_dt_configs(pdev);
+ if (rc) {
+ dev_err(&pdev->dev, "Unable to parse OSM device tree configurations\n");
+ return rc;
+ }
- rc = clk_osm_resolve_crossover_corners(&pwrcl_clk, pdev);
- if (rc)
- dev_info(&pdev->dev,
- "No APM crossover corner programmed for pwrcl_clk\n");
+ rc = clk_osm_parse_acd_dt_configs(pdev);
+ if (rc) {
+ dev_err(&pdev->dev, "Unable to parse ACD device tree configurations\n");
+ return rc;
+ }
- rc = clk_osm_resolve_crossover_corners(&perfcl_clk, pdev);
- if (rc)
- dev_info(&pdev->dev, "No MEM-ACC crossover corner programmed\n");
+ rc = clk_osm_acd_resources_init(pdev);
+ if (rc) {
+ dev_err(&pdev->dev, "ACD resources init failed, rc=%d\n",
+ rc);
+ return rc;
+ }
- clk_osm_setup_cycle_counters(&l3_clk);
- clk_osm_setup_cycle_counters(&pwrcl_clk);
- clk_osm_setup_cycle_counters(&perfcl_clk);
+ rc = clk_osm_resolve_open_loop_voltages(&l3_clk);
+ if (rc) {
+ if (rc == -EPROBE_DEFER)
+ return rc;
+ dev_err(&pdev->dev, "Unable to determine open-loop voltages for L3, rc=%d\n",
+ rc);
+ return rc;
+ }
+ rc = clk_osm_resolve_open_loop_voltages(&pwrcl_clk);
+ if (rc) {
+ if (rc == -EPROBE_DEFER)
+ return rc;
+ dev_err(&pdev->dev, "Unable to determine open-loop voltages for power cluster, rc=%d\n",
+ rc);
+ return rc;
+ }
+ rc = clk_osm_resolve_open_loop_voltages(&perfcl_clk);
+ if (rc) {
+ if (rc == -EPROBE_DEFER)
+ return rc;
+ dev_err(&pdev->dev, "Unable to determine open-loop voltages for perf cluster, rc=%d\n",
+ rc);
+ return rc;
+ }
- clk_osm_print_osm_table(&l3_clk);
- clk_osm_print_osm_table(&pwrcl_clk);
- clk_osm_print_osm_table(&perfcl_clk);
+ rc = clk_osm_resolve_crossover_corners(&l3_clk, pdev);
+ if (rc)
+ dev_info(&pdev->dev,
+ "No APM crossover corner programmed for L3\n");
+ rc = clk_osm_resolve_crossover_corners(&pwrcl_clk, pdev);
+ if (rc)
+ dev_info(&pdev->dev,
+ "No APM crossover corner programmed for pwrcl_clk\n");
+ rc = clk_osm_resolve_crossover_corners(&perfcl_clk, pdev);
+ if (rc)
+ dev_info(&pdev->dev, "No MEM-ACC crossover corner programmed\n");
- rc = clk_osm_setup_hw_table(&l3_clk);
- if (rc) {
- dev_err(&pdev->dev, "failed to setup l3 hardware table\n");
- goto exit;
- }
- rc = clk_osm_setup_hw_table(&pwrcl_clk);
- if (rc) {
- dev_err(&pdev->dev, "failed to setup power cluster hardware table\n");
- goto exit;
- }
- rc = clk_osm_setup_hw_table(&perfcl_clk);
- if (rc) {
- dev_err(&pdev->dev, "failed to setup perf cluster hardware table\n");
- goto exit;
- }
+ clk_osm_setup_cycle_counters(&l3_clk);
+ clk_osm_setup_cycle_counters(&pwrcl_clk);
+ clk_osm_setup_cycle_counters(&perfcl_clk);
- /* Policy tuning */
- rc = clk_osm_set_cc_policy(pdev);
- if (rc < 0) {
- dev_err(&pdev->dev, "cc policy setup failed");
- goto exit;
- }
+ clk_osm_print_osm_table(&l3_clk);
+ clk_osm_print_osm_table(&pwrcl_clk);
+ clk_osm_print_osm_table(&perfcl_clk);
- /* LLM Freq Policy Tuning */
- rc = clk_osm_set_llm_freq_policy(pdev);
- if (rc < 0) {
- dev_err(&pdev->dev, "LLM Frequency Policy setup failed");
- goto exit;
- }
+ rc = clk_osm_setup_hw_table(&l3_clk);
+ if (rc) {
+ dev_err(&pdev->dev, "failed to setup l3 hardware table\n");
+ goto exit;
+ }
+ rc = clk_osm_setup_hw_table(&pwrcl_clk);
+ if (rc) {
+ dev_err(&pdev->dev, "failed to setup power cluster hardware table\n");
+ goto exit;
+ }
+ rc = clk_osm_setup_hw_table(&perfcl_clk);
+ if (rc) {
+ dev_err(&pdev->dev, "failed to setup perf cluster hardware table\n");
+ goto exit;
+ }
- /* LLM Voltage Policy Tuning */
- rc = clk_osm_set_llm_volt_policy(pdev);
- if (rc < 0) {
- dev_err(&pdev->dev, "Failed to set LLM voltage Policy");
- goto exit;
- }
+ /* Policy tuning */
+ rc = clk_osm_set_cc_policy(pdev);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "cc policy setup failed");
+ goto exit;
+ }
- clk_osm_setup_fsms(&l3_clk);
- clk_osm_setup_fsms(&pwrcl_clk);
- clk_osm_setup_fsms(&perfcl_clk);
+ /* LLM Freq Policy Tuning */
+ rc = clk_osm_set_llm_freq_policy(pdev);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "LLM Frequency Policy setup failed");
+ goto exit;
+ }
- /* Program VC at which the array power supply needs to be switched */
- clk_osm_write_reg(&perfcl_clk, perfcl_clk.apm_threshold_vc,
+ /* LLM Voltage Policy Tuning */
+ rc = clk_osm_set_llm_volt_policy(pdev);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "Failed to set LLM voltage Policy");
+ goto exit;
+ }
+
+ clk_osm_setup_fsms(&l3_clk);
+ clk_osm_setup_fsms(&pwrcl_clk);
+ clk_osm_setup_fsms(&perfcl_clk);
+
+ /*
+ * Program the VC at which the array power supply
+ * needs to be switched.
+ */
+ clk_osm_write_reg(&perfcl_clk, perfcl_clk.apm_threshold_vc,
APM_CROSSOVER_VC, OSM_BASE);
- if (perfcl_clk.secure_init) {
- clk_osm_write_seq_reg(&perfcl_clk, perfcl_clk.apm_crossover_vc,
- DATA_MEM(77));
- clk_osm_write_seq_reg(&perfcl_clk,
+ if (perfcl_clk.secure_init) {
+ clk_osm_write_seq_reg(&perfcl_clk,
+ perfcl_clk.apm_crossover_vc, DATA_MEM(77));
+ clk_osm_write_seq_reg(&perfcl_clk,
(0x39 | (perfcl_clk.apm_threshold_vc << 6)),
DATA_MEM(111));
- } else {
- scm_io_write(perfcl_clk.pbases[SEQ_BASE] + DATA_MEM(77),
- perfcl_clk.apm_crossover_vc);
- scm_io_write(perfcl_clk.pbases[SEQ_BASE] + DATA_MEM(111),
+ } else {
+ scm_io_write(perfcl_clk.pbases[SEQ_BASE] + DATA_MEM(77),
+ perfcl_clk.apm_crossover_vc);
+ scm_io_write(perfcl_clk.pbases[SEQ_BASE] +
+ DATA_MEM(111),
(0x39 | (perfcl_clk.apm_threshold_vc << 6)));
- }
+ }
- /*
- * Perform typical secure-world HW initialization
- * as necessary.
- */
- clk_osm_do_additional_setup(&l3_clk, pdev);
- clk_osm_do_additional_setup(&pwrcl_clk, pdev);
- clk_osm_do_additional_setup(&perfcl_clk, pdev);
+ /*
+ * Perform typical secure-world HW initialization
+ * as necessary.
+ */
+ clk_osm_do_additional_setup(&l3_clk, pdev);
+ clk_osm_do_additional_setup(&pwrcl_clk, pdev);
+ clk_osm_do_additional_setup(&perfcl_clk, pdev);
- /* MEM-ACC Programming */
- clk_osm_program_mem_acc_regs(&l3_clk);
- clk_osm_program_mem_acc_regs(&pwrcl_clk);
- clk_osm_program_mem_acc_regs(&perfcl_clk);
+ /* MEM-ACC Programming */
+ clk_osm_program_mem_acc_regs(&l3_clk);
+ clk_osm_program_mem_acc_regs(&pwrcl_clk);
+ clk_osm_program_mem_acc_regs(&perfcl_clk);
- if (of_property_read_bool(pdev->dev.of_node, "qcom,osm-pll-setup")) {
- clk_osm_setup_cluster_pll(&l3_clk);
- clk_osm_setup_cluster_pll(&pwrcl_clk);
- clk_osm_setup_cluster_pll(&perfcl_clk);
- }
+ if (of_property_read_bool(pdev->dev.of_node,
+ "qcom,osm-pll-setup")) {
+ clk_osm_setup_cluster_pll(&l3_clk);
+ clk_osm_setup_cluster_pll(&pwrcl_clk);
+ clk_osm_setup_cluster_pll(&perfcl_clk);
+ }
- /* Misc programming */
- clk_osm_misc_programming(&l3_clk);
- clk_osm_misc_programming(&pwrcl_clk);
- clk_osm_misc_programming(&perfcl_clk);
+ /* Misc programming */
+ clk_osm_misc_programming(&l3_clk);
+ clk_osm_misc_programming(&pwrcl_clk);
+ clk_osm_misc_programming(&perfcl_clk);
- pwrcl_clk.per_core_dcvs = perfcl_clk.per_core_dcvs =
+ rc = clk_osm_acd_init(&l3_clk);
+ if (rc) {
+ pr_err("failed to initialize ACD for L3, rc=%d\n", rc);
+ goto exit;
+ }
+ rc = clk_osm_acd_init(&pwrcl_clk);
+ if (rc) {
+ pr_err("failed to initialize ACD for pwrcl, rc=%d\n",
+ rc);
+ goto exit;
+ }
+ rc = clk_osm_acd_init(&perfcl_clk);
+ if (rc) {
+ pr_err("failed to initialize ACD for perfcl, rc=%d\n",
+ rc);
+ goto exit;
+ }
+
+ pwrcl_clk.per_core_dcvs = perfcl_clk.per_core_dcvs =
of_property_read_bool(pdev->dev.of_node,
"qcom,enable-per-core-dcvs");
- if (pwrcl_clk.per_core_dcvs) {
+ if (pwrcl_clk.per_core_dcvs) {
+ val = clk_osm_read_reg(&pwrcl_clk, CORE_DCVS_CTRL);
+ val |= BIT(0);
+ clk_osm_write_reg(&pwrcl_clk, val, CORE_DCVS_CTRL,
+ OSM_BASE);
+ val = clk_osm_read_reg(&perfcl_clk, CORE_DCVS_CTRL);
+ val |= BIT(0);
+ clk_osm_write_reg(&perfcl_clk, val, CORE_DCVS_CTRL,
+ OSM_BASE);
+ }
+ } else {
+ /* OSM has been enabled already by trustzone */
+ rc = clk_osm_read_lut(pdev, &l3_clk);
+ if (rc) {
+ dev_err(&pdev->dev, "Unable to read OSM LUT for L3, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ rc = clk_osm_read_lut(pdev, &pwrcl_clk);
+ if (rc) {
+ dev_err(&pdev->dev, "Unable to read OSM LUT for power cluster, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ rc = clk_osm_read_lut(pdev, &perfcl_clk);
+ if (rc) {
+ dev_err(&pdev->dev, "Unable to read OSM LUT for perf cluster, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ /* Check if per-core DCVS is enabled/not */
val = clk_osm_read_reg(&pwrcl_clk, CORE_DCVS_CTRL);
- val |= BIT(0);
- clk_osm_write_reg(&pwrcl_clk, val, CORE_DCVS_CTRL, OSM_BASE);
+ if (val && BIT(0))
+ pwrcl_clk.per_core_dcvs = true;
val = clk_osm_read_reg(&perfcl_clk, CORE_DCVS_CTRL);
- val |= BIT(0);
- clk_osm_write_reg(&perfcl_clk, val, CORE_DCVS_CTRL, OSM_BASE);
- }
+ if (val && BIT(0))
+ perfcl_clk.per_core_dcvs = true;
- rc = clk_osm_acd_init(&l3_clk);
- if (rc) {
- pr_err("failed to initialize ACD for L3, rc=%d\n", rc);
- goto exit;
- }
- rc = clk_osm_acd_init(&pwrcl_clk);
- if (rc) {
- pr_err("failed to initialize ACD for pwrcl, rc=%d\n", rc);
- goto exit;
- }
- rc = clk_osm_acd_init(&perfcl_clk);
- if (rc) {
- pr_err("failed to initialize ACD for perfcl, rc=%d\n", rc);
- goto exit;
+ clk_ops_l3_osm.enable = NULL;
}
spin_lock_init(&l3_clk.lock);
@@ -3287,7 +3387,23 @@
get_online_cpus();
- /* Set the L3 clock to run off GPLL0 and enable OSM for the domain */
+ if (!osm_tz_enabled) {
+ populate_debugfs_dir(&l3_clk);
+ populate_debugfs_dir(&pwrcl_clk);
+ populate_debugfs_dir(&perfcl_clk);
+
+ /* Configure default rate to lowest frequency */
+ for (i = 0; i < MAX_CORE_COUNT; i++) {
+ osm_set_index(&pwrcl_clk, 0, i);
+ osm_set_index(&perfcl_clk, 0, i);
+ }
+ }
+ /*
+ * Set the L3 clock to run off GPLL0 and enable OSM for the domain.
+ * In the case that trustzone has already enabled OSM, bring the L3
+ * clock rate to a safe level until the devfreq driver comes up and
+ * votes for its desired frequency.
+ */
rc = clk_set_rate(l3_clk.hw.clk, OSM_INIT_RATE);
if (rc) {
dev_err(&pdev->dev, "Unable to set init rate on L3 cluster, rc=%d\n",
@@ -3295,21 +3411,12 @@
goto provider_err;
}
WARN(clk_prepare_enable(l3_cluster0_vote_clk.hw.clk),
- "clk: Failed to enable cluster0 clock for L3\n");
+ "clk: Failed to enable cluster0 clock for L3\n");
WARN(clk_prepare_enable(l3_cluster1_vote_clk.hw.clk),
- "clk: Failed to enable cluster1 clock for L3\n");
+ "clk: Failed to enable cluster1 clock for L3\n");
udelay(300);
- /* Configure default rate to lowest frequency */
- for (i = 0; i < MAX_CORE_COUNT; i++) {
- osm_set_index(&pwrcl_clk, 0, i);
- osm_set_index(&perfcl_clk, 0, i);
- }
-
populate_opp_table(pdev);
- populate_debugfs_dir(&l3_clk);
- populate_debugfs_dir(&pwrcl_clk);
- populate_debugfs_dir(&perfcl_clk);
of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
register_cpu_cycle_counter_cb(&cb);
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
index b63c3c3..7382cfa 100644
--- a/drivers/clk/qcom/clk-rcg2.c
+++ b/drivers/clk/qcom/clk-rcg2.c
@@ -138,9 +138,6 @@
int ret;
u32 cfg = rcg->parent_map[index].cfg << CFG_SRC_SEL_SHIFT;
- if (rcg->flags & DFS_ENABLE_RCG)
- return 0;
-
ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG,
CFG_SRC_SEL_MASK, cfg);
if (ret)
@@ -350,8 +347,9 @@
struct clk_hw *hw = &rcg->clkr.hw;
int ret, index = qcom_find_src_index(hw, rcg->parent_map, f->src);
+ /* Skip configuration if DFS control has been enabled for the RCG. */
if (rcg->flags & DFS_ENABLE_RCG)
- return -EPERM;
+ return 0;
if (index < 0)
return index;
@@ -481,7 +479,7 @@
}
ret = clk_rcg2_configure(rcg, f);
- if (ret && ret != -EPERM)
+ if (ret)
return ret;
if (rcg->flags & FORCE_ENABLE_RCG) {
@@ -934,10 +932,11 @@
EXPORT_SYMBOL_GPL(clk_byte2_ops);
static const struct frac_entry frac_table_pixel[] = {
+ { 1, 1 },
+ { 2, 3 },
+ { 4, 9 },
{ 3, 8 },
{ 2, 9 },
- { 4, 9 },
- { 1, 1 },
{ }
};
@@ -1028,6 +1027,7 @@
unsigned long parent_rate)
{
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
+ struct clk_hw *parent = clk_hw_get_parent(hw);
struct freq_tbl f = { 0 };
unsigned long src_rate;
unsigned long num, den;
@@ -1035,7 +1035,12 @@
u32 hid_div, cfg;
int i, num_parents = clk_hw_get_num_parents(hw);
- src_rate = clk_get_rate(clk_hw_get_parent(hw)->clk);
+ if (!parent) {
+ pr_err("RCG parent isn't initialized\n");
+ return -EINVAL;
+ }
+
+ src_rate = clk_get_rate(parent->clk);
if (src_rate <= 0) {
pr_err("Invalid RCG parent rate\n");
return -EINVAL;
@@ -1196,13 +1201,15 @@
u32 *mode, u32 *pre_div)
{
struct clk_rcg2 *rcg;
- int num_parents = clk_hw_get_num_parents(hw);
+ int num_parents;
u32 cfg, mask;
int i, ret;
if (!hw)
return -EINVAL;
+ num_parents = clk_hw_get_num_parents(hw);
+
rcg = to_clk_rcg2(hw);
ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + offset, &cfg);
@@ -1348,7 +1355,9 @@
"RCG flags %x\n", i, dfs_freq_tbl[i].freq, dfs_freq_tbl[i].src,
dfs_freq_tbl[i].pre_div, dfs_freq_tbl[i].m,
dfs_freq_tbl[i].n, rcg_flags);
-
+ /* Skip the safe configuration if DFS has been enabled for the RCG. */
+ if (clk->enable_safe_config)
+ clk->enable_safe_config = false;
clk->flags |= rcg_flags;
clk->freq_tbl = dfs_freq_tbl;
err:
diff --git a/drivers/clk/qcom/clk-regmap.c b/drivers/clk/qcom/clk-regmap.c
index 1c856d3..aa024c2d 100644
--- a/drivers/clk/qcom/clk-regmap.c
+++ b/drivers/clk/qcom/clk-regmap.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014, 2017, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -103,9 +103,12 @@
*/
int devm_clk_register_regmap(struct device *dev, struct clk_regmap *rclk)
{
- if (dev && dev_get_regmap(dev, NULL))
+ if (!dev || !rclk)
+ return -EINVAL;
+
+ if (dev_get_regmap(dev, NULL))
rclk->regmap = dev_get_regmap(dev, NULL);
- else if (dev && dev->parent)
+ else if (dev->parent)
rclk->regmap = dev_get_regmap(dev->parent, NULL);
return devm_clk_hw_register(dev, &rclk->hw);
diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c
index 1450b91..17b2403 100644
--- a/drivers/clk/qcom/gcc-sdm845.c
+++ b/drivers/clk/qcom/gcc-sdm845.c
@@ -182,6 +182,22 @@
"core_bi_pll_test_se",
};
+static const struct parent_map gcc_parent_map_10[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_MAIN, 1 },
+ { P_GPLL4_OUT_MAIN, 5 },
+ { P_GPLL0_OUT_EVEN, 6 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gcc_parent_names_10[] = {
+ "bi_tcxo",
+ "gpll0",
+ "gpll4",
+ "gpll0_out_even",
+ "core_bi_pll_test_se",
+};
+
static struct clk_dummy measure_only_snoc_clk = {
.rrate = 1000,
.hw.init = &(struct clk_init_data){
@@ -241,6 +257,28 @@
},
};
+static struct clk_alpha_pll gpll4 = {
+ .offset = 0x76000,
+ .vco_table = fabia_vco,
+ .num_vco = ARRAY_SIZE(fabia_vco),
+ .type = FABIA_PLL,
+ .clkr = {
+ .enable_reg = 0x52000,
+ .enable_mask = BIT(4),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll4",
+ .parent_names = (const char *[]){ "bi_tcxo" },
+ .num_parents = 1,
+ .ops = &clk_fabia_fixed_pll_ops,
+ VDD_CX_FMAX_MAP4(
+ MIN, 615000000,
+ LOW, 1066000000,
+ LOW_L1, 1600000000,
+ NOMINAL, 2000000000),
+ },
+ },
+};
+
static const struct clk_div_table post_div_table_fabia_even[] = {
{ 0x0, 1 },
{ 0x1, 2 },
@@ -476,6 +514,7 @@
F(19200000, P_BI_TCXO, 1, 0, 0),
F(29491200, P_GPLL0_OUT_EVEN, 1, 1536, 15625),
F(32000000, P_GPLL0_OUT_EVEN, 1, 8, 75),
+ F(38400000, P_GPLL0_OUT_EVEN, 1, 16, 125),
F(48000000, P_GPLL0_OUT_EVEN, 1, 4, 25),
F(64000000, P_GPLL0_OUT_EVEN, 1, 16, 75),
F(80000000, P_GPLL0_OUT_EVEN, 1, 4, 15),
@@ -830,7 +869,7 @@
F(25000000, P_GPLL0_OUT_EVEN, 12, 0, 0),
F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0),
F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0),
- F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0),
+ F(201500000, P_GPLL4_OUT_MAIN, 4, 0, 0),
{ }
};
@@ -838,12 +877,12 @@
.cmd_rcgr = 0x1400c,
.mnd_width = 8,
.hid_width = 5,
- .parent_map = gcc_parent_map_5,
+ .parent_map = gcc_parent_map_10,
.freq_tbl = ftbl_gcc_sdcc2_apps_clk_src,
.enable_safe_config = true,
.clkr.hw.init = &(struct clk_init_data){
.name = "gcc_sdcc2_apps_clk_src",
- .parent_names = gcc_parent_names_5,
+ .parent_names = gcc_parent_names_10,
.num_parents = 5,
.flags = CLK_SET_RATE_PARENT,
.ops = &clk_rcg2_ops,
@@ -851,7 +890,7 @@
MIN, 9600000,
LOWER, 19200000,
LOW, 100000000,
- LOW_L1, 200000000),
+ LOW_L1, 201500000),
},
};
@@ -1449,6 +1488,7 @@
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_camera_ahb_clk",
+ .flags = CLK_IS_CRITICAL,
.ops = &clk_branch2_ops,
},
},
@@ -1475,6 +1515,7 @@
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_camera_xo_clk",
+ .flags = CLK_IS_CRITICAL,
.ops = &clk_branch2_ops,
},
},
@@ -1569,7 +1610,7 @@
"gcc_cpuss_ahb_clk_src",
},
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
+ .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
.ops = &clk_branch2_ops,
},
},
@@ -1583,6 +1624,7 @@
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_cpuss_dvm_bus_clk",
+ .flags = CLK_IS_CRITICAL,
.ops = &clk_branch2_ops,
},
},
@@ -1598,6 +1640,7 @@
.enable_mask = BIT(22),
.hw.init = &(struct clk_init_data){
.name = "gcc_cpuss_gnoc_clk",
+ .flags = CLK_IS_CRITICAL,
.ops = &clk_branch2_ops,
},
},
@@ -1644,6 +1687,7 @@
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_disp_ahb_clk",
+ .flags = CLK_IS_CRITICAL,
.ops = &clk_branch2_ops,
},
},
@@ -1704,6 +1748,7 @@
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_disp_xo_clk",
+ .flags = CLK_IS_CRITICAL,
.ops = &clk_branch2_ops,
},
},
@@ -1773,6 +1818,7 @@
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_gpu_cfg_ahb_clk",
+ .flags = CLK_IS_CRITICAL,
.ops = &clk_branch2_ops,
},
},
@@ -2728,7 +2774,7 @@
"gcc_cpuss_ahb_clk_src",
},
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
+ .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
.ops = &clk_branch2_ops,
},
},
@@ -3501,6 +3547,7 @@
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_video_ahb_clk",
+ .flags = CLK_IS_CRITICAL,
.ops = &clk_branch2_ops,
},
},
@@ -3527,6 +3574,7 @@
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_video_xo_clk",
+ .flags = CLK_IS_CRITICAL,
.ops = &clk_branch2_ops,
},
},
@@ -3775,6 +3823,7 @@
[GCC_VSENSOR_CLK_SRC] = &gcc_vsensor_clk_src.clkr,
[GPLL0] = &gpll0.clkr,
[GPLL0_OUT_EVEN] = &gpll0_out_even.clkr,
+ [GPLL4] = &gpll4.clkr,
};
static const struct qcom_reset_map gcc_sdm845_resets[] = {
@@ -4030,22 +4079,9 @@
regmap_update_bits(regmap, GCC_MMSS_MISC, 0x3, 0x3);
regmap_update_bits(regmap, GCC_GPU_MISC, 0x3, 0x3);
- /* Keep these CPUSS clocks enabled always */
- clk_prepare_enable(gcc_cpuss_ahb_clk.clkr.hw.clk);
- clk_prepare_enable(gcc_sys_noc_cpuss_ahb_clk.clkr.hw.clk);
- clk_prepare_enable(gcc_cpuss_dvm_bus_clk.clkr.hw.clk);
- clk_prepare_enable(gcc_cpuss_gnoc_clk.clkr.hw.clk);
-
- /* Keep the core XO clock enabled always */
- clk_prepare_enable(gcc_camera_xo_clk.clkr.hw.clk);
- clk_prepare_enable(gcc_disp_xo_clk.clkr.hw.clk);
- clk_prepare_enable(gcc_video_xo_clk.clkr.hw.clk);
-
- /* Enable for core register access */
- clk_prepare_enable(gcc_gpu_cfg_ahb_clk.clkr.hw.clk);
- clk_prepare_enable(gcc_disp_ahb_clk.clkr.hw.clk);
- clk_prepare_enable(gcc_camera_ahb_clk.clkr.hw.clk);
- clk_prepare_enable(gcc_video_ahb_clk.clkr.hw.clk);
+ /* Keep this clock on all the time on SDM845 v1 */
+ if (of_device_is_compatible(pdev->dev.of_node, "qcom,gcc-sdm845"))
+ clk_prepare_enable(gcc_aggre_noc_pcie_tbu_clk.clkr.hw.clk);
/* DFS clock registration */
ret = qcom_cc_register_rcg_dfs(pdev, &gcc_sdm845_dfs_desc);
diff --git a/drivers/clk/qcom/gpucc-sdm845.c b/drivers/clk/qcom/gpucc-sdm845.c
index 5f1b1ef..1e98e08 100644
--- a/drivers/clk/qcom/gpucc-sdm845.c
+++ b/drivers/clk/qcom/gpucc-sdm845.c
@@ -142,6 +142,11 @@
.frac = 0x2aaa,
};
+static const struct pll_config gpu_cc_pll1_config = {
+ .l = 0x1a,
+ .frac = 0xaaaa,
+};
+
static struct clk_alpha_pll gpu_cc_pll0 = {
.offset = 0x0,
.vco_table = fabia_vco,
@@ -185,6 +190,26 @@
},
};
+static struct clk_alpha_pll gpu_cc_pll1 = {
+ .offset = 0x100,
+ .vco_table = fabia_vco,
+ .num_vco = ARRAY_SIZE(fabia_vco),
+ .type = FABIA_PLL,
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_pll1",
+ .parent_names = (const char *[]){ "bi_tcxo" },
+ .num_parents = 1,
+ .ops = &clk_fabia_pll_ops,
+ VDD_MX_FMAX_MAP4(
+ MIN, 615000000,
+ LOW, 1066000000,
+ LOW_L1, 1600000000,
+ NOMINAL, 2000000000),
+ },
+ },
+};
+
static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = {
F(19200000, P_BI_TCXO, 1, 0, 0),
F(200000000, P_GPLL0_OUT_MAIN_DIV, 1.5, 0, 0),
@@ -192,6 +217,13 @@
{ }
};
+static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src_sdm845_v2[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(200000000, P_GPLL0_OUT_MAIN_DIV, 1.5, 0, 0),
+ F(500000000, P_GPU_CC_PLL1_OUT_MAIN, 1, 0, 0),
+ { }
+};
+
static struct clk_rcg2 gpu_cc_gmu_clk_src = {
.cmd_rcgr = 0x1120,
.mnd_width = 0,
@@ -235,6 +267,18 @@
{ }
};
+static const struct freq_tbl ftbl_gpu_cc_gx_gfx3d_clk_src_sdm845_v2[] = {
+ F(180000000, P_CRC_DIV, 1, 0, 0),
+ F(257000000, P_CRC_DIV, 1, 0, 0),
+ F(342000000, P_CRC_DIV, 1, 0, 0),
+ F(414000000, P_CRC_DIV, 1, 0, 0),
+ F(520000000, P_CRC_DIV, 1, 0, 0),
+ F(596000000, P_CRC_DIV, 1, 0, 0),
+ F(675000000, P_CRC_DIV, 1, 0, 0),
+ F(710000000, P_CRC_DIV, 1, 0, 0),
+ { }
+};
+
static struct clk_rcg2 gpu_cc_gx_gfx3d_clk_src = {
.cmd_rcgr = 0x101c,
.mnd_width = 0,
@@ -510,10 +554,11 @@
[GPU_CC_GX_GMU_CLK] = &gpu_cc_gx_gmu_clk.clkr,
[GPU_CC_GX_VSENSE_CLK] = &gpu_cc_gx_vsense_clk.clkr,
[GPU_CC_PLL_TEST_CLK] = &gpu_cc_pll_test_clk.clkr,
+ [GPU_CC_PLL0] = &gpu_cc_pll0.clkr,
+ [GPU_CC_PLL1] = NULL,
};
static struct clk_regmap *gpu_cc_gfx_sdm845_clocks[] = {
- [GPU_CC_PLL0] = &gpu_cc_pll0.clkr,
[GPU_CC_PLL0_OUT_EVEN] = &gpu_cc_pll0_out_even.clkr,
[GPU_CC_GX_GFX3D_CLK_SRC] = &gpu_cc_gx_gfx3d_clk_src.clkr,
[GPU_CC_GX_GFX3D_CLK] = &gpu_cc_gx_gfx3d_clk.clkr,
@@ -553,16 +598,77 @@
static const struct of_device_id gpu_cc_sdm845_match_table[] = {
{ .compatible = "qcom,gpucc-sdm845" },
+ { .compatible = "qcom,gpucc-sdm845-v2" },
{ }
};
MODULE_DEVICE_TABLE(of, gpu_cc_sdm845_match_table);
static const struct of_device_id gpu_cc_gfx_sdm845_match_table[] = {
{ .compatible = "qcom,gfxcc-sdm845" },
+ { .compatible = "qcom,gfxcc-sdm845-v2" },
{},
};
MODULE_DEVICE_TABLE(of, gpu_cc_gfx_sdm845_match_table);
+static void gpu_cc_sdm845_fixup_sdm845v2(struct regmap *regmap)
+{
+ gpu_cc_sdm845_clocks[GPU_CC_PLL1] = &gpu_cc_pll1.clkr;
+ clk_fabia_pll_configure(&gpu_cc_pll1, regmap, &gpu_cc_pll1_config);
+
+ gpu_cc_gmu_clk_src.freq_tbl = ftbl_gpu_cc_gmu_clk_src_sdm845_v2;
+ gpu_cc_gmu_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = 500000000;
+}
+
+static void gpu_cc_gfx_sdm845_fixup_sdm845v2(void)
+{
+ gpu_cc_gx_gfx3d_clk_src.freq_tbl =
+ ftbl_gpu_cc_gx_gfx3d_clk_src_sdm845_v2;
+ gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_MIN] = 180000000;
+ gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_LOWER] =
+ 257000000;
+ gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_LOW] = 342000000;
+ gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_LOW_L1] =
+ 414000000;
+ gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_NOMINAL] =
+ 520000000;
+ gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_NOMINAL_L1] =
+ 596000000;
+ gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_HIGH] = 675000000;
+ gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_HIGH_L1] =
+ 710000000;
+}
+
+static int gpu_cc_gfx_sdm845_fixup(struct platform_device *pdev)
+{
+ const char *compat = NULL;
+ int compatlen = 0;
+
+ compat = of_get_property(pdev->dev.of_node, "compatible", &compatlen);
+ if (!compat || (compatlen <= 0))
+ return -EINVAL;
+
+ if (!strcmp(compat, "qcom,gfxcc-sdm845-v2"))
+ gpu_cc_gfx_sdm845_fixup_sdm845v2();
+
+ return 0;
+}
+
+static int gpu_cc_sdm845_fixup(struct platform_device *pdev,
+ struct regmap *regmap)
+{
+ const char *compat = NULL;
+ int compatlen = 0;
+
+ compat = of_get_property(pdev->dev.of_node, "compatible", &compatlen);
+ if (!compat || (compatlen <= 0))
+ return -EINVAL;
+
+ if (!strcmp(compat, "qcom,gpucc-sdm845-v2"))
+ gpu_cc_sdm845_fixup_sdm845v2(regmap);
+
+ return 0;
+}
+
static int gpu_cc_gfx_sdm845_probe(struct platform_device *pdev)
{
struct regmap *regmap;
@@ -596,15 +702,6 @@
return PTR_ERR(regmap);
}
- /* Get MX voltage regulator for GPU PLL graphic clock. */
- vdd_mx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_mx");
- if (IS_ERR(vdd_mx.regulator[0])) {
- if (!(PTR_ERR(vdd_mx.regulator[0]) == -EPROBE_DEFER))
- dev_err(&pdev->dev,
- "Unable to get vdd_mx regulator\n");
- return PTR_ERR(vdd_mx.regulator[0]);
- }
-
/* GFX voltage regulators for GFX3D graphic clock. */
vdd_gfx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_gfx");
if (IS_ERR(vdd_gfx.regulator[0])) {
@@ -616,6 +713,12 @@
/* Avoid turning on the rail during clock registration */
vdd_gfx.skip_handoff = true;
+ ret = gpu_cc_gfx_sdm845_fixup(pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to do GFX clock fixup\n");
+ return ret;
+ }
+
clk_fabia_pll_configure(&gpu_cc_pll0, regmap, &gpu_cc_pll0_config);
ret = qcom_cc_really_probe(pdev, &gpu_cc_gfx_sdm845_desc, regmap);
@@ -668,6 +771,21 @@
return PTR_ERR(vdd_cx.regulator[0]);
}
+ /* Get MX voltage regulator for GPU PLL graphic clock. */
+ vdd_mx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_mx");
+ if (IS_ERR(vdd_mx.regulator[0])) {
+ if (!(PTR_ERR(vdd_mx.regulator[0]) == -EPROBE_DEFER))
+ dev_err(&pdev->dev,
+ "Unable to get vdd_mx regulator\n");
+ return PTR_ERR(vdd_mx.regulator[0]);
+ }
+
+ ret = gpu_cc_sdm845_fixup(pdev, regmap);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to do GPU CC clock fixup\n");
+ return ret;
+ }
+
ret = qcom_cc_really_probe(pdev, &gpu_cc_sdm845_desc, regmap);
if (ret) {
dev_err(&pdev->dev, "Failed to register GPU CC clocks\n");
diff --git a/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c b/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c
index 93ad1b0..eb6c658 100644
--- a/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c
+++ b/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c
@@ -94,7 +94,6 @@
struct dsi_pll_regs {
u32 pll_prop_gain_rate;
- u32 pll_outdiv_rate;
u32 pll_lockdet_rate;
u32 decimal_div_start;
u32 frac_div_start_low;
@@ -134,6 +133,165 @@
struct dsi_pll_regs reg_setup;
};
+static inline int pll_reg_read(void *context, unsigned int reg,
+ unsigned int *val)
+{
+ int rc = 0;
+ struct mdss_pll_resources *rsc = context;
+
+ rc = mdss_pll_resource_enable(rsc, true);
+ if (rc) {
+ pr_err("Failed to enable dsi pll resources, rc=%d\n", rc);
+ return rc;
+ }
+
+ *val = MDSS_PLL_REG_R(rsc->pll_base, reg);
+ (void)mdss_pll_resource_enable(rsc, false);
+
+ return rc;
+}
+
+static inline int pll_reg_write(void *context, unsigned int reg,
+ unsigned int val)
+{
+ int rc = 0;
+ struct mdss_pll_resources *rsc = context;
+
+ rc = mdss_pll_resource_enable(rsc, true);
+ if (rc) {
+ pr_err("Failed to enable dsi pll resources, rc=%d\n", rc);
+ return rc;
+ }
+
+ MDSS_PLL_REG_W(rsc->pll_base, reg, val);
+ (void)mdss_pll_resource_enable(rsc, false);
+
+ return rc;
+}
+
+static inline int phy_reg_read(void *context, unsigned int reg,
+ unsigned int *val)
+{
+ int rc = 0;
+ struct mdss_pll_resources *rsc = context;
+
+ rc = mdss_pll_resource_enable(rsc, true);
+ if (rc) {
+ pr_err("Failed to enable dsi pll resources, rc=%d\n", rc);
+ return rc;
+ }
+
+ *val = MDSS_PLL_REG_R(rsc->phy_base, reg);
+ (void)mdss_pll_resource_enable(rsc, false);
+
+ return rc;
+}
+
+static inline int phy_reg_write(void *context, unsigned int reg,
+ unsigned int val)
+{
+ int rc = 0;
+ struct mdss_pll_resources *rsc = context;
+
+ rc = mdss_pll_resource_enable(rsc, true);
+ if (rc) {
+ pr_err("Failed to enable dsi pll resources, rc=%d\n", rc);
+ return rc;
+ }
+
+ MDSS_PLL_REG_W(rsc->phy_base, reg, val);
+ (void)mdss_pll_resource_enable(rsc, false);
+
+ return rc;
+}
+
+static inline int phy_reg_update_bits_sub(struct mdss_pll_resources *rsc,
+ unsigned int reg, unsigned int mask, unsigned int val)
+{
+ u32 reg_val;
+ int rc = 0;
+
+ reg_val = MDSS_PLL_REG_R(rsc->phy_base, reg);
+ reg_val &= ~mask;
+ reg_val |= (val & mask);
+ MDSS_PLL_REG_W(rsc->phy_base, reg, reg_val);
+
+ return rc;
+}
+
+static inline int phy_reg_update_bits(void *context, unsigned int reg,
+ unsigned int mask, unsigned int val)
+{
+ int rc = 0;
+ struct mdss_pll_resources *rsc = context;
+
+ rc = mdss_pll_resource_enable(rsc, true);
+ if (rc) {
+ pr_err("Failed to enable dsi pll resources, rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = phy_reg_update_bits_sub(rsc, reg, mask, val);
+ if (!rc && rsc->slave)
+ rc = phy_reg_update_bits_sub(rsc->slave, reg, mask, val);
+ (void)mdss_pll_resource_enable(rsc, false);
+
+ return rc;
+}
+
+static inline int pclk_mux_read_sel(void *context, unsigned int reg,
+ unsigned int *val)
+{
+ int rc = 0;
+ struct mdss_pll_resources *rsc = context;
+
+ rc = mdss_pll_resource_enable(rsc, true);
+ if (rc)
+ pr_err("Failed to enable dsi pll resources, rc=%d\n", rc);
+ else
+ *val = (MDSS_PLL_REG_R(rsc->pll_base, reg) & 0x3);
+
+ (void)mdss_pll_resource_enable(rsc, false);
+ return rc;
+}
+
+
+static inline int pclk_mux_write_sel_sub(struct mdss_pll_resources *rsc,
+ unsigned int reg, unsigned int val)
+{
+ u32 reg_val;
+ int rc = 0;
+
+ reg_val = MDSS_PLL_REG_R(rsc->phy_base, reg);
+ reg_val &= ~0x03;
+ reg_val |= val;
+
+ MDSS_PLL_REG_W(rsc->phy_base, reg, reg_val);
+
+ return rc;
+}
+
+static inline int pclk_mux_write_sel(void *context, unsigned int reg,
+ unsigned int val)
+{
+ int rc = 0;
+ struct mdss_pll_resources *rsc = context;
+
+ rc = mdss_pll_resource_enable(rsc, true);
+ if (rc) {
+ pr_err("Failed to enable dsi pll resources, rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = pclk_mux_write_sel_sub(rsc, reg, val);
+ if (!rc && rsc->slave)
+ rc = pclk_mux_write_sel_sub(rsc->slave, reg, val);
+
+ (void)mdss_pll_resource_enable(rsc, false);
+
+ return rc;
+}
+
static struct mdss_pll_resources *pll_rsc_db[DSI_PLL_MAX];
static struct dsi_pll_10nm plls[DSI_PLL_MAX];
@@ -203,54 +361,14 @@
{
struct dsi_pll_config *config = &pll->pll_configuration;
struct dsi_pll_regs *regs = &pll->reg_setup;
- u64 target_freq;
u64 fref = rsc->vco_ref_clk_rate;
- u32 computed_output_div, div_log = 0;
u64 pll_freq;
u64 divider;
u64 dec, dec_multiple;
u32 frac;
u64 multiplier;
- u32 i;
- target_freq = rsc->vco_current_rate;
- pr_debug("target_freq = %llu\n", target_freq);
-
- if (config->div_override) {
- computed_output_div = config->output_div;
-
- /*
- * Computed_output_div = 2 ^ div_log
- * To get div_log from output div just get the index of the
- * 1 bit in the value.
- * div_log ranges from 0-3. so check the 4 lsbs
- */
-
- for (i = 0; i < 4; i++) {
- if (computed_output_div & (1 << i)) {
- div_log = i;
- break;
- }
- }
-
- } else {
- if (target_freq < MHZ_250) {
- computed_output_div = 8;
- div_log = 3;
- } else if (target_freq < MHZ_500) {
- computed_output_div = 4;
- div_log = 2;
- } else if (target_freq < MHZ_1000) {
- computed_output_div = 2;
- div_log = 1;
- } else {
- computed_output_div = 1;
- div_log = 0;
- }
- }
- pr_debug("computed_output_div = %d\n", computed_output_div);
-
- pll_freq = target_freq * computed_output_div;
+ pll_freq = rsc->vco_current_rate;
if (config->disable_prescaler)
divider = fref;
@@ -274,7 +392,6 @@
else
regs->pll_clock_inverters = 0;
- regs->pll_outdiv_rate = div_log;
regs->pll_lockdet_rate = config->lock_timer;
regs->decimal_div_start = dec;
regs->frac_div_start_low = (frac & 0xff);
@@ -394,7 +511,6 @@
MDSS_PLL_REG_W(pll_base, PLL_FRAC_DIV_START_HIGH_1,
reg->frac_div_start_high);
MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCKDET_RATE_1, 0x40);
- MDSS_PLL_REG_W(pll_base, PLL_PLL_OUTDIV_RATE, reg->pll_outdiv_rate);
MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCK_DELAY, 0x06);
MDSS_PLL_REG_W(pll_base, PLL_CMODE, 0x10);
MDSS_PLL_REG_W(pll_base, PLL_CLOCK_INVERTERS, reg->pll_clock_inverters);
@@ -605,7 +721,9 @@
}
pll->cached_cfg0 = MDSS_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG0);
pll->cached_cfg1 = MDSS_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG1);
- pr_debug("cfg0=%d,cfg1=%d\n", pll->cached_cfg0, pll->cached_cfg1);
+ pll->cached_outdiv = MDSS_PLL_REG_R(pll->pll_base, PLL_PLL_OUTDIV_RATE);
+ pr_debug("cfg0=%d,cfg1=%d, outdiv=%d\n", pll->cached_cfg0,
+ pll->cached_cfg1, pll->cached_outdiv);
pll->vco_cached_rate = clk_hw_get_rate(hw);
dsi_pll_disable(vco);
@@ -646,6 +764,8 @@
pll->cached_cfg0);
MDSS_PLL_REG_W(pll->phy_base, PHY_CMN_CLK_CFG1,
pll->cached_cfg1);
+ MDSS_PLL_REG_W(pll->pll_base, PLL_PLL_OUTDIV_RATE,
+ pll->cached_outdiv);
}
rc = dsi_pll_enable(vco);
@@ -855,176 +975,6 @@
return rc;
}
-static int post_vco_clk_get_div(void *context, unsigned int reg,
- unsigned int *div)
-{
- int rc;
- struct mdss_pll_resources *pll = context;
- u32 reg_val;
-
- rc = mdss_pll_resource_enable(pll, true);
- if (rc) {
- pr_err("Failed to enable dsi pll resources, rc=%d\n", rc);
- return rc;
- }
-
- reg_val = MDSS_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG1);
- reg_val &= 0x3;
-
- if (reg_val == 2)
- *div = 1;
- else if (reg_val == 3)
- *div = 4;
- else
- *div = 1;
-
- /**
- *Common clock framework the divider value is interpreted as one less
- * hence we return one less for all dividers except when zero
- */
- if (*div != 0)
- *div -= 1;
-
- (void)mdss_pll_resource_enable(pll, false);
-
- return rc;
-}
-
-static int post_vco_clk_set_div_sub(struct mdss_pll_resources *pll, int div)
-{
- u32 reg_val;
- int rc = 0;
-
- reg_val = MDSS_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG1);
- reg_val &= ~0x03;
- if (div == 1) {
- reg_val |= 0x2;
- } else if (div == 4) {
- reg_val |= 0x3;
- } else {
- rc = -EINVAL;
- pr_err("unsupported divider %d\n", div);
- goto error;
- }
-
- MDSS_PLL_REG_W(pll->phy_base, PHY_CMN_CLK_CFG1, reg_val);
-
-error:
- return rc;
-}
-
-static int post_vco_clk_set_div(void *context, unsigned int reg,
- unsigned int div)
-{
- int rc = 0;
- struct mdss_pll_resources *pll = context;
-
- rc = mdss_pll_resource_enable(pll, true);
- if (rc) {
- pr_err("Failed to enable dsi pll resources, rc=%d\n", rc);
- return rc;
- }
-
- /**
- * In common clock framework the divider value provided is one less and
- * and hence adjusting the divider value by one prior to writing it to
- * hardware
- */
- div++;
- rc = post_vco_clk_set_div_sub(pll, div);
- if (!rc && pll->slave)
- rc = post_vco_clk_set_div_sub(pll->slave, div);
-
- (void)mdss_pll_resource_enable(pll, false);
-
- return rc;
-}
-
-static int post_bit_clk_get_div(void *context, unsigned int reg,
- unsigned int *div)
-{
- int rc;
- struct mdss_pll_resources *pll = context;
- u32 reg_val;
-
- rc = mdss_pll_resource_enable(pll, true);
- if (rc) {
- pr_err("Failed to enable dsi pll resources, rc=%d\n", rc);
- return rc;
- }
-
- reg_val = MDSS_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG1);
- reg_val &= 0x3;
-
- if (reg_val == 0)
- *div = 1;
- else if (reg_val == 1)
- *div = 2;
- else
- *div = 1;
-
- /**
- *Common clock framework the divider value is interpreted as one less
- * hence we return one less for all dividers except when zero
- */
- if (*div != 0)
- *div -= 1;
-
- (void)mdss_pll_resource_enable(pll, false);
-
- return rc;
-}
-
-static int post_bit_clk_set_div_sub(struct mdss_pll_resources *pll, int div)
-{
- int rc = 0;
- u32 reg_val;
-
- reg_val = MDSS_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG1);
- reg_val &= ~0x03;
- if (div == 1) {
- reg_val |= 0x0;
- } else if (div == 2) {
- reg_val |= 0x1;
- } else {
- rc = -EINVAL;
- pr_err("unsupported divider %d\n", div);
- goto error;
- }
-
- MDSS_PLL_REG_W(pll->phy_base, PHY_CMN_CLK_CFG1, reg_val);
-
-error:
- return rc;
-}
-
-static int post_bit_clk_set_div(void *context, unsigned int reg,
- unsigned int div)
-{
- int rc = 0;
- struct mdss_pll_resources *pll = context;
-
- rc = mdss_pll_resource_enable(pll, true);
- if (rc) {
- pr_err("Failed to enable dsi pll resources, rc=%d\n", rc);
- return rc;
- }
-
- /**
- * In common clock framework the divider value provided is one less and
- * and hence adjusting the divider value by one prior to writing it to
- * hardware
- */
- div++;
- rc = post_bit_clk_set_div_sub(pll, div);
- if (!rc && pll->slave)
- rc = post_bit_clk_set_div_sub(pll->slave, div);
-
- (void)mdss_pll_resource_enable(pll, false);
-
- return rc;
-}
-
static struct regmap_config dsi_pll_10nm_config = {
.reg_bits = 32,
.reg_stride = 4,
@@ -1032,14 +982,14 @@
.max_register = 0x7c0,
};
-static struct regmap_bus post_vco_regmap_bus = {
- .reg_write = post_vco_clk_set_div,
- .reg_read = post_vco_clk_get_div,
+static struct regmap_bus pll_regmap_bus = {
+ .reg_write = pll_reg_write,
+ .reg_read = pll_reg_read,
};
-static struct regmap_bus post_bit_regmap_bus = {
- .reg_write = post_bit_clk_set_div,
- .reg_read = post_bit_clk_get_div,
+static struct regmap_bus pclk_mux_regmap_bus = {
+ .reg_read = phy_reg_read,
+ .reg_write = pclk_mux_write_sel,
};
static struct regmap_bus pclk_src_regmap_bus = {
@@ -1073,23 +1023,30 @@
* | vco_clk |
* +-------+-------+
* |
- * +--------------------------------------+
- * | |
- * +-------v-------+ |
- * | bitclk_src | |
- * | DIV(1..15) | |
- * +-------+-------+ |
- * | |
- * +--------------------+ |
- * Shadow Path | | |
- * + +-------v-------+ +------v------+ +------v-------+
- * | | byteclk_src | |post_bit_div | |post_vco_div |
- * | | DIV(8) | |DIV(1,2) | |DIV(1,4) |
- * | +-------+-------+ +------+------+ +------+-------+
- * | | | |
- * | | +------+ +----+
- * | +--------+ | |
- * | | +----v-----v------+
+ * |
+ * +---------------+
+ * | pll_out_div |
+ * | DIV(1,2,4,8) |
+ * +-------+-------+
+ * |
+ * +-----------------------------+--------+
+ * | | |
+ * +-------v-------+ | |
+ * | bitclk_src | | |
+ * | DIV(1..15) | | |
+ * +-------+-------+ | |
+ * | | |
+ * +----------+---------+ | |
+ * Shadow Path | | | | |
+ * + +-------v-------+ | +------v------+ | +------v-------+
+ * | | byteclk_src | | |post_bit_div | | |post_vco_div |
+ * | | DIV(8) | | |DIV (2) | | |DIV(4) |
+ * | +-------+-------+ | +------+------+ | +------+-------+
+ * | | | | | | |
+ * | | | +------+ | |
+ * | | +-------------+ | | +----+
+ * | +--------+ | | | |
+ * | | +-v--v-v---v------+
* +-v---------v----+ \ pclk_src_mux /
* \ byteclk_mux / \ /
* \ / +-----+-----+
@@ -1140,13 +1097,45 @@
},
};
+static struct clk_regmap_div dsi0pll_pll_out_div = {
+ .reg = PLL_PLL_OUTDIV_RATE,
+ .shift = 0,
+ .width = 2,
+ .flags = CLK_DIVIDER_POWER_OF_TWO,
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi0pll_pll_out_div",
+ .parent_names = (const char *[]){"dsi0pll_vco_clk"},
+ .num_parents = 1,
+ .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
+ .ops = &clk_regmap_div_ops,
+ },
+ },
+};
+
+static struct clk_regmap_div dsi1pll_pll_out_div = {
+ .reg = PLL_PLL_OUTDIV_RATE,
+ .shift = 0,
+ .width = 2,
+ .flags = CLK_DIVIDER_POWER_OF_TWO,
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi1pll_pll_out_div",
+ .parent_names = (const char *[]){"dsi1pll_vco_clk"},
+ .num_parents = 1,
+ .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
+ .ops = &clk_regmap_div_ops,
+ },
+ },
+};
+
static struct clk_regmap_div dsi0pll_bitclk_src = {
.shift = 0,
.width = 4,
.clkr = {
.hw.init = &(struct clk_init_data){
.name = "dsi0pll_bitclk_src",
- .parent_names = (const char *[]){"dsi0pll_vco_clk"},
+ .parent_names = (const char *[]){"dsi0pll_pll_out_div"},
.num_parents = 1,
.flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
.ops = &clk_regmap_div_ops,
@@ -1160,7 +1149,7 @@
.clkr = {
.hw.init = &(struct clk_init_data){
.name = "dsi1pll_bitclk_src",
- .parent_names = (const char *[]){"dsi1pll_vco_clk"},
+ .parent_names = (const char *[]){"dsi1pll_pll_out_div"},
.num_parents = 1,
.flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
.ops = &clk_regmap_div_ops,
@@ -1168,31 +1157,27 @@
},
};
-static struct clk_regmap_div dsi0pll_post_vco_div = {
- .shift = 0,
- .width = 2,
- .clkr = {
- .hw.init = &(struct clk_init_data){
- .name = "dsi0pll_post_vco_div",
- .parent_names = (const char *[]){"dsi0pll_vco_clk"},
- .num_parents = 1,
- .flags = CLK_GET_RATE_NOCACHE,
- .ops = &clk_regmap_div_ops,
- },
+static struct clk_fixed_factor dsi0pll_post_vco_div = {
+ .div = 4,
+ .mult = 1,
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi0pll_post_vco_div",
+ .parent_names = (const char *[]){"dsi0pll_pll_out_div"},
+ .num_parents = 1,
+ .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
+ .ops = &clk_fixed_factor_ops,
},
};
-static struct clk_regmap_div dsi1pll_post_vco_div = {
- .shift = 0,
- .width = 2,
- .clkr = {
- .hw.init = &(struct clk_init_data){
- .name = "dsi1pll_post_vco_div",
- .parent_names = (const char *[]){"dsi1pll_vco_clk"},
- .num_parents = 1,
- .flags = CLK_GET_RATE_NOCACHE,
- .ops = &clk_regmap_div_ops,
- },
+static struct clk_fixed_factor dsi1pll_post_vco_div = {
+ .div = 4,
+ .mult = 1,
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi1pll_post_vco_div",
+ .parent_names = (const char *[]){"dsi1pll_pll_out_div"},
+ .num_parents = 1,
+ .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
+ .ops = &clk_fixed_factor_ops,
},
};
@@ -1220,31 +1205,27 @@
},
};
-static struct clk_regmap_div dsi0pll_post_bit_div = {
- .shift = 0,
- .width = 1,
- .clkr = {
- .hw.init = &(struct clk_init_data){
- .name = "dsi0pll_post_bit_div",
- .parent_names = (const char *[]){"dsi0pll_bitclk_src"},
- .num_parents = 1,
- .flags = CLK_GET_RATE_NOCACHE,
- .ops = &clk_regmap_div_ops,
- },
+static struct clk_fixed_factor dsi0pll_post_bit_div = {
+ .div = 2,
+ .mult = 1,
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi0pll_post_bit_div",
+ .parent_names = (const char *[]){"dsi0pll_bitclk_src"},
+ .num_parents = 1,
+ .flags = CLK_GET_RATE_NOCACHE,
+ .ops = &clk_fixed_factor_ops,
},
};
-static struct clk_regmap_div dsi1pll_post_bit_div = {
- .shift = 0,
- .width = 1,
- .clkr = {
- .hw.init = &(struct clk_init_data){
- .name = "dsi1pll_post_bit_div",
- .parent_names = (const char *[]){"dsi1pll_bitclk_src"},
- .num_parents = 1,
- .flags = CLK_GET_RATE_NOCACHE,
- .ops = &clk_regmap_div_ops,
- },
+static struct clk_fixed_factor dsi1pll_post_bit_div = {
+ .div = 2,
+ .mult = 1,
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi1pll_post_bit_div",
+ .parent_names = (const char *[]){"dsi1pll_bitclk_src"},
+ .num_parents = 1,
+ .flags = CLK_GET_RATE_NOCACHE,
+ .ops = &clk_fixed_factor_ops,
},
};
@@ -1277,30 +1258,36 @@
};
static struct clk_regmap_mux dsi0pll_pclk_src_mux = {
+ .reg = PHY_CMN_CLK_CFG1,
.shift = 0,
- .width = 1,
+ .width = 2,
.clkr = {
.hw.init = &(struct clk_init_data){
.name = "dsi0pll_pclk_src_mux",
- .parent_names = (const char *[]){"dsi0pll_post_bit_div",
- "dsi0pll_post_vco_div"},
- .num_parents = 2,
- .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
+ .parent_names = (const char *[]){"dsi0pll_bitclk_src",
+ "dsi0pll_post_bit_div",
+ "dsi0pll_pll_out_div",
+ "dsi0pll_post_vco_div"},
+ .num_parents = 4,
+ .flags = CLK_GET_RATE_NOCACHE,
.ops = &clk_regmap_mux_closest_ops,
},
},
};
static struct clk_regmap_mux dsi1pll_pclk_src_mux = {
+ .reg = PHY_CMN_CLK_CFG1,
.shift = 0,
- .width = 1,
+ .width = 2,
.clkr = {
.hw.init = &(struct clk_init_data){
.name = "dsi1pll_pclk_src_mux",
- .parent_names = (const char *[]){"dsi1pll_post_bit_div",
- "dsi1pll_post_vco_div"},
- .num_parents = 2,
- .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
+ .parent_names = (const char *[]){"dsi1pll_bitclk_src",
+ "dsi1pll_post_bit_div",
+ "dsi1pll_pll_out_div",
+ "dsi1pll_post_vco_div"},
+ .num_parents = 4,
+ .flags = CLK_GET_RATE_NOCACHE,
.ops = &clk_regmap_mux_closest_ops,
},
},
@@ -1366,24 +1353,25 @@
static struct clk_hw *mdss_dsi_pllcc_10nm[] = {
[VCO_CLK_0] = &dsi0pll_vco_clk.hw,
+ [PLL_OUT_DIV_0_CLK] = &dsi0pll_pll_out_div.clkr.hw,
[BITCLK_SRC_0_CLK] = &dsi0pll_bitclk_src.clkr.hw,
[BYTECLK_SRC_0_CLK] = &dsi0pll_byteclk_src.hw,
- [POST_BIT_DIV_0_CLK] = &dsi0pll_post_bit_div.clkr.hw,
- [POST_VCO_DIV_0_CLK] = &dsi0pll_post_vco_div.clkr.hw,
+ [POST_BIT_DIV_0_CLK] = &dsi0pll_post_bit_div.hw,
+ [POST_VCO_DIV_0_CLK] = &dsi0pll_post_vco_div.hw,
[BYTECLK_MUX_0_CLK] = &dsi0pll_byteclk_mux.clkr.hw,
[PCLK_SRC_MUX_0_CLK] = &dsi0pll_pclk_src_mux.clkr.hw,
[PCLK_SRC_0_CLK] = &dsi0pll_pclk_src.clkr.hw,
[PCLK_MUX_0_CLK] = &dsi0pll_pclk_mux.clkr.hw,
[VCO_CLK_1] = &dsi1pll_vco_clk.hw,
+ [PLL_OUT_DIV_1_CLK] = &dsi1pll_pll_out_div.clkr.hw,
[BITCLK_SRC_1_CLK] = &dsi1pll_bitclk_src.clkr.hw,
[BYTECLK_SRC_1_CLK] = &dsi1pll_byteclk_src.hw,
- [POST_BIT_DIV_1_CLK] = &dsi1pll_post_bit_div.clkr.hw,
- [POST_VCO_DIV_1_CLK] = &dsi1pll_post_vco_div.clkr.hw,
+ [POST_BIT_DIV_1_CLK] = &dsi1pll_post_bit_div.hw,
+ [POST_VCO_DIV_1_CLK] = &dsi1pll_post_vco_div.hw,
[BYTECLK_MUX_1_CLK] = &dsi1pll_byteclk_mux.clkr.hw,
[PCLK_SRC_MUX_1_CLK] = &dsi1pll_pclk_src_mux.clkr.hw,
[PCLK_SRC_1_CLK] = &dsi1pll_pclk_src.clkr.hw,
[PCLK_MUX_1_CLK] = &dsi1pll_pclk_mux.clkr.hw,
-
};
int dsi_pll_clock_register_10nm(struct platform_device *pdev,
@@ -1428,13 +1416,10 @@
/* Establish client data */
if (ndx == 0) {
- rmap = devm_regmap_init(&pdev->dev, &post_vco_regmap_bus,
- pll_res, &dsi_pll_10nm_config);
- dsi0pll_post_vco_div.clkr.regmap = rmap;
- rmap = devm_regmap_init(&pdev->dev, &post_bit_regmap_bus,
+ rmap = devm_regmap_init(&pdev->dev, &pll_regmap_bus,
pll_res, &dsi_pll_10nm_config);
- dsi0pll_post_bit_div.clkr.regmap = rmap;
+ dsi0pll_pll_out_div.clkr.regmap = rmap;
rmap = devm_regmap_init(&pdev->dev, &bitclk_src_regmap_bus,
pll_res, &dsi_pll_10nm_config);
@@ -1448,10 +1433,9 @@
pll_res, &dsi_pll_10nm_config);
dsi0pll_pclk_mux.clkr.regmap = rmap;
- rmap = devm_regmap_init(&pdev->dev, &mdss_mux_regmap_bus,
+ rmap = devm_regmap_init(&pdev->dev, &pclk_mux_regmap_bus,
pll_res, &dsi_pll_10nm_config);
dsi0pll_pclk_src_mux.clkr.regmap = rmap;
-
rmap = devm_regmap_init(&pdev->dev, &mdss_mux_regmap_bus,
pll_res, &dsi_pll_10nm_config);
dsi0pll_byteclk_mux.clkr.regmap = rmap;
@@ -1475,13 +1459,9 @@
} else {
- rmap = devm_regmap_init(&pdev->dev, &post_vco_regmap_bus,
+ rmap = devm_regmap_init(&pdev->dev, &pll_regmap_bus,
pll_res, &dsi_pll_10nm_config);
- dsi1pll_post_vco_div.clkr.regmap = rmap;
-
- rmap = devm_regmap_init(&pdev->dev, &post_bit_regmap_bus,
- pll_res, &dsi_pll_10nm_config);
- dsi1pll_post_bit_div.clkr.regmap = rmap;
+ dsi1pll_pll_out_div.clkr.regmap = rmap;
rmap = devm_regmap_init(&pdev->dev, &bitclk_src_regmap_bus,
pll_res, &dsi_pll_10nm_config);
@@ -1491,14 +1471,13 @@
pll_res, &dsi_pll_10nm_config);
dsi1pll_pclk_src.clkr.regmap = rmap;
- rmap = devm_regmap_init(&pdev->dev, &mdss_mux_regmap_bus,
+ rmap = devm_regmap_init(&pdev->dev, &pclk_mux_regmap_bus,
pll_res, &dsi_pll_10nm_config);
dsi1pll_pclk_mux.clkr.regmap = rmap;
rmap = devm_regmap_init(&pdev->dev, &mdss_mux_regmap_bus,
pll_res, &dsi_pll_10nm_config);
dsi1pll_pclk_src_mux.clkr.regmap = rmap;
-
rmap = devm_regmap_init(&pdev->dev, &mdss_mux_regmap_bus,
pll_res, &dsi_pll_10nm_config);
dsi1pll_byteclk_mux.clkr.regmap = rmap;
diff --git a/drivers/clk/qcom/mdss/mdss-pll.h b/drivers/clk/qcom/mdss/mdss-pll.h
index 033462d..2f92270 100644
--- a/drivers/clk/qcom/mdss/mdss-pll.h
+++ b/drivers/clk/qcom/mdss/mdss-pll.h
@@ -99,6 +99,7 @@
unsigned long vco_cached_rate;
u32 cached_cfg0;
u32 cached_cfg1;
+ u32 cached_outdiv;
/* dsi/edp/hmdi pll interface type */
u32 pll_interface_type;
diff --git a/drivers/cpufreq/cpu-boost.c b/drivers/cpufreq/cpu-boost.c
index 07603fe..e67f12b 100644
--- a/drivers/cpufreq/cpu-boost.c
+++ b/drivers/cpufreq/cpu-boost.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2015,2017, The Linux Foundation. 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 and
@@ -39,8 +39,8 @@
static unsigned int input_boost_ms = 40;
module_param(input_boost_ms, uint, 0644);
-static bool sched_boost_on_input;
-module_param(sched_boost_on_input, bool, 0644);
+static unsigned int sched_boost_on_input;
+module_param(sched_boost_on_input, uint, 0644);
static bool sched_boost_active;
@@ -209,8 +209,8 @@
update_policy_online();
/* Enable scheduler boost to migrate tasks to big cluster */
- if (sched_boost_on_input) {
- ret = sched_set_boost(1);
+ if (sched_boost_on_input > 0) {
+ ret = sched_set_boost(sched_boost_on_input);
if (ret)
pr_err("cpu-boost: HMP boost enable failed\n");
else
diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c
index e11ea50..afca9f4 100644
--- a/drivers/cpuidle/lpm-levels.c
+++ b/drivers/cpuidle/lpm-levels.c
@@ -55,6 +55,7 @@
#define SCLK_HZ (32768)
#define PSCI_POWER_STATE(reset) (reset << 30)
#define PSCI_AFFINITY_LEVEL(lvl) ((lvl & 0x3) << 24)
+#define BIAS_HYST (bias_hyst * NSEC_PER_MSEC)
enum {
MSM_LPM_LVL_DBG_SUSPEND_LIMITS = BIT(0),
@@ -93,6 +94,9 @@
static uint32_t tmr_add = 100;
module_param_named(tmr_add, tmr_add, uint, 0664);
+static uint32_t bias_hyst;
+module_param_named(bias_hyst, bias_hyst, uint, 0664);
+
struct lpm_history {
uint32_t resi[MAXSAMPLES];
int mode[MAXSAMPLES];
@@ -572,6 +576,17 @@
static void update_history(struct cpuidle_device *dev, int idx);
+static inline bool is_cpu_biased(int cpu)
+{
+ u64 now = sched_clock();
+ u64 last = sched_get_cpu_last_busy_time(cpu);
+
+ if (!last)
+ return false;
+
+ return (now - last) < BIAS_HYST;
+}
+
static int cpu_power_select(struct cpuidle_device *dev,
struct lpm_cpu *cpu)
{
@@ -596,6 +611,11 @@
next_event_us = (uint32_t)(ktime_to_us(get_next_event_time(dev->cpu)));
+ if (is_cpu_biased(dev->cpu)) {
+ best_level = 0;
+ goto done_select;
+ }
+
for (i = 0; i < cpu->nlevels; i++) {
struct lpm_cpu_level *level = &cpu->levels[i];
struct power_params *pwr_params = &level->pwr;
@@ -674,6 +694,7 @@
histtimer_start(htime);
}
+done_select:
trace_cpu_power_select(best_level, sleep_us, latency_us, next_event_us);
trace_cpu_pred_select(idx_restrict_time ? 2 : (predicted ? 1 : 0),
@@ -959,6 +980,9 @@
if (suspend_in_progress && from_idle && level->notify_rpm)
continue;
+ if (level->is_reset && !system_sleep_allowed())
+ continue;
+
best_level = i;
if (from_idle &&
@@ -1021,7 +1045,8 @@
clear_predict_history();
clear_cl_predict_history();
- system_sleep_enter(us);
+ if (system_sleep_enter(us))
+ return -EBUSY;
}
/* Notify cluster enter event after successfully config completion */
cluster_notify(cluster, level, true);
@@ -1031,9 +1056,7 @@
if (predicted && (idx < (cluster->nlevels - 1))) {
struct power_params *pwr_params = &cluster->levels[idx].pwr;
- tick_broadcast_exit();
clusttimer_start(cluster, pwr_params->max_residency + tmr_add);
- tick_broadcast_enter();
}
return 0;
@@ -1086,10 +1109,8 @@
struct power_params *pwr_params =
&cluster->levels[0].pwr;
- tick_broadcast_exit();
clusttimer_start(cluster,
pwr_params->max_residency + tmr_add);
- tick_broadcast_enter();
}
}
@@ -1196,9 +1217,6 @@
* next wakeup within a cluster, in which case, CPU switches over to
* use broadcast timer.
*/
- if (from_idle && cpu_level->use_bc_timer)
- tick_broadcast_enter();
-
if (from_idle && ((cpu_level->mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE)
|| (cpu_level->mode ==
MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE)
@@ -1218,9 +1236,6 @@
struct lpm_cpu_level *cpu_level = &cpu->levels[cpu_index];
bool jtag_save_restore = cpu->levels[cpu_index].jtag_save_restore;
- if (from_idle && cpu_level->use_bc_timer)
- tick_broadcast_exit();
-
if (from_idle && ((cpu_level->mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE)
|| (cpu_level->mode ==
MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE)
@@ -1272,6 +1287,11 @@
/*
* idx = 0 is the default LPM state
*/
+ if (from_idle && cpu->levels[idx].use_bc_timer) {
+ if (tick_broadcast_enter())
+ return false;
+ }
+
if (!idx) {
stop_critical_timings();
wfi();
@@ -1290,6 +1310,10 @@
start_critical_timings();
update_debug_pc_event(CPU_EXIT, state_id,
success, 0xdeaffeed, true);
+
+ if (from_idle && cpu->levels[idx].use_bc_timer)
+ tick_broadcast_exit();
+
return success;
}
diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c
index 97e3479..6fcf25f 100644
--- a/drivers/crypto/atmel-sha.c
+++ b/drivers/crypto/atmel-sha.c
@@ -1000,7 +1000,9 @@
ctx->flags |= SHA_FLAGS_FINUP;
err1 = atmel_sha_update(req);
- if (err1 == -EINPROGRESS || err1 == -EBUSY)
+ if (err1 == -EINPROGRESS ||
+ (err1 == -EBUSY && (ahash_request_flags(req) &
+ CRYPTO_TFM_REQ_MAY_BACKLOG)))
return err1;
/*
diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c
index 3bda6e5..0d743c6 100644
--- a/drivers/crypto/caam/caamalg.c
+++ b/drivers/crypto/caam/caamalg.c
@@ -2014,10 +2014,10 @@
{
struct ablkcipher_request *req = context;
struct ablkcipher_edesc *edesc;
-#ifdef DEBUG
struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req);
int ivsize = crypto_ablkcipher_ivsize(ablkcipher);
+#ifdef DEBUG
dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err);
#endif
@@ -2037,6 +2037,14 @@
#endif
ablkcipher_unmap(jrdev, edesc, req);
+
+ /*
+ * The crypto API expects us to set the IV (req->info) to the last
+ * ciphertext block. This is used e.g. by the CTS mode.
+ */
+ scatterwalk_map_and_copy(req->info, req->dst, req->nbytes - ivsize,
+ ivsize, 0);
+
kfree(edesc);
ablkcipher_request_complete(req, err);
@@ -2047,10 +2055,10 @@
{
struct ablkcipher_request *req = context;
struct ablkcipher_edesc *edesc;
-#ifdef DEBUG
struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req);
int ivsize = crypto_ablkcipher_ivsize(ablkcipher);
+#ifdef DEBUG
dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err);
#endif
@@ -2069,6 +2077,14 @@
#endif
ablkcipher_unmap(jrdev, edesc, req);
+
+ /*
+ * The crypto API expects us to set the IV (req->info) to the last
+ * ciphertext block.
+ */
+ scatterwalk_map_and_copy(req->info, req->src, req->nbytes - ivsize,
+ ivsize, 0);
+
kfree(edesc);
ablkcipher_request_complete(req, err);
diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c
index 2474f14..631337c 100644
--- a/drivers/crypto/caam/caamhash.c
+++ b/drivers/crypto/caam/caamhash.c
@@ -491,7 +491,7 @@
ret = caam_jr_enqueue(jrdev, desc, split_key_done, &result);
if (!ret) {
/* in progress */
- wait_for_completion_interruptible(&result.completion);
+ wait_for_completion(&result.completion);
ret = result.err;
#ifdef DEBUG
print_hex_dump(KERN_ERR,
diff --git a/drivers/crypto/caam/key_gen.c b/drivers/crypto/caam/key_gen.c
index e1eaf4f..3ce1d5c 100644
--- a/drivers/crypto/caam/key_gen.c
+++ b/drivers/crypto/caam/key_gen.c
@@ -103,7 +103,7 @@
ret = caam_jr_enqueue(jrdev, desc, split_key_done, &result);
if (!ret) {
/* in progress */
- wait_for_completion_interruptible(&result.completion);
+ wait_for_completion(&result.completion);
ret = result.err;
#ifdef DEBUG
print_hex_dump(KERN_ERR, "ctx.key@"__stringify(__LINE__)": ",
diff --git a/drivers/crypto/msm/compat_qcedev.c b/drivers/crypto/msm/compat_qcedev.c
index 0ca28be..d61b6f3 100644
--- a/drivers/crypto/msm/compat_qcedev.c
+++ b/drivers/crypto/msm/compat_qcedev.c
@@ -96,7 +96,6 @@
for (i = 0; i < QCEDEV_MAX_BUFFERS; i++) {
err |= get_user(vaddr, &vbuf32->src[i].vaddr);
- vbuf->src[i].vaddr = NULL;
err |= put_user(vaddr, (compat_uptr_t *)&vbuf->src[i].vaddr);
err |= get_user(len, &vbuf32->src[i].len);
err |= put_user(len, &vbuf->src[i].len);
@@ -104,7 +103,6 @@
for (i = 0; i < QCEDEV_MAX_BUFFERS; i++) {
err |= get_user(vaddr, &vbuf32->dst[i].vaddr);
- vbuf->dst[i].vaddr = NULL;
err |= put_user(vaddr, (compat_uptr_t *)&vbuf->dst[i].vaddr);
err |= get_user(len, &vbuf32->dst[i].len);
err |= put_user(len, &vbuf->dst[i].len);
@@ -122,7 +120,6 @@
for (i = 0; i < QCEDEV_MAX_BUFFERS; i++) {
err |= get_user(vaddr, (compat_uptr_t *)&vbuf->src[i].vaddr);
- vbuf32->src[i].vaddr = 0;
err |= put_user(vaddr, &vbuf32->src[i].vaddr);
err |= get_user(len, &vbuf->src[i].len);
err |= put_user(len, &vbuf32->src[i].len);
@@ -130,7 +127,6 @@
for (i = 0; i < QCEDEV_MAX_BUFFERS; i++) {
err |= get_user(vaddr, (compat_uptr_t *)&vbuf->dst[i].vaddr);
- vbuf32->dst[i].vaddr = 0;
err |= put_user(vaddr, &vbuf32->dst[i].vaddr);
err |= get_user(len, &vbuf->dst[i].len);
err |= put_user(len, &vbuf32->dst[i].len);
@@ -275,7 +271,6 @@
for (i = 0; i < QCEDEV_MAX_BUFFERS; i++) {
err |= get_user(vaddr, &data32->data[i].vaddr);
- data->data[i].vaddr = 0;
err |= put_user(vaddr, (compat_uptr_t *)&data->data[i].vaddr);
err |= get_user(len, &data32->data[i].len);
err |= put_user(len, &data->data[i].len);
@@ -294,7 +289,6 @@
err |= get_user(diglen, &data32->diglen);
err |= put_user(diglen, &data->diglen);
err |= get_user(authkey, &data32->authkey);
- data->authkey = NULL;
err |= put_user(authkey, (compat_uptr_t *)&data->authkey);
err |= get_user(authklen, &data32->authklen);
err |= put_user(authklen, &data->authklen);
@@ -321,7 +315,6 @@
for (i = 0; i < QCEDEV_MAX_BUFFERS; i++) {
err |= get_user(vaddr, (compat_uptr_t *)&data->data[i].vaddr);
- data32->data[i].vaddr = 0;
err |= put_user(vaddr, &data32->data[i].vaddr);
err |= get_user(len, &data->data[i].len);
err |= put_user(len, &data32->data[i].len);
@@ -340,7 +333,6 @@
err |= get_user(diglen, &data->diglen);
err |= put_user(diglen, &data32->diglen);
err |= get_user(authkey, (compat_uptr_t *)&data->authkey);
- data32->authkey = 0;
err |= put_user(authkey, &data32->authkey);
err |= get_user(authklen, &data->authklen);
err |= put_user(authklen, &data32->authklen);
diff --git a/drivers/crypto/msm/ice.c b/drivers/crypto/msm/ice.c
index b411726..6ed82ef 100644
--- a/drivers/crypto/msm/ice.c
+++ b/drivers/crypto/msm/ice.c
@@ -459,7 +459,7 @@
(ICE_REV(ice_dev->ice_hw_version, MINOR) >= 1))) {
reg = qcom_ice_readl(ice_dev, QCOM_ICE_REGS_BYPASS_STATUS);
if ((reg & 0x80000000) != 0x0) {
- pr_err("%s: Bypass failed for ice = %p",
+ pr_err("%s: Bypass failed for ice = %pK",
__func__, (void *)ice_dev);
WARN_ON(1);
}
@@ -485,7 +485,7 @@
}
ice_dev->ice_hw_version = rev;
- dev_info(ice_dev->pdev, "QC ICE %d.%d.%d device found @0x%p\n",
+ dev_info(ice_dev->pdev, "QC ICE %d.%d.%d device found @0x%pK\n",
maj_rev, min_rev, step_rev,
ice_dev->mmio);
@@ -1275,7 +1275,7 @@
goto out;
}
- pr_err("%s: =========== REGISTER DUMP (%p)===========\n",
+ pr_err("%s: =========== REGISTER DUMP (%pK)===========\n",
ice_dev->ice_instance_type, ice_dev);
pr_err("%s: ICE Control: 0x%08x | ICE Reset: 0x%08x\n",
@@ -1589,7 +1589,7 @@
struct ice_device *ice_dev = NULL;
if (!node) {
- pr_err("%s: invalid node %p", __func__, node);
+ pr_err("%s: invalid node %pK", __func__, node);
goto out;
}
@@ -1606,13 +1606,14 @@
list_for_each_entry(ice_dev, &ice_devices, list) {
if (ice_dev->pdev->of_node == node) {
- pr_info("%s: found ice device %p\n", __func__, ice_dev);
+ pr_info("%s: found ice device %pK\n", __func__,
+ ice_dev);
break;
}
}
ice_pdev = to_platform_device(ice_dev->pdev);
- pr_info("%s: matching platform device %p\n", __func__, ice_pdev);
+ pr_info("%s: matching platform device %pK\n", __func__, ice_pdev);
out:
return ice_pdev;
}
@@ -1650,7 +1651,7 @@
}
ret = regulator_enable(ice_dev->reg);
if (ret) {
- pr_err("%s:%p: Could not enable regulator\n",
+ pr_err("%s:%pK: Could not enable regulator\n",
__func__, ice_dev);
goto out;
}
@@ -1658,7 +1659,7 @@
/* Setup Clocks */
if (qcom_ice_enable_clocks(ice_dev, true)) {
- pr_err("%s:%p:%s Could not enable clocks\n", __func__,
+ pr_err("%s:%pK:%s Could not enable clocks\n", __func__,
ice_dev, ice_dev->ice_instance_type);
goto out_reg;
}
@@ -1670,7 +1671,7 @@
ret = qcom_ice_set_bus_vote(ice_dev, vote);
if (ret) {
- pr_err("%s:%p: failed %d\n", __func__, ice_dev, ret);
+ pr_err("%s:%pK: failed %d\n", __func__, ice_dev, ret);
goto out_clocks;
}
@@ -1702,19 +1703,19 @@
/* Setup Bus Vote */
vote = qcom_ice_get_bus_vote(ice_dev, "MIN");
if (vote < 0) {
- pr_err("%s:%p: Unable to get bus vote\n", __func__, ice_dev);
+ pr_err("%s:%pK: Unable to get bus vote\n", __func__, ice_dev);
goto out_disable_clocks;
}
ret = qcom_ice_set_bus_vote(ice_dev, vote);
if (ret)
- pr_err("%s:%p: failed %d\n", __func__, ice_dev, ret);
+ pr_err("%s:%pK: failed %d\n", __func__, ice_dev, ret);
out_disable_clocks:
/* Setup Clocks */
if (qcom_ice_enable_clocks(ice_dev, false))
- pr_err("%s:%p:%s Could not disable clocks\n", __func__,
+ pr_err("%s:%pK:%s Could not disable clocks\n", __func__,
ice_dev, ice_dev->ice_instance_type);
/* Setup Regulator */
@@ -1725,7 +1726,7 @@
}
ret = regulator_disable(ice_dev->reg);
if (ret) {
- pr_err("%s:%p: Could not disable regulator\n",
+ pr_err("%s:%pK: Could not disable regulator\n",
__func__, ice_dev);
goto out;
}
diff --git a/drivers/crypto/msm/ota_crypto.c b/drivers/crypto/msm/ota_crypto.c
index 3a2a51d..d477815 100644
--- a/drivers/crypto/msm/ota_crypto.c
+++ b/drivers/crypto/msm/ota_crypto.c
@@ -172,7 +172,7 @@
podev = file->private_data;
if (podev != NULL && podev->magic != OTA_MAGIC) {
- pr_err("%s: invalid handle %p\n",
+ pr_err("%s: invalid handle %pK\n",
__func__, podev);
}
@@ -440,7 +440,7 @@
podev = file->private_data;
if (podev == NULL || podev->magic != OTA_MAGIC) {
- pr_err("%s: invalid handle %p\n",
+ pr_err("%s: invalid handle %pK\n",
__func__, podev);
return -ENOENT;
}
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index d9ebe113..35d7542 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -33,12 +33,17 @@
#include <crypto/hash.h>
#include <crypto/sha.h>
#include <soc/qcom/socinfo.h>
+#include <asm/dma-iommu.h>
+#include <linux/iommu.h>
#include "qce.h"
#include "qce50.h"
#include "qcryptohw_50.h"
#include "qce_ota.h"
+#define CRYPTO_SMMU_IOVA_START 0x10000000
+#define CRYPTO_SMMU_IOVA_SIZE 0x40000000
+
#define CRYPTO_CONFIG_RESET 0xE01EF
#define MAX_SPS_DESC_FIFO_SIZE 0xfff0
#define QCE_MAX_NUM_DSCR 0x200
@@ -156,6 +161,8 @@
atomic_t last_intr_seq;
bool cadence_flag;
uint8_t *dummyreq_in_buf;
+ struct dma_iommu_mapping *smmu_mapping;
+ bool bypass_s1_smmu;
};
static void print_notify_debug(struct sps_event_notify *notify);
@@ -1157,7 +1164,7 @@
#define QCE_WRITE_REG(val, addr) \
{ \
- pr_info(" [0x%p] 0x%x\n", addr, (uint32_t)val); \
+ pr_info(" [0x%pK] 0x%x\n", addr, (uint32_t)val); \
writel_relaxed(val, addr); \
}
@@ -2153,6 +2160,10 @@
pce_sps_data = &preq_info->ce_sps;
qce_callback = preq_info->qce_cb;
areq = (struct ahash_request *) preq_info->areq;
+ if (!areq) {
+ pr_err("sha operation error. areq is NULL\n");
+ return -ENXIO;
+ }
qce_dma_unmap_sg(pce_dev->pdev, areq->src, preq_info->src_nents,
DMA_TO_DEVICE);
memcpy(digest, (char *)(&pce_sps_data->result->auth_iv[0]),
@@ -2728,7 +2739,7 @@
sps_event->callback = NULL;
}
- pr_debug("success, %s : pipe_handle=0x%lx, desc fifo base (phy) = 0x%p\n",
+ pr_debug("success, %s : pipe_handle=0x%lx, desc fifo base (phy) = 0x%pK\n",
is_producer ? "PRODUCER(RX/OUT)" : "CONSUMER(TX/IN)",
(uintptr_t)sps_pipe_info, &sps_connect_info->desc.phys_base);
goto out;
@@ -2890,7 +2901,7 @@
bam.ipc_loglevel = QCE_BAM_DEFAULT_IPC_LOGLVL;
bam.options |= SPS_BAM_CACHED_WP;
pr_debug("bam physical base=0x%lx\n", (uintptr_t)bam.phys_addr);
- pr_debug("bam virtual base=0x%p\n", bam.virt_addr);
+ pr_debug("bam virtual base=0x%pK\n", bam.virt_addr);
/* Register CE Peripheral BAM device to SPS driver */
rc = sps_register_bam_device(&bam, &pbam->handle);
@@ -2965,7 +2976,7 @@
request_index++;
if (request_index >= MAX_QCE_BAM_REQ)
request_index = 0;
- if (xchg(&pce_dev->ce_request_info[request_index].
+ if (atomic_xchg(&pce_dev->ce_request_info[request_index].
in_use, true) == false) {
pce_dev->ce_request_index = request_index;
return request_index;
@@ -2981,7 +2992,8 @@
bool is_complete)
{
pce_dev->ce_request_info[req_info].xfer_type = QCE_XFER_TYPE_LAST;
- if (xchg(&pce_dev->ce_request_info[req_info].in_use, false) == true) {
+ if (atomic_xchg(&pce_dev->ce_request_info[req_info].in_use,
+ false) == true) {
if (req_info < MAX_QCE_BAM_REQ && is_complete)
atomic_dec(&pce_dev->no_of_queued_req);
} else
@@ -2993,7 +3005,7 @@
phys_addr_t addr =
DESC_FULL_ADDR((phys_addr_t) notify->data.transfer.iovec.flags,
notify->data.transfer.iovec.addr);
- pr_debug("sps ev_id=%d, addr=0x%pa, size=0x%x, flags=0x%x user=0x%p\n",
+ pr_debug("sps ev_id=%d, addr=0x%pa, size=0x%x, flags=0x%x user=0x%pK\n",
notify->event_id, &addr,
notify->data.transfer.iovec.size,
notify->data.transfer.iovec.flags,
@@ -4605,7 +4617,7 @@
{
int ret = 0;
- if (!(xchg(&pce_dev->ce_request_info[DUMMY_REQ_INDEX].
+ if (!(atomic_xchg(&pce_dev->ce_request_info[DUMMY_REQ_INDEX].
in_use, true) == false))
return -EBUSY;
ret = qce_process_sha_req(pce_dev, NULL);
@@ -5703,6 +5715,10 @@
pr_info("CE operating frequency is not defined, setting to default 100MHZ\n");
pce_dev->ce_opp_freq_hz = CE_CLK_100MHZ;
}
+
+ if (of_property_read_bool((&pdev->dev)->of_node, "qcom,smmu-s1-bypass"))
+ pce_dev->bypass_s1_smmu = true;
+
pce_dev->ce_bam_info.dest_pipe_index =
2 * pce_dev->ce_bam_info.pipe_pair_index;
pce_dev->ce_bam_info.src_pipe_index =
@@ -5936,6 +5952,48 @@
return 0;
}
+static void qce_iommu_release_iomapping(struct qce_device *pce_dev)
+{
+ if (pce_dev->smmu_mapping)
+ arm_iommu_release_mapping(pce_dev->smmu_mapping);
+
+ pce_dev->smmu_mapping = NULL;
+}
+
+static int qce_smmu_init(struct qce_device *pce_dev)
+{
+ struct dma_iommu_mapping *mapping;
+ int s1_bypass = 1;
+ int ret = 0;
+
+ mapping = arm_iommu_create_mapping(&platform_bus_type,
+ CRYPTO_SMMU_IOVA_START, CRYPTO_SMMU_IOVA_SIZE);
+ if (IS_ERR(mapping)) {
+ ret = PTR_ERR(mapping);
+ pr_err("Create mapping failed, err = %d\n", ret);
+ return ret;
+ }
+
+ ret = iommu_domain_set_attr(mapping->domain,
+ DOMAIN_ATTR_S1_BYPASS, &s1_bypass);
+ if (ret < 0) {
+ pr_err("Set s1_bypass attribute failed, err = %d\n", ret);
+ goto ext_fail_set_attr;
+ }
+
+ ret = arm_iommu_attach_device(pce_dev->pdev, mapping);
+ if (ret < 0) {
+ pr_err("Attach device failed, err = %d\n", ret);
+ goto ext_fail_set_attr;
+ }
+ pce_dev->smmu_mapping = mapping;
+ return ret;
+
+ext_fail_set_attr:
+ qce_iommu_release_iomapping(pce_dev);
+ return ret;
+}
+
/* crypto engine open function. */
void *qce_open(struct platform_device *pdev, int *rc)
{
@@ -5963,7 +6021,7 @@
}
for (i = 0; i < MAX_QCE_ALLOC_BAM_REQ; i++)
- pce_dev->ce_request_info[i].in_use = false;
+ atomic_set(&pce_dev->ce_request_info[i].in_use, false);
pce_dev->ce_request_index = 0;
pce_dev->memsize = 10 * PAGE_SIZE * MAX_QCE_ALLOC_BAM_REQ;
@@ -5993,6 +6051,13 @@
if (*rc)
goto err_enable_clk;
+ if (pce_dev->bypass_s1_smmu) {
+ if (qce_smmu_init(pce_dev)) {
+ *rc = -EIO;
+ goto err_smmu;
+ }
+ }
+
if (_probe_ce_engine(pce_dev)) {
*rc = -ENXIO;
goto err;
@@ -6019,6 +6084,9 @@
mutex_unlock(&qce_iomap_mutex);
return pce_dev;
err:
+ if (pce_dev->bypass_s1_smmu)
+ qce_iommu_release_iomapping(pce_dev);
+err_smmu:
qce_disable_clk(pce_dev);
err_enable_clk:
@@ -6060,6 +6128,9 @@
kfree(pce_dev->dummyreq_in_buf);
kfree(pce_dev->iovec_vmem);
+ if (pce_dev->bypass_s1_smmu)
+ qce_iommu_release_iomapping(pce_dev);
+
qce_disable_clk(pce_dev);
__qce_deinit_clk(pce_dev);
mutex_unlock(&qce_iomap_mutex);
@@ -6128,12 +6199,13 @@
void qce_dump_req(void *handle)
{
int i;
+ bool req_in_use;
struct qce_device *pce_dev = (struct qce_device *)handle;
for (i = 0; i < MAX_QCE_BAM_REQ; i++) {
- pr_info("qce_dump_req %d %d\n", i,
- pce_dev->ce_request_info[i].in_use);
- if (pce_dev->ce_request_info[i].in_use == true)
+ req_in_use = atomic_read(&pce_dev->ce_request_info[i].in_use);
+ pr_info("qce_dump_req %d %d\n", i, req_in_use);
+ if (req_in_use == true)
_qce_dump_descr_fifos(pce_dev, i);
}
}
diff --git a/drivers/crypto/msm/qce50.h b/drivers/crypto/msm/qce50.h
index 0e60bd2..ab0d21d 100644
--- a/drivers/crypto/msm/qce50.h
+++ b/drivers/crypto/msm/qce50.h
@@ -214,7 +214,7 @@
};
struct ce_request_info {
- bool in_use;
+ atomic_t in_use;
bool in_prog;
enum qce_xfer_type_enum xfer_type;
struct ce_sps_data ce_sps;
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index 5d6e0c2..2cf303e 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -57,6 +57,7 @@
static DEFINE_MUTEX(send_cmd_lock);
static DEFINE_MUTEX(qcedev_sent_bw_req);
+static DEFINE_MUTEX(hash_access_lock);
static int qcedev_control_clocks(struct qcedev_control *podev, bool enable)
{
@@ -269,7 +270,7 @@
handle = file->private_data;
podev = handle->cntl;
if (podev != NULL && podev->magic != QCEDEV_MAGIC) {
- pr_err("%s: invalid handle %p\n",
+ pr_err("%s: invalid handle %pK\n",
__func__, podev);
}
kzfree(handle);
@@ -1657,7 +1658,7 @@
podev = handle->cntl;
qcedev_areq.handle = handle;
if (podev == NULL || podev->magic != QCEDEV_MAGIC) {
- pr_err("%s: invalid handle %p\n",
+ pr_err("%s: invalid handle %pK\n",
__func__, podev);
return -ENOENT;
}
@@ -1699,12 +1700,18 @@
(void __user *)arg,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
- if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev))
+ mutex_lock(&hash_access_lock);
+ if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev)) {
+ mutex_unlock(&hash_access_lock);
return -EINVAL;
+ }
qcedev_areq.op_type = QCEDEV_CRYPTO_OPER_SHA;
err = qcedev_hash_init(&qcedev_areq, handle, &sg_src);
- if (err)
+ if (err) {
+ mutex_unlock(&hash_access_lock);
return err;
+ }
+ mutex_unlock(&hash_access_lock);
if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
@@ -1722,32 +1729,42 @@
(void __user *)arg,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
- if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev))
+ mutex_lock(&hash_access_lock);
+ if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev)) {
+ mutex_unlock(&hash_access_lock);
return -EINVAL;
+ }
qcedev_areq.op_type = QCEDEV_CRYPTO_OPER_SHA;
if (qcedev_areq.sha_op_req.alg == QCEDEV_ALG_AES_CMAC) {
err = qcedev_hash_cmac(&qcedev_areq, handle, &sg_src);
- if (err)
+ if (err) {
+ mutex_unlock(&hash_access_lock);
return err;
+ }
} else {
if (handle->sha_ctxt.init_done == false) {
pr_err("%s Init was not called\n", __func__);
+ mutex_unlock(&hash_access_lock);
return -EINVAL;
}
err = qcedev_hash_update(&qcedev_areq, handle, &sg_src);
- if (err)
+ if (err) {
+ mutex_unlock(&hash_access_lock);
return err;
+ }
}
if (handle->sha_ctxt.diglen > QCEDEV_MAX_SHA_DIGEST) {
pr_err("Invalid sha_ctxt.diglen %d\n",
handle->sha_ctxt.diglen);
+ mutex_unlock(&hash_access_lock);
return -EINVAL;
}
memcpy(&qcedev_areq.sha_op_req.digest[0],
&handle->sha_ctxt.digest[0],
handle->sha_ctxt.diglen);
+ mutex_unlock(&hash_access_lock);
if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
@@ -1764,16 +1781,28 @@
(void __user *)arg,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
- if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev))
+ mutex_lock(&hash_access_lock);
+ if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev)) {
+ mutex_unlock(&hash_access_lock);
return -EINVAL;
+ }
qcedev_areq.op_type = QCEDEV_CRYPTO_OPER_SHA;
err = qcedev_hash_final(&qcedev_areq, handle);
- if (err)
+ if (err) {
+ mutex_unlock(&hash_access_lock);
return err;
+ }
+ if (handle->sha_ctxt.diglen > QCEDEV_MAX_SHA_DIGEST) {
+ pr_err("Invalid sha_ctxt.diglen %d\n",
+ handle->sha_ctxt.diglen);
+ mutex_unlock(&hash_access_lock);
+ return -EINVAL;
+ }
qcedev_areq.sha_op_req.diglen = handle->sha_ctxt.diglen;
memcpy(&qcedev_areq.sha_op_req.digest[0],
&handle->sha_ctxt.digest[0],
handle->sha_ctxt.diglen);
+ mutex_unlock(&hash_access_lock);
if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
@@ -1788,20 +1817,34 @@
(void __user *)arg,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
- if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev))
+ mutex_lock(&hash_access_lock);
+ if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev)) {
+ mutex_unlock(&hash_access_lock);
return -EINVAL;
+ }
qcedev_areq.op_type = QCEDEV_CRYPTO_OPER_SHA;
qcedev_hash_init(&qcedev_areq, handle, &sg_src);
err = qcedev_hash_update(&qcedev_areq, handle, &sg_src);
- if (err)
+ if (err) {
+ mutex_unlock(&hash_access_lock);
return err;
+ }
err = qcedev_hash_final(&qcedev_areq, handle);
- if (err)
+ if (err) {
+ mutex_unlock(&hash_access_lock);
return err;
+ }
+ if (handle->sha_ctxt.diglen > QCEDEV_MAX_SHA_DIGEST) {
+ pr_err("Invalid sha_ctxt.diglen %d\n",
+ handle->sha_ctxt.diglen);
+ mutex_unlock(&hash_access_lock);
+ return -EINVAL;
+ }
qcedev_areq.sha_op_req.diglen = handle->sha_ctxt.diglen;
memcpy(&qcedev_areq.sha_op_req.digest[0],
&handle->sha_ctxt.digest[0],
handle->sha_ctxt.diglen);
+ mutex_unlock(&hash_access_lock);
if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index b979fb9..b3269a6 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -265,7 +265,7 @@
preq->arsp = NULL;
/* free req */
if (xchg(&preq->in_use, false) == false)
- pr_warn("request info %p free already\n", preq);
+ pr_warn("request info %pK free already\n", preq);
else
atomic_dec(&pce->req_count);
}
@@ -1759,7 +1759,7 @@
}
#ifdef QCRYPTO_DEBUG
- dev_info(&pengine->pdev->dev, "_qce_ahash_complete: %p ret %d\n",
+ dev_info(&pengine->pdev->dev, "_qce_ahash_complete: %pK ret %d\n",
areq, ret);
#endif
if (digest) {
@@ -1818,7 +1818,7 @@
}
#ifdef QCRYPTO_DEBUG
- dev_info(&pengine->pdev->dev, "_qce_ablk_cipher_complete: %p ret %d\n",
+ dev_info(&pengine->pdev->dev, "_qce_ablk_cipher_complete: %pK ret %d\n",
areq, ret);
#endif
if (iv)
@@ -2520,7 +2520,7 @@
WARN_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
#ifdef QCRYPTO_DEBUG
- dev_info(&ctx->pengine->pdev->dev, "_qcrypto_enc_aes_ecb: %p\n", req);
+ dev_info(&ctx->pengine->pdev->dev, "_qcrypto_enc_aes_ecb: %pK\n", req);
#endif
if ((ctx->enc_key_len == AES_KEYSIZE_192) &&
@@ -2550,7 +2550,7 @@
WARN_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
#ifdef QCRYPTO_DEBUG
- dev_info(&ctx->pengine->pdev->dev, "_qcrypto_enc_aes_cbc: %p\n", req);
+ dev_info(&ctx->pengine->pdev->dev, "_qcrypto_enc_aes_cbc: %pK\n", req);
#endif
if ((ctx->enc_key_len == AES_KEYSIZE_192) &&
@@ -2580,7 +2580,7 @@
WARN_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
#ifdef QCRYPTO_DEBUG
- dev_info(&ctx->pengine->pdev->dev, "_qcrypto_enc_aes_ctr: %p\n", req);
+ dev_info(&ctx->pengine->pdev->dev, "_qcrypto_enc_aes_ctr: %pK\n", req);
#endif
if ((ctx->enc_key_len == AES_KEYSIZE_192) &&
@@ -2768,7 +2768,7 @@
WARN_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
#ifdef QCRYPTO_DEBUG
- dev_info(&ctx->pengine->pdev->dev, "_qcrypto_dec_aes_ecb: %p\n", req);
+ dev_info(&ctx->pengine->pdev->dev, "_qcrypto_dec_aes_ecb: %pK\n", req);
#endif
if ((ctx->enc_key_len == AES_KEYSIZE_192) &&
@@ -2798,7 +2798,7 @@
WARN_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
#ifdef QCRYPTO_DEBUG
- dev_info(&ctx->pengine->pdev->dev, "_qcrypto_dec_aes_cbc: %p\n", req);
+ dev_info(&ctx->pengine->pdev->dev, "_qcrypto_dec_aes_cbc: %pK\n", req);
#endif
if ((ctx->enc_key_len == AES_KEYSIZE_192) &&
@@ -2828,7 +2828,7 @@
WARN_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
#ifdef QCRYPTO_DEBUG
- dev_info(&ctx->pengine->pdev->dev, "_qcrypto_dec_aes_ctr: %p\n", req);
+ dev_info(&ctx->pengine->pdev->dev, "_qcrypto_dec_aes_ctr: %pK\n", req);
#endif
if ((ctx->enc_key_len == AES_KEYSIZE_192) &&
@@ -3394,7 +3394,7 @@
#ifdef QCRYPTO_DEBUG
dev_info(&ctx->pengine->pdev->dev,
- "_qcrypto_aead_encrypt_aes_cbc: %p\n", req);
+ "_qcrypto_aead_encrypt_aes_cbc: %pK\n", req);
#endif
rctx = aead_request_ctx(req);
@@ -3425,7 +3425,7 @@
#ifdef QCRYPTO_DEBUG
dev_info(&ctx->pengine->pdev->dev,
- "_qcrypto_aead_decrypt_aes_cbc: %p\n", req);
+ "_qcrypto_aead_decrypt_aes_cbc: %pK\n", req);
#endif
rctx = aead_request_ctx(req);
rctx->aead = 1;
@@ -4011,7 +4011,7 @@
unsigned int len)
{
struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(&tfm->base);
-
+ int ret = 0;
memset(&sha_ctx->authkey[0], 0, SHA1_BLOCK_SIZE);
if (len <= SHA1_BLOCK_SIZE) {
memcpy(&sha_ctx->authkey[0], key, len);
@@ -4019,16 +4019,19 @@
} else {
sha_ctx->alg = QCE_HASH_SHA1;
sha_ctx->diglen = SHA1_DIGEST_SIZE;
- _sha_hmac_setkey(tfm, key, len);
+ ret = _sha_hmac_setkey(tfm, key, len);
+ if (ret)
+ pr_err("SHA1 hmac setkey failed\n");
sha_ctx->authkey_in_len = SHA1_BLOCK_SIZE;
}
- return 0;
+ return ret;
}
static int _sha256_hmac_setkey(struct crypto_ahash *tfm, const u8 *key,
unsigned int len)
{
struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(&tfm->base);
+ int ret = 0;
memset(&sha_ctx->authkey[0], 0, SHA256_BLOCK_SIZE);
if (len <= SHA256_BLOCK_SIZE) {
@@ -4037,11 +4040,13 @@
} else {
sha_ctx->alg = QCE_HASH_SHA256;
sha_ctx->diglen = SHA256_DIGEST_SIZE;
- _sha_hmac_setkey(tfm, key, len);
+ ret = _sha_hmac_setkey(tfm, key, len);
+ if (ret)
+ pr_err("SHA256 hmac setkey failed\n");
sha_ctx->authkey_in_len = SHA256_BLOCK_SIZE;
}
- return 0;
+ return ret;
}
static int _sha_hmac_init_ihash(struct ahash_request *req,
diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
index 0418a2f..571de2f 100644
--- a/drivers/crypto/talitos.c
+++ b/drivers/crypto/talitos.c
@@ -816,7 +816,7 @@
* HMAC_SNOOP_NO_AFEA (HSNA) instead of type IPSEC_ESP
*/
#define TALITOS_CRA_PRIORITY_AEAD_HSNA (TALITOS_CRA_PRIORITY - 1)
-#define TALITOS_MAX_KEY_SIZE 96
+#define TALITOS_MAX_KEY_SIZE (AES_MAX_KEY_SIZE + SHA512_BLOCK_SIZE)
#define TALITOS_MAX_IV_LENGTH 16 /* max of AES_BLOCK_SIZE, DES3_EDE_BLOCK_SIZE */
struct talitos_ctx {
@@ -1495,6 +1495,11 @@
{
struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+ if (keylen > TALITOS_MAX_KEY_SIZE) {
+ crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN);
+ return -EINVAL;
+ }
+
memcpy(&ctx->key, key, keylen);
ctx->keylen = keylen;
diff --git a/drivers/edac/kryo3xx_arm64_edac.c b/drivers/edac/kryo3xx_arm64_edac.c
index f5bb3ed..5ca93a6 100644
--- a/drivers/edac/kryo3xx_arm64_edac.c
+++ b/drivers/edac/kryo3xx_arm64_edac.c
@@ -16,6 +16,7 @@
#include <linux/platform_device.h>
#include <linux/smp.h>
#include <linux/cpu.h>
+#include <linux/cpu_pm.h>
#include <linux/interrupt.h>
#include <linux/of_irq.h>
@@ -125,6 +126,7 @@
struct erp_drvdata {
struct edac_device_ctl_info *edev_ctl;
struct erp_drvdata __percpu **erp_cpu_drvdata;
+ struct notifier_block nb_pm;
int ppi;
};
@@ -358,6 +360,19 @@
return IRQ_HANDLED;
}
+static int kryo3xx_pmu_cpu_pm_notify(struct notifier_block *self,
+ unsigned long action, void *v)
+{
+ switch (action) {
+ case CPU_PM_EXIT:
+ kryo3xx_check_l3_scu_error(panic_handler_drvdata->edev_ctl);
+ kryo3xx_check_l1_l2_ecc(panic_handler_drvdata->edev_ctl);
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
static void initialize_registers(void *info)
{
set_errxctlr_el1();
@@ -400,6 +415,7 @@
drv->edev_ctl->ctl_name = "cache";
drv->edev_ctl->panic_on_ce = ARM64_ERP_PANIC_ON_CE;
drv->edev_ctl->panic_on_ue = ARM64_ERP_PANIC_ON_UE;
+ drv->nb_pm.notifier_call = kryo3xx_pmu_cpu_pm_notify;
platform_set_drvdata(pdev, drv);
rc = edac_device_add_device(drv->edev_ctl);
@@ -424,6 +440,8 @@
goto out_dev;
}
+ cpu_pm_register_notifier(&(drv->nb_pm));
+
return 0;
out_dev:
diff --git a/drivers/edac/qcom_llcc_edac.c b/drivers/edac/qcom_llcc_edac.c
index a8ec359..4b89cbf 100644
--- a/drivers/edac/qcom_llcc_edac.c
+++ b/drivers/edac/qcom_llcc_edac.c
@@ -291,7 +291,7 @@
qcom_llcc_clear_errors(err_type, drv);
- errors[err_type].func(edev_ctl, 0, 0, errors[err_type].msg);
+ errors[err_type].func(edev_ctl, 0, bank, errors[err_type].msg);
}
static void qcom_llcc_check_cache_errors
@@ -353,10 +353,26 @@
struct erp_drvdata *drv;
struct edac_device_ctl_info *edev_ctl;
struct device *dev = &pdev->dev;
+ u32 num_banks;
+ struct regmap *llcc_map = NULL;
+
+ llcc_map = syscon_node_to_regmap(dev->parent->of_node);
+ if (IS_ERR(llcc_map)) {
+ dev_err(dev, "no regmap for syscon llcc parent\n");
+ return -ENOMEM;
+ }
+
+ /* Find the number of LLC banks supported */
+ regmap_read(llcc_map, LLCC_COMMON_STATUS0,
+ &num_banks);
+
+ num_banks &= LLCC_LB_CNT_MASK;
+ num_banks >>= LLCC_LB_CNT_SHIFT;
/* Allocate edac control info */
edev_ctl = edac_device_alloc_ctl_info(sizeof(*drv), "qcom-llcc", 1,
- NULL, 0, 1, NULL, 0, edac_device_alloc_index());
+ "bank", num_banks, 1, NULL, 0,
+ edac_device_alloc_index());
if (!edev_ctl)
return -ENOMEM;
@@ -374,64 +390,59 @@
edev_ctl->panic_on_ue = LLCC_ERP_PANIC_ON_UE;
drv = edev_ctl->pvt_info;
+ drv->num_banks = num_banks;
+ drv->llcc_map = llcc_map;
- drv->llcc_map = syscon_node_to_regmap(dev->parent->of_node);
- if (IS_ERR(drv->llcc_map)) {
- dev_err(dev, "no regmap for syscon llcc parent\n");
- rc = -ENOMEM;
- goto out;
- }
+ rc = edac_device_add_device(edev_ctl);
+ if (rc)
+ goto out_mem;
if (interrupt_mode) {
drv->ecc_irq = platform_get_irq_byname(pdev, "ecc_irq");
if (!drv->ecc_irq) {
rc = -ENODEV;
- goto out;
+ goto out_dev;
}
rc = devm_request_irq(dev, drv->ecc_irq, llcc_ecc_irq_handler,
IRQF_TRIGGER_HIGH, "llcc_ecc", edev_ctl);
if (rc) {
dev_err(dev, "failed to request ecc irq\n");
- goto out;
+ goto out_dev;
}
}
- /* Find the number of LLC banks supported */
- regmap_read(drv->llcc_map, LLCC_COMMON_STATUS0,
- &drv->num_banks);
-
- drv->num_banks &= LLCC_LB_CNT_MASK;
- drv->num_banks >>= LLCC_LB_CNT_SHIFT;
-
drv->llcc_banks = devm_kzalloc(&pdev->dev,
sizeof(u32) * drv->num_banks, GFP_KERNEL);
if (!drv->llcc_banks) {
dev_err(dev, "Cannot allocate memory for llcc_banks\n");
- return -ENOMEM;
+ rc = -ENOMEM;
+ goto out_dev;
}
rc = of_property_read_u32_array(dev->parent->of_node,
"qcom,llcc-banks-off", drv->llcc_banks, drv->num_banks);
if (rc) {
dev_err(dev, "Cannot read llcc-banks-off property\n");
- return -EINVAL;
+ goto out_dev;
}
rc = of_property_read_u32(dev->parent->of_node,
"qcom,llcc-broadcast-off", &drv->b_off);
if (rc) {
dev_err(dev, "Cannot read llcc-broadcast-off property\n");
- return -EINVAL;
+ goto out_dev;
}
platform_set_drvdata(pdev, edev_ctl);
- rc = edac_device_add_device(edev_ctl);
-out:
- if (rc)
- edac_device_free_ctl_info(edev_ctl);
+ return 0;
+
+out_dev:
+ edac_device_del_device(edev_ctl->dev);
+out_mem:
+ edac_device_free_ctl_info(edev_ctl);
return rc;
}
diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile
index 5e23e2d..f9a1e98 100644
--- a/drivers/firmware/efi/libstub/Makefile
+++ b/drivers/firmware/efi/libstub/Makefile
@@ -17,6 +17,7 @@
cflags-$(CONFIG_EFI_ARMSTUB) += -I$(srctree)/scripts/dtc/libfdt
KBUILD_CFLAGS := $(cflags-y) -DDISABLE_BRANCH_PROFILING \
+ -D__NO_FORTIFY \
$(call cc-option,-ffreestanding) \
$(call cc-option,-fno-stack-protector)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
index dcaf691..264899d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
@@ -1419,6 +1419,9 @@
if (size & 0x3 || *pos & 0x3)
return -EINVAL;
+ if (*pos >= adev->mc.mc_vram_size)
+ return -ENXIO;
+
while (size) {
unsigned long flags;
uint32_t value;
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c
index 3e6fe82..ac5437e 100644
--- a/drivers/gpu/drm/drm_dp_helper.c
+++ b/drivers/gpu/drm/drm_dp_helper.c
@@ -144,6 +144,8 @@
return DP_LINK_BW_2_7;
case 540000:
return DP_LINK_BW_5_4;
+ case 810000:
+ return DP_LINK_BW_8_1;
}
}
EXPORT_SYMBOL(drm_dp_link_rate_to_bw_code);
@@ -158,6 +160,8 @@
return 270000;
case DP_LINK_BW_5_4:
return 540000;
+ case DP_LINK_BW_8_1:
+ return 810000;
}
}
EXPORT_SYMBOL(drm_dp_bw_code_to_link_rate);
diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c
index f59771d..db7890c 100644
--- a/drivers/gpu/drm/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/drm_dp_mst_topology.c
@@ -330,6 +330,13 @@
return false;
}
+ /*
+ * ignore out-of-order messages or messages that are part of a
+ * failed transaction
+ */
+ if (!recv_hdr.somt && !msg->have_somt)
+ return false;
+
/* get length contained in this portion */
msg->curchunk_len = recv_hdr.msg_len;
msg->curchunk_hdrlen = hdrlen;
@@ -2168,7 +2175,7 @@
}
EXPORT_SYMBOL(drm_dp_mst_topology_mgr_resume);
-static void drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up)
+static bool drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up)
{
int len;
u8 replyblock[32];
@@ -2183,12 +2190,12 @@
replyblock, len);
if (ret != len) {
DRM_DEBUG_KMS("failed to read DPCD down rep %d %d\n", len, ret);
- return;
+ return false;
}
ret = drm_dp_sideband_msg_build(msg, replyblock, len, true);
if (!ret) {
DRM_DEBUG_KMS("sideband msg build failed %d\n", replyblock[0]);
- return;
+ return false;
}
replylen = msg->curchunk_len + msg->curchunk_hdrlen;
@@ -2200,21 +2207,32 @@
ret = drm_dp_dpcd_read(mgr->aux, basereg + curreply,
replyblock, len);
if (ret != len) {
- DRM_DEBUG_KMS("failed to read a chunk\n");
+ DRM_DEBUG_KMS("failed to read a chunk (len %d, ret %d)\n",
+ len, ret);
+ return false;
}
+
ret = drm_dp_sideband_msg_build(msg, replyblock, len, false);
- if (ret == false)
+ if (!ret) {
DRM_DEBUG_KMS("failed to build sideband msg\n");
+ return false;
+ }
+
curreply += len;
replylen -= len;
}
+ return true;
}
static int drm_dp_mst_handle_down_rep(struct drm_dp_mst_topology_mgr *mgr)
{
int ret = 0;
- drm_dp_get_one_sb_msg(mgr, false);
+ if (!drm_dp_get_one_sb_msg(mgr, false)) {
+ memset(&mgr->down_rep_recv, 0,
+ sizeof(struct drm_dp_sideband_msg_rx));
+ return 0;
+ }
if (mgr->down_rep_recv.have_eomt) {
struct drm_dp_sideband_msg_tx *txmsg;
@@ -2270,7 +2288,12 @@
static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr)
{
int ret = 0;
- drm_dp_get_one_sb_msg(mgr, true);
+
+ if (!drm_dp_get_one_sb_msg(mgr, true)) {
+ memset(&mgr->up_req_recv, 0,
+ sizeof(struct drm_dp_sideband_msg_rx));
+ return 0;
+ }
if (mgr->up_req_recv.have_eomt) {
struct drm_dp_sideband_msg_req_body msg;
@@ -2322,7 +2345,9 @@
DRM_DEBUG_KMS("Got RSN: pn: %d avail_pbn %d\n", msg.u.resource_stat.port_number, msg.u.resource_stat.available_pbn);
}
- drm_dp_put_mst_branch_device(mstb);
+ if (mstb)
+ drm_dp_put_mst_branch_device(mstb);
+
memset(&mgr->up_req_recv, 0, sizeof(struct drm_dp_sideband_msg_rx));
}
return ret;
diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig
index eeb7c49..31e5b76 100644
--- a/drivers/gpu/drm/msm/Kconfig
+++ b/drivers/gpu/drm/msm/Kconfig
@@ -12,6 +12,8 @@
select QCOM_SCM
select SND_SOC_HDMI_CODEC if SND_SOC
select SYNC_FILE
+ select HDCP_QSEECOM
+ select MSM_EXT_DISPLAY
default y
help
DRM/KMS driver for MSM/snapdragon.
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index b698b65..4015832 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -3,6 +3,7 @@
ccflags-$(CONFIG_DRM_MSM_DSI_PLL) += -Idrivers/gpu/drm/msm/dsi
ccflags-y += -Idrivers/gpu/drm/msm/sde
ccflags-y += -Idrivers/media/platform/msm/sde/rotator
+ccflags-y += -Idrivers/gpu/drm/msm/hdmi
msm_drm-y := \
dp/dp_usbpd.o \
@@ -13,8 +14,11 @@
dp/dp_panel.o \
dp/dp_link.o \
dp/dp_ctrl.o \
+ dp/dp_audio.o \
+ dp/dp_debug.o \
dp/dp_display.o \
dp/dp_drm.o \
+ dp/dp_hdcp2p2.o \
sde/sde_crtc.o \
sde/sde_encoder.o \
sde/sde_encoder_phys_vid.o \
@@ -36,6 +40,7 @@
sde/sde_hw_color_proc_v4.o \
sde/sde_hw_ad4.o \
sde_edid_parser.o \
+ sde_hdcp_1x.o
msm_drm-$(CONFIG_DRM_MSM_HDMI) += hdmi/hdmi.o \
hdmi/hdmi_audio.o \
diff --git a/drivers/gpu/drm/msm/dp/dp_audio.c b/drivers/gpu/drm/msm/dp/dp_audio.c
new file mode 100644
index 0000000..c263115
--- /dev/null
+++ b/drivers/gpu/drm/msm/dp/dp_audio.c
@@ -0,0 +1,794 @@
+/*
+ * Copyright (c) 2016-2017, The Linux Foundation. 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 and
+ * only 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.
+ *
+ */
+
+#define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__
+
+#include <linux/of_platform.h>
+#include <linux/msm_ext_display.h>
+
+#include <drm/drm_dp_helper.h>
+
+#include "dp_catalog.h"
+#include "dp_audio.h"
+#include "dp_panel.h"
+
+#define HEADER_BYTE_2_BIT 0
+#define PARITY_BYTE_2_BIT 8
+#define HEADER_BYTE_1_BIT 16
+#define PARITY_BYTE_1_BIT 24
+#define HEADER_BYTE_3_BIT 16
+#define PARITY_BYTE_3_BIT 24
+
+struct dp_audio_private {
+ struct platform_device *ext_pdev;
+ struct platform_device *pdev;
+ struct dp_catalog_audio *catalog;
+ struct msm_ext_disp_init_data ext_audio_data;
+ struct dp_panel *panel;
+
+ bool ack_enabled;
+ bool session_on;
+ bool engine_on;
+
+ u32 channels;
+
+ struct completion hpd_comp;
+
+ struct dp_audio dp_audio;
+};
+
+static u8 dp_audio_get_g0_value(u8 data)
+{
+ u8 c[4];
+ u8 g[4];
+ u8 ret_data = 0;
+ u8 i;
+
+ for (i = 0; i < 4; i++)
+ c[i] = (data >> i) & 0x01;
+
+ g[0] = c[3];
+ g[1] = c[0] ^ c[3];
+ g[2] = c[1];
+ g[3] = c[2];
+
+ for (i = 0; i < 4; i++)
+ ret_data = ((g[i] & 0x01) << i) | ret_data;
+
+ return ret_data;
+}
+
+static u8 dp_audio_get_g1_value(u8 data)
+{
+ u8 c[4];
+ u8 g[4];
+ u8 ret_data = 0;
+ u8 i;
+
+ for (i = 0; i < 4; i++)
+ c[i] = (data >> i) & 0x01;
+
+ g[0] = c[0] ^ c[3];
+ g[1] = c[0] ^ c[1] ^ c[3];
+ g[2] = c[1] ^ c[2];
+ g[3] = c[2] ^ c[3];
+
+ for (i = 0; i < 4; i++)
+ ret_data = ((g[i] & 0x01) << i) | ret_data;
+
+ return ret_data;
+}
+
+static u8 dp_audio_calculate_parity(u32 data)
+{
+ u8 x0 = 0;
+ u8 x1 = 0;
+ u8 ci = 0;
+ u8 iData = 0;
+ u8 i = 0;
+ u8 parity_byte;
+ u8 num_byte = (data & 0xFF00) > 0 ? 8 : 2;
+
+ for (i = 0; i < num_byte; i++) {
+ iData = (data >> i*4) & 0xF;
+
+ ci = iData ^ x1;
+ x1 = x0 ^ dp_audio_get_g1_value(ci);
+ x0 = dp_audio_get_g0_value(ci);
+ }
+
+ parity_byte = x1 | (x0 << 4);
+
+ return parity_byte;
+}
+
+static u32 dp_audio_get_header(struct dp_catalog_audio *catalog,
+ enum dp_catalog_audio_sdp_type sdp,
+ enum dp_catalog_audio_header_type header)
+{
+ catalog->sdp_type = sdp;
+ catalog->sdp_header = header;
+ catalog->get_header(catalog);
+
+ return catalog->data;
+}
+
+static void dp_audio_set_header(struct dp_catalog_audio *catalog,
+ u32 data,
+ enum dp_catalog_audio_sdp_type sdp,
+ enum dp_catalog_audio_header_type header)
+{
+ catalog->sdp_type = sdp;
+ catalog->sdp_header = header;
+ catalog->data = data;
+ catalog->set_header(catalog);
+}
+
+static void dp_audio_stream_sdp(struct dp_audio_private *audio)
+{
+ struct dp_catalog_audio *catalog = audio->catalog;
+ u32 value, new_value;
+ u8 parity_byte;
+
+ /* Config header and parity byte 1 */
+ value = dp_audio_get_header(catalog,
+ DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_1);
+
+ new_value = 0x02;
+ parity_byte = dp_audio_calculate_parity(new_value);
+ value |= ((new_value << HEADER_BYTE_1_BIT)
+ | (parity_byte << PARITY_BYTE_1_BIT));
+ pr_debug("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
+ value, parity_byte);
+ dp_audio_set_header(catalog, value,
+ DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_1);
+
+ /* Config header and parity byte 2 */
+ value = dp_audio_get_header(catalog,
+ DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_2);
+ new_value = value;
+ parity_byte = dp_audio_calculate_parity(new_value);
+ value |= ((new_value << HEADER_BYTE_2_BIT)
+ | (parity_byte << PARITY_BYTE_2_BIT));
+ pr_debug("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
+ value, parity_byte);
+
+ dp_audio_set_header(catalog, value,
+ DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_2);
+
+ /* Config header and parity byte 3 */
+ value = dp_audio_get_header(catalog,
+ DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_3);
+
+ new_value = audio->channels - 1;
+ parity_byte = dp_audio_calculate_parity(new_value);
+ value |= ((new_value << HEADER_BYTE_3_BIT)
+ | (parity_byte << PARITY_BYTE_3_BIT));
+ pr_debug("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",
+ value, parity_byte);
+
+ dp_audio_set_header(catalog, value,
+ DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_3);
+}
+
+static void dp_audio_timestamp_sdp(struct dp_audio_private *audio)
+{
+ struct dp_catalog_audio *catalog = audio->catalog;
+ u32 value, new_value;
+ u8 parity_byte;
+
+ /* Config header and parity byte 1 */
+ value = dp_audio_get_header(catalog,
+ DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_1);
+
+ new_value = 0x1;
+ parity_byte = dp_audio_calculate_parity(new_value);
+ value |= ((new_value << HEADER_BYTE_1_BIT)
+ | (parity_byte << PARITY_BYTE_1_BIT));
+ pr_debug("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
+ value, parity_byte);
+ dp_audio_set_header(catalog, value,
+ DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_1);
+
+ /* Config header and parity byte 2 */
+ value = dp_audio_get_header(catalog,
+ DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_2);
+
+ new_value = 0x17;
+ parity_byte = dp_audio_calculate_parity(new_value);
+ value |= ((new_value << HEADER_BYTE_2_BIT)
+ | (parity_byte << PARITY_BYTE_2_BIT));
+ pr_debug("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
+ value, parity_byte);
+ dp_audio_set_header(catalog, value,
+ DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_2);
+
+ /* Config header and parity byte 3 */
+ value = dp_audio_get_header(catalog,
+ DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_3);
+
+ new_value = (0x0 | (0x11 << 2));
+ parity_byte = dp_audio_calculate_parity(new_value);
+ value |= ((new_value << HEADER_BYTE_3_BIT)
+ | (parity_byte << PARITY_BYTE_3_BIT));
+ pr_debug("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",
+ value, parity_byte);
+ dp_audio_set_header(catalog, value,
+ DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_3);
+}
+
+static void dp_audio_infoframe_sdp(struct dp_audio_private *audio)
+{
+ struct dp_catalog_audio *catalog = audio->catalog;
+ u32 value, new_value;
+ u8 parity_byte;
+
+ /* Config header and parity byte 1 */
+ value = dp_audio_get_header(catalog,
+ DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_1);
+
+ new_value = 0x84;
+ parity_byte = dp_audio_calculate_parity(new_value);
+ value |= ((new_value << HEADER_BYTE_1_BIT)
+ | (parity_byte << PARITY_BYTE_1_BIT));
+ pr_debug("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
+ value, parity_byte);
+ dp_audio_set_header(catalog, value,
+ DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_1);
+
+ /* Config header and parity byte 2 */
+ value = dp_audio_get_header(catalog,
+ DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_2);
+
+ new_value = 0x1b;
+ parity_byte = dp_audio_calculate_parity(new_value);
+ value |= ((new_value << HEADER_BYTE_2_BIT)
+ | (parity_byte << PARITY_BYTE_2_BIT));
+ pr_debug("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
+ value, parity_byte);
+ dp_audio_set_header(catalog, value,
+ DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_2);
+
+ /* Config header and parity byte 3 */
+ value = dp_audio_get_header(catalog,
+ DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_3);
+
+ new_value = (0x0 | (0x11 << 2));
+ parity_byte = dp_audio_calculate_parity(new_value);
+ value |= ((new_value << HEADER_BYTE_3_BIT)
+ | (parity_byte << PARITY_BYTE_3_BIT));
+ pr_debug("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",
+ new_value, parity_byte);
+ dp_audio_set_header(catalog, value,
+ DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_3);
+}
+
+static void dp_audio_copy_management_sdp(struct dp_audio_private *audio)
+{
+ struct dp_catalog_audio *catalog = audio->catalog;
+ u32 value, new_value;
+ u8 parity_byte;
+
+ /* Config header and parity byte 1 */
+ value = dp_audio_get_header(catalog,
+ DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_1);
+
+ new_value = 0x05;
+ parity_byte = dp_audio_calculate_parity(new_value);
+ value |= ((new_value << HEADER_BYTE_1_BIT)
+ | (parity_byte << PARITY_BYTE_1_BIT));
+ pr_debug("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
+ value, parity_byte);
+ dp_audio_set_header(catalog, value,
+ DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_1);
+
+ /* Config header and parity byte 2 */
+ value = dp_audio_get_header(catalog,
+ DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_2);
+
+ new_value = 0x0F;
+ parity_byte = dp_audio_calculate_parity(new_value);
+ value |= ((new_value << HEADER_BYTE_2_BIT)
+ | (parity_byte << PARITY_BYTE_2_BIT));
+ pr_debug("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
+ value, parity_byte);
+ dp_audio_set_header(catalog, value,
+ DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_2);
+
+ /* Config header and parity byte 3 */
+ value = dp_audio_get_header(catalog,
+ DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_3);
+
+ new_value = 0x0;
+ parity_byte = dp_audio_calculate_parity(new_value);
+ value |= ((new_value << HEADER_BYTE_3_BIT)
+ | (parity_byte << PARITY_BYTE_3_BIT));
+ pr_debug("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",
+ value, parity_byte);
+ dp_audio_set_header(catalog, value,
+ DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_3);
+}
+
+static void dp_audio_isrc_sdp(struct dp_audio_private *audio)
+{
+ struct dp_catalog_audio *catalog = audio->catalog;
+ u32 value, new_value;
+ u8 parity_byte;
+
+ /* Config header and parity byte 1 */
+ value = dp_audio_get_header(catalog,
+ DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_1);
+
+ new_value = 0x06;
+ parity_byte = dp_audio_calculate_parity(new_value);
+ value |= ((new_value << HEADER_BYTE_1_BIT)
+ | (parity_byte << PARITY_BYTE_1_BIT));
+ pr_debug("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
+ value, parity_byte);
+ dp_audio_set_header(catalog, value,
+ DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_1);
+
+ /* Config header and parity byte 2 */
+ value = dp_audio_get_header(catalog,
+ DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_2);
+
+ new_value = 0x0F;
+ parity_byte = dp_audio_calculate_parity(new_value);
+ value |= ((new_value << HEADER_BYTE_2_BIT)
+ | (parity_byte << PARITY_BYTE_2_BIT));
+ pr_debug("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
+ value, parity_byte);
+ dp_audio_set_header(catalog, value,
+ DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_2);
+}
+
+static void dp_audio_setup_sdp(struct dp_audio_private *audio)
+{
+ audio->catalog->config_sdp(audio->catalog);
+
+ dp_audio_stream_sdp(audio);
+ dp_audio_timestamp_sdp(audio);
+ dp_audio_infoframe_sdp(audio);
+ dp_audio_copy_management_sdp(audio);
+ dp_audio_isrc_sdp(audio);
+}
+
+static void dp_audio_setup_acr(struct dp_audio_private *audio)
+{
+ u32 select = 0;
+ struct dp_catalog_audio *catalog = audio->catalog;
+
+ switch (audio->dp_audio.bw_code) {
+ case DP_LINK_BW_1_62:
+ select = 0;
+ break;
+ case DP_LINK_BW_2_7:
+ select = 1;
+ break;
+ case DP_LINK_BW_5_4:
+ select = 2;
+ break;
+ case DP_LINK_RATE_810:
+ select = 3;
+ break;
+ default:
+ pr_debug("Unknown link rate\n");
+ select = 0;
+ break;
+ }
+
+ catalog->data = select;
+ catalog->config_acr(catalog);
+}
+
+static void dp_audio_safe_to_exit_level(struct dp_audio_private *audio)
+{
+ struct dp_catalog_audio *catalog = audio->catalog;
+ u32 safe_to_exit_level = 0;
+
+ switch (audio->dp_audio.lane_count) {
+ case 1:
+ safe_to_exit_level = 14;
+ break;
+ case 2:
+ safe_to_exit_level = 8;
+ break;
+ case 4:
+ safe_to_exit_level = 5;
+ break;
+ default:
+ pr_debug("setting the default safe_to_exit_level = %u\n",
+ safe_to_exit_level);
+ safe_to_exit_level = 14;
+ break;
+ }
+
+ catalog->data = safe_to_exit_level;
+ catalog->safe_to_exit_level(catalog);
+}
+
+static void dp_audio_enable(struct dp_audio_private *audio, bool enable)
+{
+ struct dp_catalog_audio *catalog = audio->catalog;
+
+ catalog->data = enable;
+ catalog->enable(catalog);
+
+ audio->engine_on = enable;
+}
+
+static struct dp_audio_private *get_audio_get_data(struct platform_device *pdev)
+{
+ struct msm_ext_disp_data *ext_data;
+ struct dp_audio *dp_audio;
+
+ if (!pdev) {
+ pr_err("invalid input\n");
+ return ERR_PTR(-ENODEV);
+ }
+
+ ext_data = platform_get_drvdata(pdev);
+ if (!ext_data) {
+ pr_err("invalid ext disp data\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ dp_audio = ext_data->intf_data;
+ if (!ext_data) {
+ pr_err("invalid intf data\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ return container_of(dp_audio, struct dp_audio_private, dp_audio);
+}
+
+static int dp_audio_info_setup(struct platform_device *pdev,
+ struct msm_ext_disp_audio_setup_params *params)
+{
+ int rc = 0;
+ struct dp_audio_private *audio;
+
+ audio = get_audio_get_data(pdev);
+ if (IS_ERR(audio)) {
+ rc = PTR_ERR(audio);
+ goto end;
+ }
+
+ audio->channels = params->num_of_channels;
+
+ dp_audio_setup_sdp(audio);
+ dp_audio_setup_acr(audio);
+ dp_audio_safe_to_exit_level(audio);
+ dp_audio_enable(audio, true);
+end:
+ return rc;
+}
+
+static int dp_audio_get_edid_blk(struct platform_device *pdev,
+ struct msm_ext_disp_audio_edid_blk *blk)
+{
+ int rc = 0;
+ struct dp_audio_private *audio;
+ struct sde_edid_ctrl *edid;
+
+ audio = get_audio_get_data(pdev);
+ if (IS_ERR(audio)) {
+ rc = PTR_ERR(audio);
+ goto end;
+ }
+
+ if (!audio->panel || !audio->panel->edid_ctrl) {
+ pr_err("invalid panel data\n");
+ rc = -EINVAL;
+ goto end;
+ }
+
+ edid = audio->panel->edid_ctrl;
+
+ blk->audio_data_blk = edid->audio_data_block;
+ blk->audio_data_blk_size = edid->adb_size;
+
+ blk->spk_alloc_data_blk = edid->spkr_alloc_data_block;
+ blk->spk_alloc_data_blk_size = edid->sadb_size;
+end:
+ return rc;
+}
+
+static int dp_audio_get_cable_status(struct platform_device *pdev, u32 vote)
+{
+ int rc = 0;
+ struct dp_audio_private *audio;
+
+ audio = get_audio_get_data(pdev);
+ if (IS_ERR(audio)) {
+ rc = PTR_ERR(audio);
+ goto end;
+ }
+
+ if (!audio->panel) {
+ pr_err("invalid panel data\n");
+ rc = -EINVAL;
+ goto end;
+ }
+
+ return audio->session_on;
+end:
+ return rc;
+}
+
+static int dp_audio_get_intf_id(struct platform_device *pdev)
+{
+ int rc = 0;
+ struct dp_audio_private *audio;
+
+ audio = get_audio_get_data(pdev);
+ if (IS_ERR(audio)) {
+ rc = PTR_ERR(audio);
+ goto end;
+ }
+
+ return EXT_DISPLAY_TYPE_DP;
+end:
+ return rc;
+}
+
+static void dp_audio_teardown_done(struct platform_device *pdev)
+{
+ struct dp_audio_private *audio;
+
+ audio = get_audio_get_data(pdev);
+ if (IS_ERR(audio))
+ return;
+
+ if (!audio->panel) {
+ pr_err("invalid panel data\n");
+ return;
+ }
+
+ dp_audio_enable(audio, false);
+
+ complete_all(&audio->hpd_comp);
+
+ pr_debug("audio engine disabled\n");
+}
+
+static int dp_audio_ack_done(struct platform_device *pdev, u32 ack)
+{
+ int rc = 0, ack_hpd;
+ struct dp_audio_private *audio;
+
+ audio = get_audio_get_data(pdev);
+ if (IS_ERR(audio)) {
+ rc = PTR_ERR(audio);
+ goto end;
+ }
+
+ if (ack & AUDIO_ACK_SET_ENABLE) {
+ audio->ack_enabled = ack & AUDIO_ACK_ENABLE ?
+ true : false;
+
+ pr_debug("audio ack feature %s\n",
+ audio->ack_enabled ? "enabled" : "disabled");
+ goto end;
+ }
+
+ if (!audio->ack_enabled)
+ goto end;
+
+ ack_hpd = ack & AUDIO_ACK_CONNECT;
+
+ pr_debug("acknowledging audio (%d)\n", ack_hpd);
+
+ if (!audio->engine_on)
+ complete_all(&audio->hpd_comp);
+end:
+ return rc;
+}
+
+static int dp_audio_init_ext_disp(struct dp_audio_private *audio)
+{
+ int rc = 0;
+ struct device_node *pd = NULL;
+ const char *phandle = "qcom,ext-disp";
+ struct msm_ext_disp_init_data *ext;
+ struct msm_ext_disp_audio_codec_ops *ops;
+
+ ext = &audio->ext_audio_data;
+ ops = &ext->codec_ops;
+
+ ext->type = EXT_DISPLAY_TYPE_DP;
+ ext->pdev = audio->pdev;
+ ext->intf_data = &audio->dp_audio;
+
+ ops->audio_info_setup = dp_audio_info_setup;
+ ops->get_audio_edid_blk = dp_audio_get_edid_blk;
+ ops->cable_status = dp_audio_get_cable_status;
+ ops->get_intf_id = dp_audio_get_intf_id;
+ ops->teardown_done = dp_audio_teardown_done;
+ ops->acknowledge = dp_audio_ack_done;
+
+ if (!audio->pdev->dev.of_node) {
+ pr_err("cannot find audio dev.of_node\n");
+ rc = -ENODEV;
+ goto end;
+ }
+
+ pd = of_parse_phandle(audio->pdev->dev.of_node, phandle, 0);
+ if (!pd) {
+ pr_err("cannot parse %s handle\n", phandle);
+ rc = -ENODEV;
+ goto end;
+ }
+
+ audio->ext_pdev = of_find_device_by_node(pd);
+ if (!audio->ext_pdev) {
+ pr_err("cannot find %s pdev\n", phandle);
+ rc = -ENODEV;
+ goto end;
+ }
+
+ rc = msm_ext_disp_register_intf(audio->ext_pdev, ext);
+ if (rc)
+ pr_err("failed to register disp\n");
+end:
+ if (pd)
+ of_node_put(pd);
+
+ return rc;
+}
+
+static int dp_audio_on(struct dp_audio *dp_audio)
+{
+ int rc = 0;
+ struct dp_audio_private *audio;
+ struct msm_ext_disp_init_data *ext;
+
+ if (!dp_audio) {
+ pr_err("invalid input\n");
+ rc = -EINVAL;
+ goto end;
+ }
+
+ audio = container_of(dp_audio, struct dp_audio_private, dp_audio);
+
+ ext = &audio->ext_audio_data;
+
+ audio->session_on = true;
+
+ rc = ext->intf_ops.audio_config(audio->ext_pdev,
+ EXT_DISPLAY_TYPE_DP,
+ EXT_DISPLAY_CABLE_CONNECT);
+ if (rc) {
+ pr_err("failed to config audio, err=%d\n", rc);
+ goto end;
+ }
+
+ rc = ext->intf_ops.audio_notify(audio->ext_pdev,
+ EXT_DISPLAY_TYPE_DP,
+ EXT_DISPLAY_CABLE_CONNECT);
+ if (rc) {
+ pr_err("failed to notify audio, err=%d\n", rc);
+ goto end;
+ }
+
+ reinit_completion(&audio->hpd_comp);
+ rc = wait_for_completion_timeout(&audio->hpd_comp, HZ * 5);
+ if (!rc) {
+ pr_err("timeout\n");
+ rc = -ETIMEDOUT;
+ goto end;
+ }
+
+ pr_debug("success\n");
+end:
+ return rc;
+}
+
+static int dp_audio_off(struct dp_audio *dp_audio)
+{
+ int rc = 0;
+ struct dp_audio_private *audio;
+ struct msm_ext_disp_init_data *ext;
+
+ if (!dp_audio) {
+ pr_err("invalid input\n");
+ return -EINVAL;
+ }
+
+ audio = container_of(dp_audio, struct dp_audio_private, dp_audio);
+ ext = &audio->ext_audio_data;
+
+ rc = ext->intf_ops.audio_notify(audio->ext_pdev,
+ EXT_DISPLAY_TYPE_DP,
+ EXT_DISPLAY_CABLE_DISCONNECT);
+ if (rc) {
+ pr_err("failed to notify audio, err=%d\n", rc);
+ goto end;
+ }
+
+ reinit_completion(&audio->hpd_comp);
+ rc = wait_for_completion_timeout(&audio->hpd_comp, HZ * 5);
+ if (!rc) {
+ pr_err("timeout\n");
+ rc = -ETIMEDOUT;
+ goto end;
+ }
+
+ pr_debug("success\n");
+end:
+ rc = ext->intf_ops.audio_config(audio->ext_pdev,
+ EXT_DISPLAY_TYPE_DP,
+ EXT_DISPLAY_CABLE_DISCONNECT);
+ if (rc)
+ pr_err("failed to config audio, err=%d\n", rc);
+
+ audio->session_on = false;
+ audio->engine_on = false;
+
+ return rc;
+}
+
+struct dp_audio *dp_audio_get(struct platform_device *pdev,
+ struct dp_panel *panel,
+ struct dp_catalog_audio *catalog)
+{
+ int rc = 0;
+ struct dp_audio_private *audio;
+ struct dp_audio *dp_audio;
+
+ if (!pdev || !panel || !catalog) {
+ pr_err("invalid input\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ audio = devm_kzalloc(&pdev->dev, sizeof(*audio), GFP_KERNEL);
+ if (!audio) {
+ rc = -ENOMEM;
+ goto error;
+ }
+
+ init_completion(&audio->hpd_comp);
+
+ audio->pdev = pdev;
+ audio->panel = panel;
+ audio->catalog = catalog;
+
+ dp_audio = &audio->dp_audio;
+
+ dp_audio->on = dp_audio_on;
+ dp_audio->off = dp_audio_off;
+
+ rc = dp_audio_init_ext_disp(audio);
+ if (rc)
+ goto error;
+
+ catalog->init(catalog);
+
+ return dp_audio;
+error:
+ return ERR_PTR(rc);
+}
+
+void dp_audio_put(struct dp_audio *dp_audio)
+{
+ struct dp_audio_private *audio;
+
+ if (!dp_audio)
+ return;
+
+ audio = container_of(dp_audio, struct dp_audio_private, dp_audio);
+
+ kzfree(audio);
+}
diff --git a/drivers/gpu/drm/msm/dp/dp_audio.h b/drivers/gpu/drm/msm/dp/dp_audio.h
new file mode 100644
index 0000000..d6e6b74
--- /dev/null
+++ b/drivers/gpu/drm/msm/dp/dp_audio.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2016-2017, The Linux Foundation. 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 and
+ * only 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 _DP_AUDIO_H_
+#define _DP_AUDIO_H_
+
+#include <linux/platform_device.h>
+
+#include "dp_panel.h"
+#include "dp_catalog.h"
+
+/**
+ * struct dp_audio
+ * @lane_count: number of lanes configured in current session
+ * @bw_code: link rate's bandwidth code for current session
+ */
+struct dp_audio {
+ u32 lane_count;
+ u32 bw_code;
+
+ /**
+ * on()
+ *
+ * Enables the audio by notifying the user module.
+ *
+ * @dp_audio: an instance of struct dp_audio.
+ *
+ * Returns the error code in case of failure, 0 in success case.
+ */
+ int (*on)(struct dp_audio *dp_audio);
+
+ /**
+ * off()
+ *
+ * Disables the audio by notifying the user module.
+ *
+ * @dp_audio: an instance of struct dp_audio.
+ *
+ * Returns the error code in case of failure, 0 in success case.
+ */
+ int (*off)(struct dp_audio *dp_audio);
+};
+
+/**
+ * dp_audio_get()
+ *
+ * Creates and instance of dp audio.
+ *
+ * @pdev: caller's platform device instance.
+ * @panel: an instance of dp_panel module.
+ * @catalog: an instance of dp_catalog_audio module.
+ *
+ * Returns the error code in case of failure, otherwize
+ * an instance of newly created dp_module.
+ */
+struct dp_audio *dp_audio_get(struct platform_device *pdev,
+ struct dp_panel *panel,
+ struct dp_catalog_audio *catalog);
+
+/**
+ * dp_audio_put()
+ *
+ * Cleans the dp_audio instance.
+ *
+ * @dp_audio: an instance of dp_audio.
+ */
+void dp_audio_put(struct dp_audio *dp_audio);
+#endif /* _DP_AUDIO_H_ */
+
+
diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c b/drivers/gpu/drm/msm/dp/dp_aux.c
index 67c6b2d..9106027 100644
--- a/drivers/gpu/drm/msm/dp/dp_aux.c
+++ b/drivers/gpu/drm/msm/dp/dp_aux.c
@@ -28,11 +28,13 @@
struct device *dev;
struct dp_aux dp_aux;
struct dp_catalog_aux *catalog;
+ struct dp_aux_cfg *cfg;
struct mutex mutex;
struct completion comp;
u32 aux_error_num;
+ u32 retry_cnt;
bool cmd_busy;
bool native;
bool read;
@@ -127,7 +129,7 @@
timeout = wait_for_completion_timeout(&aux->comp, aux_timeout_ms);
if (!timeout) {
- pr_err("aux write timeout\n");
+ pr_err("aux %s timeout\n", (aux->read ? "read" : "write"));
return -ETIMEDOUT;
}
@@ -232,6 +234,22 @@
dp_aux_i2c_handler(aux);
}
+static void dp_aux_reconfig(struct dp_aux *dp_aux)
+{
+ struct dp_aux_private *aux;
+
+ if (!dp_aux) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
+
+ aux->catalog->update_aux_cfg(aux->catalog,
+ aux->cfg, PHY_AUX_CFG1);
+ aux->catalog->reset(aux->catalog);
+}
+
/*
* This function does the real job to process an AUX transaction.
* It will call aux_reset() function to reset the AUX channel,
@@ -243,6 +261,7 @@
ssize_t ret;
int const aux_cmd_native_max = 16;
int const aux_cmd_i2c_max = 128;
+ int const retry_count = 5;
struct dp_aux_private *aux = container_of(drm_aux,
struct dp_aux_private, drm_aux);
@@ -270,8 +289,14 @@
}
ret = dp_aux_cmd_fifo_tx(aux, msg);
- if (ret < 0) {
- aux->catalog->reset(aux->catalog); /* reset aux */
+ if ((ret < 0) && aux->native) {
+ aux->retry_cnt++;
+ if (!(aux->retry_cnt % retry_count))
+ aux->catalog->update_aux_cfg(aux->catalog,
+ aux->cfg, PHY_AUX_CFG1);
+ aux->catalog->reset(aux->catalog);
+ goto unlock_exit;
+ } else if (ret < 0) {
goto unlock_exit;
}
@@ -289,6 +314,7 @@
/* Return requested size for success or retry */
ret = msg->size;
+ aux->retry_cnt = 0;
unlock_exit:
aux->cmd_busy = false;
@@ -296,11 +322,19 @@
return ret;
}
-static void dp_aux_init(struct dp_aux *dp_aux, u32 *aux_cfg)
+static void dp_aux_reset_phy_config_indices(struct dp_aux_cfg *aux_cfg)
+{
+ int i = 0;
+
+ for (i = 0; i < PHY_AUX_CFG_MAX; i++)
+ aux_cfg[i].current_index = 0;
+}
+
+static void dp_aux_init(struct dp_aux *dp_aux, struct dp_aux_cfg *aux_cfg)
{
struct dp_aux_private *aux;
- if (!dp_aux) {
+ if (!dp_aux || !aux_cfg) {
pr_err("invalid input\n");
return;
}
@@ -309,6 +343,8 @@
aux->catalog->reset(aux->catalog);
aux->catalog->enable(aux->catalog, true);
+ aux->retry_cnt = 0;
+ dp_aux_reset_phy_config_indices(aux_cfg);
aux->catalog->setup(aux->catalog, aux_cfg);
}
@@ -365,13 +401,14 @@
drm_dp_aux_unregister(&aux->drm_aux);
}
-struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog)
+struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog,
+ struct dp_aux_cfg *aux_cfg)
{
int rc = 0;
struct dp_aux_private *aux;
struct dp_aux *dp_aux;
- if (!catalog) {
+ if (!catalog || !aux_cfg) {
pr_err("invalid input\n");
rc = -ENODEV;
goto error;
@@ -389,13 +426,16 @@
aux->dev = dev;
aux->catalog = catalog;
+ aux->cfg = aux_cfg;
dp_aux = &aux->dp_aux;
+ aux->retry_cnt = 0;
dp_aux->isr = dp_aux_isr;
dp_aux->init = dp_aux_init;
dp_aux->deinit = dp_aux_deinit;
dp_aux->drm_aux_register = dp_aux_register;
dp_aux->drm_aux_deregister = dp_aux_deregister;
+ dp_aux->reconfig = dp_aux_reconfig;
return dp_aux;
error:
diff --git a/drivers/gpu/drm/msm/dp/dp_aux.h b/drivers/gpu/drm/msm/dp/dp_aux.h
index f08c12b..5d96fd9 100644
--- a/drivers/gpu/drm/msm/dp/dp_aux.h
+++ b/drivers/gpu/drm/msm/dp/dp_aux.h
@@ -32,11 +32,13 @@
int (*drm_aux_register)(struct dp_aux *aux);
void (*drm_aux_deregister)(struct dp_aux *aux);
void (*isr)(struct dp_aux *aux);
- void (*init)(struct dp_aux *aux, u32 *aux_cfg);
+ void (*init)(struct dp_aux *aux, struct dp_aux_cfg *aux_cfg);
void (*deinit)(struct dp_aux *aux);
+ void (*reconfig)(struct dp_aux *aux);
};
-struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog);
+struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog,
+ struct dp_aux_cfg *aux_cfg);
void dp_aux_put(struct dp_aux *aux);
#endif /*__DP_AUX_H_*/
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c
index 5825ba8..94bd199 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -17,196 +17,7 @@
#include <linux/delay.h>
#include "dp_catalog.h"
-
-/* DP_TX Registers */
-#define DP_HW_VERSION (0x00000000)
-#define DP_SW_RESET (0x00000010)
-#define DP_PHY_CTRL (0x00000014)
-#define DP_CLK_CTRL (0x00000018)
-#define DP_CLK_ACTIVE (0x0000001C)
-#define DP_INTR_STATUS (0x00000020)
-#define DP_INTR_STATUS2 (0x00000024)
-#define DP_INTR_STATUS3 (0x00000028)
-
-#define DP_DP_HPD_CTRL (0x00000200)
-#define DP_DP_HPD_INT_STATUS (0x00000204)
-#define DP_DP_HPD_INT_ACK (0x00000208)
-#define DP_DP_HPD_INT_MASK (0x0000020C)
-#define DP_DP_HPD_REFTIMER (0x00000218)
-#define DP_DP_HPD_EVENT_TIME_0 (0x0000021C)
-#define DP_DP_HPD_EVENT_TIME_1 (0x00000220)
-#define DP_AUX_CTRL (0x00000230)
-#define DP_AUX_DATA (0x00000234)
-#define DP_AUX_TRANS_CTRL (0x00000238)
-#define DP_TIMEOUT_COUNT (0x0000023C)
-#define DP_AUX_LIMITS (0x00000240)
-#define DP_AUX_STATUS (0x00000244)
-
-#define DP_DPCD_CP_IRQ (0x201)
-#define DP_DPCD_RXSTATUS (0x69493)
-
-#define DP_INTERRUPT_TRANS_NUM (0x000002A0)
-
-#define DP_MAINLINK_CTRL (0x00000400)
-#define DP_STATE_CTRL (0x00000404)
-#define DP_CONFIGURATION_CTRL (0x00000408)
-#define DP_SOFTWARE_MVID (0x00000410)
-#define DP_SOFTWARE_NVID (0x00000418)
-#define DP_TOTAL_HOR_VER (0x0000041C)
-#define DP_START_HOR_VER_FROM_SYNC (0x00000420)
-#define DP_HSYNC_VSYNC_WIDTH_POLARITY (0x00000424)
-#define DP_ACTIVE_HOR_VER (0x00000428)
-#define DP_MISC1_MISC0 (0x0000042C)
-#define DP_VALID_BOUNDARY (0x00000430)
-#define DP_VALID_BOUNDARY_2 (0x00000434)
-#define DP_LOGICAL2PHYSCIAL_LANE_MAPPING (0x00000438)
-
-#define DP_MAINLINK_READY (0x00000440)
-#define DP_MAINLINK_LEVELS (0x00000444)
-#define DP_TU (0x0000044C)
-
-#define DP_HBR2_COMPLIANCE_SCRAMBLER_RESET (0x00000454)
-#define DP_TEST_80BIT_CUSTOM_PATTERN_REG0 (0x000004C0)
-#define DP_TEST_80BIT_CUSTOM_PATTERN_REG1 (0x000004C4)
-#define DP_TEST_80BIT_CUSTOM_PATTERN_REG2 (0x000004C8)
-
-#define MMSS_DP_MISC1_MISC0 (0x0000042C)
-#define MMSS_DP_AUDIO_TIMING_GEN (0x00000480)
-#define MMSS_DP_AUDIO_TIMING_RBR_32 (0x00000484)
-#define MMSS_DP_AUDIO_TIMING_HBR_32 (0x00000488)
-#define MMSS_DP_AUDIO_TIMING_RBR_44 (0x0000048C)
-#define MMSS_DP_AUDIO_TIMING_HBR_44 (0x00000490)
-#define MMSS_DP_AUDIO_TIMING_RBR_48 (0x00000494)
-#define MMSS_DP_AUDIO_TIMING_HBR_48 (0x00000498)
-
-#define MMSS_DP_PSR_CRC_RG (0x00000554)
-#define MMSS_DP_PSR_CRC_B (0x00000558)
-
-#define MMSS_DP_AUDIO_CFG (0x00000600)
-#define MMSS_DP_AUDIO_STATUS (0x00000604)
-#define MMSS_DP_AUDIO_PKT_CTRL (0x00000608)
-#define MMSS_DP_AUDIO_PKT_CTRL2 (0x0000060C)
-#define MMSS_DP_AUDIO_ACR_CTRL (0x00000610)
-#define MMSS_DP_AUDIO_CTRL_RESET (0x00000614)
-
-#define MMSS_DP_SDP_CFG (0x00000628)
-#define MMSS_DP_SDP_CFG2 (0x0000062C)
-#define MMSS_DP_AUDIO_TIMESTAMP_0 (0x00000630)
-#define MMSS_DP_AUDIO_TIMESTAMP_1 (0x00000634)
-
-#define MMSS_DP_AUDIO_STREAM_0 (0x00000640)
-#define MMSS_DP_AUDIO_STREAM_1 (0x00000644)
-
-#define MMSS_DP_EXTENSION_0 (0x00000650)
-#define MMSS_DP_EXTENSION_1 (0x00000654)
-#define MMSS_DP_EXTENSION_2 (0x00000658)
-#define MMSS_DP_EXTENSION_3 (0x0000065C)
-#define MMSS_DP_EXTENSION_4 (0x00000660)
-#define MMSS_DP_EXTENSION_5 (0x00000664)
-#define MMSS_DP_EXTENSION_6 (0x00000668)
-#define MMSS_DP_EXTENSION_7 (0x0000066C)
-#define MMSS_DP_EXTENSION_8 (0x00000670)
-#define MMSS_DP_EXTENSION_9 (0x00000674)
-#define MMSS_DP_AUDIO_COPYMANAGEMENT_0 (0x00000678)
-#define MMSS_DP_AUDIO_COPYMANAGEMENT_1 (0x0000067C)
-#define MMSS_DP_AUDIO_COPYMANAGEMENT_2 (0x00000680)
-#define MMSS_DP_AUDIO_COPYMANAGEMENT_3 (0x00000684)
-#define MMSS_DP_AUDIO_COPYMANAGEMENT_4 (0x00000688)
-#define MMSS_DP_AUDIO_COPYMANAGEMENT_5 (0x0000068C)
-#define MMSS_DP_AUDIO_ISRC_0 (0x00000690)
-#define MMSS_DP_AUDIO_ISRC_1 (0x00000694)
-#define MMSS_DP_AUDIO_ISRC_2 (0x00000698)
-#define MMSS_DP_AUDIO_ISRC_3 (0x0000069C)
-#define MMSS_DP_AUDIO_ISRC_4 (0x000006A0)
-#define MMSS_DP_AUDIO_ISRC_5 (0x000006A4)
-#define MMSS_DP_AUDIO_INFOFRAME_0 (0x000006A8)
-#define MMSS_DP_AUDIO_INFOFRAME_1 (0x000006AC)
-#define MMSS_DP_AUDIO_INFOFRAME_2 (0x000006B0)
-
-#define MMSS_DP_GENERIC0_0 (0x00000700)
-#define MMSS_DP_GENERIC0_1 (0x00000704)
-#define MMSS_DP_GENERIC0_2 (0x00000708)
-#define MMSS_DP_GENERIC0_3 (0x0000070C)
-#define MMSS_DP_GENERIC0_4 (0x00000710)
-#define MMSS_DP_GENERIC0_5 (0x00000714)
-#define MMSS_DP_GENERIC0_6 (0x00000718)
-#define MMSS_DP_GENERIC0_7 (0x0000071C)
-#define MMSS_DP_GENERIC0_8 (0x00000720)
-#define MMSS_DP_GENERIC0_9 (0x00000724)
-#define MMSS_DP_GENERIC1_0 (0x00000728)
-#define MMSS_DP_GENERIC1_1 (0x0000072C)
-#define MMSS_DP_GENERIC1_2 (0x00000730)
-#define MMSS_DP_GENERIC1_3 (0x00000734)
-#define MMSS_DP_GENERIC1_4 (0x00000738)
-#define MMSS_DP_GENERIC1_5 (0x0000073C)
-#define MMSS_DP_GENERIC1_6 (0x00000740)
-#define MMSS_DP_GENERIC1_7 (0x00000744)
-#define MMSS_DP_GENERIC1_8 (0x00000748)
-#define MMSS_DP_GENERIC1_9 (0x0000074C)
-
-#define MMSS_DP_TIMING_ENGINE_EN (0x00000A10)
-#define MMSS_DP_ASYNC_FIFO_CONFIG (0x00000A88)
-
-/*DP PHY Register offsets */
-#define DP_PHY_REVISION_ID0 (0x00000000)
-#define DP_PHY_REVISION_ID1 (0x00000004)
-#define DP_PHY_REVISION_ID2 (0x00000008)
-#define DP_PHY_REVISION_ID3 (0x0000000C)
-
-#define DP_PHY_CFG (0x00000010)
-#define DP_PHY_PD_CTL (0x00000018)
-#define DP_PHY_MODE (0x0000001C)
-
-#define DP_PHY_AUX_CFG0 (0x00000020)
-#define DP_PHY_AUX_CFG1 (0x00000024)
-#define DP_PHY_AUX_CFG2 (0x00000028)
-#define DP_PHY_AUX_CFG3 (0x0000002C)
-#define DP_PHY_AUX_CFG4 (0x00000030)
-#define DP_PHY_AUX_CFG5 (0x00000034)
-#define DP_PHY_AUX_CFG6 (0x00000038)
-#define DP_PHY_AUX_CFG7 (0x0000003C)
-#define DP_PHY_AUX_CFG8 (0x00000040)
-#define DP_PHY_AUX_CFG9 (0x00000044)
-#define DP_PHY_AUX_INTERRUPT_MASK (0x00000048)
-#define DP_PHY_AUX_INTERRUPT_CLEAR (0x0000004C)
-
-#define DP_PHY_SPARE0 (0x00AC)
-
-#define TXn_TX_EMP_POST1_LVL (0x000C)
-#define TXn_TX_DRV_LVL (0x001C)
-
-#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN (0x004)
-
-/* DP MMSS_CC registers */
-#define MMSS_DP_LINK_CMD_RCGR (0x0138)
-#define MMSS_DP_LINK_CFG_RCGR (0x013C)
-#define MMSS_DP_PIXEL_M (0x0174)
-#define MMSS_DP_PIXEL_N (0x0178)
-
-/* DP HDCP 1.3 registers */
-#define DP_HDCP_CTRL (0x0A0)
-#define DP_HDCP_STATUS (0x0A4)
-#define DP_HDCP_SW_UPPER_AKSV (0x298)
-#define DP_HDCP_SW_LOWER_AKSV (0x29C)
-#define DP_HDCP_ENTROPY_CTRL0 (0x750)
-#define DP_HDCP_ENTROPY_CTRL1 (0x75C)
-#define DP_HDCP_SHA_STATUS (0x0C8)
-#define DP_HDCP_RCVPORT_DATA2_0 (0x0B0)
-#define DP_HDCP_RCVPORT_DATA3 (0x2A4)
-#define DP_HDCP_RCVPORT_DATA4 (0x2A8)
-#define DP_HDCP_RCVPORT_DATA5 (0x0C0)
-#define DP_HDCP_RCVPORT_DATA6 (0x0C4)
-
-#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_CTRL (0x024)
-#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_DATA (0x028)
-#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA0 (0x004)
-#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA1 (0x008)
-#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA7 (0x00C)
-#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA8 (0x010)
-#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA9 (0x014)
-#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA10 (0x018)
-#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA11 (0x01C)
-#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA12 (0x020)
+#include "dp_reg.h"
#define dp_read(offset) readl_relaxed((offset))
#define dp_write(offset, data) writel_relaxed((data), (offset))
@@ -248,9 +59,12 @@
{0xFF, 0xFF, 0xFF, 0xFF} /* sw1, 1.2 v, optional */
};
+/* audio related catalog functions */
struct dp_catalog_private {
struct device *dev;
struct dp_io *io;
+
+ u32 (*audio_map)[DP_AUDIO_SDP_HEADER_MAX];
struct dp_catalog dp_catalog;
};
@@ -364,11 +178,37 @@
dp_write(base + DP_AUX_CTRL, aux_ctrl);
}
-static void dp_catalog_aux_setup(struct dp_catalog_aux *aux, u32 *aux_cfg)
+static void dp_catalog_aux_update_cfg(struct dp_catalog_aux *aux,
+ struct dp_aux_cfg *cfg, enum dp_phy_aux_config_type type)
{
struct dp_catalog_private *catalog;
+ u32 new_index = 0, current_index = 0;
- if (!aux || !aux_cfg) {
+ if (!aux || !cfg || (type >= PHY_AUX_CFG_MAX)) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ dp_catalog_get_priv(aux);
+
+ current_index = cfg[type].current_index;
+ new_index = (current_index + 1) % cfg[type].cfg_cnt;
+ pr_debug("Updating %s from 0x%08x to 0x%08x\n",
+ dp_phy_aux_config_type_to_string(type),
+ cfg[type].lut[current_index], cfg[type].lut[new_index]);
+
+ dp_write(catalog->io->phy_io.base + cfg[type].offset,
+ cfg[type].lut[new_index]);
+ cfg[type].current_index = new_index;
+}
+
+static void dp_catalog_aux_setup(struct dp_catalog_aux *aux,
+ struct dp_aux_cfg *cfg)
+{
+ struct dp_catalog_private *catalog;
+ int i = 0;
+
+ if (!aux || !cfg) {
pr_err("invalid input\n");
return;
}
@@ -384,16 +224,13 @@
QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x3f);
/* DP AUX CFG register programming */
- dp_write(catalog->io->phy_io.base + DP_PHY_AUX_CFG0, aux_cfg[0]);
- dp_write(catalog->io->phy_io.base + DP_PHY_AUX_CFG1, aux_cfg[1]);
- dp_write(catalog->io->phy_io.base + DP_PHY_AUX_CFG2, aux_cfg[2]);
- dp_write(catalog->io->phy_io.base + DP_PHY_AUX_CFG3, aux_cfg[3]);
- dp_write(catalog->io->phy_io.base + DP_PHY_AUX_CFG4, aux_cfg[4]);
- dp_write(catalog->io->phy_io.base + DP_PHY_AUX_CFG5, aux_cfg[5]);
- dp_write(catalog->io->phy_io.base + DP_PHY_AUX_CFG6, aux_cfg[6]);
- dp_write(catalog->io->phy_io.base + DP_PHY_AUX_CFG7, aux_cfg[7]);
- dp_write(catalog->io->phy_io.base + DP_PHY_AUX_CFG8, aux_cfg[8]);
- dp_write(catalog->io->phy_io.base + DP_PHY_AUX_CFG9, aux_cfg[9]);
+ for (i = 0; i < PHY_AUX_CFG_MAX; i++) {
+ pr_debug("%s: offset=0x%08x, value=0x%08x\n",
+ dp_phy_aux_config_type_to_string(i),
+ cfg[i].offset, cfg[i].lut[cfg[i].current_index]);
+ dp_write(catalog->io->phy_io.base + cfg[i].offset,
+ cfg[i].lut[cfg[i].current_index]);
+ }
dp_write(catalog->io->phy_io.base + DP_PHY_AUX_INTERRUPT_MASK, 0x1F);
}
@@ -424,6 +261,22 @@
}
/* controller related catalog functions */
+static u32 dp_catalog_ctrl_read_hdcp_status(struct dp_catalog_ctrl *ctrl)
+{
+ struct dp_catalog_private *catalog;
+ void __iomem *base;
+
+ if (!ctrl) {
+ pr_err("invalid input\n");
+ return -EINVAL;
+ }
+
+ dp_catalog_get_priv(ctrl);
+ base = catalog->io->ctrl_io.base;
+
+ return dp_read(base + DP_HDCP_STATUS);
+}
+
static void dp_catalog_ctrl_update_transfer_unit(struct dp_catalog_ctrl *ctrl)
{
struct dp_catalog_private *catalog;
@@ -548,10 +401,13 @@
}
static void dp_catalog_ctrl_config_msa(struct dp_catalog_ctrl *ctrl,
- u32 rate)
+ u32 rate, u32 stream_rate_khz,
+ bool fixed_nvid)
{
u32 pixel_m, pixel_n;
u32 mvid, nvid;
+ u64 mvid_calc;
+ u32 const nvid_fixed = 0x8000;
u32 const link_rate = 540000;
struct dp_catalog_private *catalog;
void __iomem *base_cc, *base_ctrl;
@@ -562,21 +418,42 @@
}
dp_catalog_get_priv(ctrl);
- base_cc = catalog->io->dp_cc_io.base;
+ if (fixed_nvid) {
+ pr_debug("use fixed NVID=0x%x\n", nvid_fixed);
+ nvid = nvid_fixed;
+
+ pr_debug("link rate=%dkbps, stream_rate_khz=%uKhz",
+ rate, stream_rate_khz);
+
+ /*
+ * For intermediate results, use 64 bit arithmetic to avoid
+ * loss of precision.
+ */
+ mvid_calc = (u64) stream_rate_khz * nvid;
+ mvid_calc = div_u64(mvid_calc, rate);
+
+ /*
+ * truncate back to 32 bits as this final divided value will
+ * always be within the range of a 32 bit unsigned int.
+ */
+ mvid = (u32) mvid_calc;
+ } else {
+ base_cc = catalog->io->dp_cc_io.base;
+
+ pixel_m = dp_read(base_cc + MMSS_DP_PIXEL_M);
+ pixel_n = dp_read(base_cc + MMSS_DP_PIXEL_N);
+ pr_debug("pixel_m=0x%x, pixel_n=0x%x\n", pixel_m, pixel_n);
+
+ mvid = (pixel_m & 0xFFFF) * 5;
+ nvid = (0xFFFF & (~pixel_n)) + (pixel_m & 0xFFFF);
+
+ pr_debug("rate = %d\n", rate);
+
+ if (link_rate == rate)
+ nvid *= 2;
+ }
+
base_ctrl = catalog->io->ctrl_io.base;
-
- pixel_m = dp_read(base_cc + MMSS_DP_PIXEL_M);
- pixel_n = dp_read(base_cc + MMSS_DP_PIXEL_N);
- pr_debug("pixel_m=0x%x, pixel_n=0x%x\n", pixel_m, pixel_n);
-
- mvid = (pixel_m & 0xFFFF) * 5;
- nvid = (0xFFFF & (~pixel_n)) + (pixel_m & 0xFFFF);
-
- pr_debug("rate = %d\n", rate);
-
- if (link_rate == rate)
- nvid *= 2;
-
pr_debug("mvid=0x%x, nvid=0x%x\n", mvid, nvid);
dp_write(base_ctrl + DP_SOFTWARE_MVID, mvid);
dp_write(base_ctrl + DP_SOFTWARE_NVID, nvid);
@@ -850,40 +727,190 @@
end:
return 0;
}
- /* audio related catalog functions */
-static int dp_catalog_audio_acr_ctrl(struct dp_catalog_audio *audio)
+
+static void dp_catalog_audio_init(struct dp_catalog_audio *audio)
{
- return 0;
+ struct dp_catalog_private *catalog;
+ static u32 sdp_map[][DP_AUDIO_SDP_HEADER_MAX] = {
+ {
+ MMSS_DP_AUDIO_STREAM_0,
+ MMSS_DP_AUDIO_STREAM_1,
+ MMSS_DP_AUDIO_STREAM_1,
+ },
+ {
+ MMSS_DP_AUDIO_TIMESTAMP_0,
+ MMSS_DP_AUDIO_TIMESTAMP_1,
+ MMSS_DP_AUDIO_TIMESTAMP_1,
+ },
+ {
+ MMSS_DP_AUDIO_INFOFRAME_0,
+ MMSS_DP_AUDIO_INFOFRAME_1,
+ MMSS_DP_AUDIO_INFOFRAME_1,
+ },
+ {
+ MMSS_DP_AUDIO_COPYMANAGEMENT_0,
+ MMSS_DP_AUDIO_COPYMANAGEMENT_1,
+ MMSS_DP_AUDIO_COPYMANAGEMENT_1,
+ },
+ {
+ MMSS_DP_AUDIO_ISRC_0,
+ MMSS_DP_AUDIO_ISRC_1,
+ MMSS_DP_AUDIO_ISRC_1,
+ },
+ };
+
+ if (!audio)
+ return;
+
+ dp_catalog_get_priv(audio);
+
+ catalog->audio_map = sdp_map;
}
-static int dp_catalog_audio_stream_sdp(struct dp_catalog_audio *audio)
+static void dp_catalog_audio_config_sdp(struct dp_catalog_audio *audio)
{
- return 0;
+ struct dp_catalog_private *catalog;
+ void __iomem *base;
+ u32 sdp_cfg = 0;
+ u32 sdp_cfg2 = 0;
+
+ if (!audio)
+ return;
+
+ dp_catalog_get_priv(audio);
+ base = catalog->io->ctrl_io.base;
+
+ /* AUDIO_TIMESTAMP_SDP_EN */
+ sdp_cfg |= BIT(1);
+ /* AUDIO_STREAM_SDP_EN */
+ sdp_cfg |= BIT(2);
+ /* AUDIO_COPY_MANAGEMENT_SDP_EN */
+ sdp_cfg |= BIT(5);
+ /* AUDIO_ISRC_SDP_EN */
+ sdp_cfg |= BIT(6);
+ /* AUDIO_INFOFRAME_SDP_EN */
+ sdp_cfg |= BIT(20);
+
+ pr_debug("sdp_cfg = 0x%x\n", sdp_cfg);
+ dp_write(base + MMSS_DP_SDP_CFG, sdp_cfg);
+
+ sdp_cfg2 = dp_read(base + MMSS_DP_SDP_CFG2);
+ /* IFRM_REGSRC -> Do not use reg values */
+ sdp_cfg2 &= ~BIT(0);
+ /* AUDIO_STREAM_HB3_REGSRC-> Do not use reg values */
+ sdp_cfg2 &= ~BIT(1);
+
+ pr_debug("sdp_cfg2 = 0x%x\n", sdp_cfg2);
+ dp_write(base + MMSS_DP_SDP_CFG2, sdp_cfg2);
}
-static int dp_catalog_audio_timestamp_sdp(struct dp_catalog_audio *audio)
+static void dp_catalog_audio_get_header(struct dp_catalog_audio *audio)
{
- return 0;
+ struct dp_catalog_private *catalog;
+ u32 (*sdp_map)[DP_AUDIO_SDP_HEADER_MAX];
+ void __iomem *base;
+ enum dp_catalog_audio_sdp_type sdp;
+ enum dp_catalog_audio_header_type header;
+
+ if (!audio)
+ return;
+
+ dp_catalog_get_priv(audio);
+
+ base = catalog->io->ctrl_io.base;
+ sdp_map = catalog->audio_map;
+ sdp = audio->sdp_type;
+ header = audio->sdp_header;
+
+ audio->data = dp_read(base + sdp_map[sdp][header]);
}
-static int dp_catalog_audio_infoframe_sdp(struct dp_catalog_audio *audio)
+static void dp_catalog_audio_set_header(struct dp_catalog_audio *audio)
{
- return 0;
+ struct dp_catalog_private *catalog;
+ u32 (*sdp_map)[DP_AUDIO_SDP_HEADER_MAX];
+ void __iomem *base;
+ enum dp_catalog_audio_sdp_type sdp;
+ enum dp_catalog_audio_header_type header;
+ u32 data;
+
+ if (!audio)
+ return;
+
+ dp_catalog_get_priv(audio);
+
+ base = catalog->io->ctrl_io.base;
+ sdp_map = catalog->audio_map;
+ sdp = audio->sdp_type;
+ header = audio->sdp_header;
+ data = audio->data;
+
+ dp_write(base + sdp_map[sdp][header], data);
}
-static int dp_catalog_audio_copy_mgmt_sdp(struct dp_catalog_audio *audio)
+static void dp_catalog_audio_config_acr(struct dp_catalog_audio *audio)
{
- return 0;
+ struct dp_catalog_private *catalog;
+ void __iomem *base;
+ u32 acr_ctrl, select;
+
+ dp_catalog_get_priv(audio);
+
+ select = audio->data;
+ base = catalog->io->ctrl_io.base;
+
+ acr_ctrl = select << 4 | BIT(31) | BIT(8) | BIT(14);
+
+ pr_debug("select = 0x%x, acr_ctrl = 0x%x\n", select, acr_ctrl);
+
+ dp_write(base + MMSS_DP_AUDIO_ACR_CTRL, acr_ctrl);
}
-static int dp_catalog_audio_isrc_sdp(struct dp_catalog_audio *audio)
+static void dp_catalog_audio_safe_to_exit_level(struct dp_catalog_audio *audio)
{
- return 0;
+ struct dp_catalog_private *catalog;
+ void __iomem *base;
+ u32 mainlink_levels, safe_to_exit_level;
+
+ dp_catalog_get_priv(audio);
+
+ base = catalog->io->ctrl_io.base;
+ safe_to_exit_level = audio->data;
+
+ mainlink_levels = dp_read(base + DP_MAINLINK_LEVELS);
+ mainlink_levels &= 0xFE0;
+ mainlink_levels |= safe_to_exit_level;
+
+ pr_debug("mainlink_level = 0x%x, safe_to_exit_level = 0x%x\n",
+ mainlink_levels, safe_to_exit_level);
+
+ dp_write(base + DP_MAINLINK_LEVELS, mainlink_levels);
}
-static int dp_catalog_audio_setup_sdp(struct dp_catalog_audio *audio)
+static void dp_catalog_audio_enable(struct dp_catalog_audio *audio)
{
- return 0;
+ struct dp_catalog_private *catalog;
+ void __iomem *base;
+ bool enable;
+ u32 audio_ctrl;
+
+ dp_catalog_get_priv(audio);
+
+ base = catalog->io->ctrl_io.base;
+ enable = !!audio->data;
+
+ audio_ctrl = dp_read(base + MMSS_DP_AUDIO_CFG);
+
+ if (enable)
+ audio_ctrl |= BIT(0);
+ else
+ audio_ctrl &= ~BIT(0);
+
+ pr_debug("dp_audio_cfg = 0x%x\n", audio_ctrl);
+ dp_write(base + MMSS_DP_AUDIO_CFG, audio_ctrl);
+
+ /* make sure audio engine is disabled */
+ wmb();
}
struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_io *io)
@@ -896,6 +923,7 @@
.write_data = dp_catalog_aux_write_data,
.write_trans = dp_catalog_aux_write_trans,
.reset = dp_catalog_aux_reset,
+ .update_aux_cfg = dp_catalog_aux_update_cfg,
.enable = dp_catalog_aux_enable,
.setup = dp_catalog_aux_setup,
.get_irq = dp_catalog_aux_get_irq,
@@ -917,15 +945,16 @@
.update_vx_px = dp_catalog_ctrl_update_vx_px,
.get_interrupt = dp_catalog_ctrl_get_interrupt,
.update_transfer_unit = dp_catalog_ctrl_update_transfer_unit,
+ .read_hdcp_status = dp_catalog_ctrl_read_hdcp_status,
};
struct dp_catalog_audio audio = {
- .acr_ctrl = dp_catalog_audio_acr_ctrl,
- .stream_sdp = dp_catalog_audio_stream_sdp,
- .timestamp_sdp = dp_catalog_audio_timestamp_sdp,
- .infoframe_sdp = dp_catalog_audio_infoframe_sdp,
- .copy_mgmt_sdp = dp_catalog_audio_copy_mgmt_sdp,
- .isrc_sdp = dp_catalog_audio_isrc_sdp,
- .setup_sdp = dp_catalog_audio_setup_sdp,
+ .init = dp_catalog_audio_init,
+ .config_acr = dp_catalog_audio_config_acr,
+ .enable = dp_catalog_audio_enable,
+ .config_sdp = dp_catalog_audio_config_sdp,
+ .set_header = dp_catalog_audio_set_header,
+ .get_header = dp_catalog_audio_get_header,
+ .safe_to_exit_level = dp_catalog_audio_safe_to_exit_level,
};
struct dp_catalog_panel panel = {
.timing_cfg = dp_catalog_panel_timing_cfg,
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h b/drivers/gpu/drm/msm/dp/dp_catalog.h
index c9916c72..47c10bf 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.h
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.h
@@ -43,7 +43,10 @@
int (*write_trans)(struct dp_catalog_aux *aux);
void (*reset)(struct dp_catalog_aux *aux);
void (*enable)(struct dp_catalog_aux *aux, bool enable);
- void (*setup)(struct dp_catalog_aux *aux, u32 *aux_cfg);
+ void (*update_aux_cfg)(struct dp_catalog_aux *aux,
+ struct dp_aux_cfg *cfg, enum dp_phy_aux_config_type type);
+ void (*setup)(struct dp_catalog_aux *aux,
+ struct dp_aux_cfg *aux_cfg);
void (*get_irq)(struct dp_catalog_aux *aux, bool cmd_busy);
};
@@ -58,7 +61,8 @@
void (*lane_mapping)(struct dp_catalog_ctrl *ctrl);
void (*mainlink_ctrl)(struct dp_catalog_ctrl *ctrl, bool enable);
void (*config_misc)(struct dp_catalog_ctrl *ctrl, u32 cc, u32 tb);
- void (*config_msa)(struct dp_catalog_ctrl *ctrl, u32 rate);
+ void (*config_msa)(struct dp_catalog_ctrl *ctrl, u32 rate,
+ u32 stream_rate_khz, bool fixed_nvid);
void (*set_pattern)(struct dp_catalog_ctrl *ctrl, u32 pattern);
void (*reset)(struct dp_catalog_ctrl *ctrl);
bool (*mainlink_ready)(struct dp_catalog_ctrl *ctrl);
@@ -71,18 +75,37 @@
u8 p_level);
void (*get_interrupt)(struct dp_catalog_ctrl *ctrl);
void (*update_transfer_unit)(struct dp_catalog_ctrl *ctrl);
+ u32 (*read_hdcp_status)(struct dp_catalog_ctrl *ctrl);
+};
+
+enum dp_catalog_audio_sdp_type {
+ DP_AUDIO_SDP_STREAM,
+ DP_AUDIO_SDP_TIMESTAMP,
+ DP_AUDIO_SDP_INFOFRAME,
+ DP_AUDIO_SDP_COPYMANAGEMENT,
+ DP_AUDIO_SDP_ISRC,
+ DP_AUDIO_SDP_MAX,
+};
+
+enum dp_catalog_audio_header_type {
+ DP_AUDIO_SDP_HEADER_1,
+ DP_AUDIO_SDP_HEADER_2,
+ DP_AUDIO_SDP_HEADER_3,
+ DP_AUDIO_SDP_HEADER_MAX,
};
struct dp_catalog_audio {
+ enum dp_catalog_audio_sdp_type sdp_type;
+ enum dp_catalog_audio_header_type sdp_header;
u32 data;
- int (*acr_ctrl)(struct dp_catalog_audio *audio);
- int (*stream_sdp)(struct dp_catalog_audio *audio);
- int (*timestamp_sdp)(struct dp_catalog_audio *audio);
- int (*infoframe_sdp)(struct dp_catalog_audio *audio);
- int (*copy_mgmt_sdp)(struct dp_catalog_audio *audio);
- int (*isrc_sdp)(struct dp_catalog_audio *audio);
- int (*setup_sdp)(struct dp_catalog_audio *audio);
+ void (*init)(struct dp_catalog_audio *audio);
+ void (*enable)(struct dp_catalog_audio *audio);
+ void (*config_acr)(struct dp_catalog_audio *audio);
+ void (*config_sdp)(struct dp_catalog_audio *audio);
+ void (*set_header)(struct dp_catalog_audio *audio);
+ void (*get_header)(struct dp_catalog_audio *audio);
+ void (*safe_to_exit_level)(struct dp_catalog_audio *audio);
};
struct dp_catalog_panel {
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index b78f0df..51abcf5 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -1129,6 +1129,24 @@
pr_debug("Host deinitialized successfully\n");
}
+static bool dp_ctrl_use_fixed_nvid(struct dp_ctrl_private *ctrl)
+{
+ u8 *dpcd = ctrl->panel->dpcd;
+
+ /*
+ * For better interop experience, used a fixed NVID=0x8000
+ * whenever connected to a VGA dongle downstream.
+ */
+ if (dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT) {
+ u8 type = dpcd[DP_DOWNSTREAMPORT_PRESENT] &
+ DP_DWN_STRM_PORT_TYPE_MASK;
+ if (type == DP_DWN_STRM_PORT_TYPE_ANALOG)
+ return true;
+ }
+
+ return false;
+}
+
static int dp_ctrl_on_irq(struct dp_ctrl_private *ctrl, bool lt_needed)
{
int ret = 0;
@@ -1158,7 +1176,8 @@
dp_ctrl_configure_source_params(ctrl);
ctrl->catalog->config_msa(ctrl->catalog,
- drm_dp_bw_code_to_link_rate(ctrl->link->bw_code));
+ drm_dp_bw_code_to_link_rate(ctrl->link->bw_code),
+ ctrl->pixel_rate, dp_ctrl_use_fixed_nvid(ctrl));
reinit_completion(&ctrl->idle_comp);
@@ -1212,7 +1231,8 @@
while (--link_train_max_retries && !atomic_read(&ctrl->aborted)) {
ctrl->catalog->config_msa(ctrl->catalog,
- drm_dp_bw_code_to_link_rate(ctrl->link->bw_code));
+ drm_dp_bw_code_to_link_rate(ctrl->link->bw_code),
+ ctrl->pixel_rate, dp_ctrl_use_fixed_nvid(ctrl));
ret = dp_ctrl_setup_main_link(ctrl, true);
if (!ret)
diff --git a/drivers/gpu/drm/msm/dp/dp_debug.c b/drivers/gpu/drm/msm/dp/dp_debug.c
new file mode 100644
index 0000000..82e34df
--- /dev/null
+++ b/drivers/gpu/drm/msm/dp/dp_debug.c
@@ -0,0 +1,498 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. 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 and
+ * only 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.
+ *
+ */
+
+#define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__
+
+#include <linux/debugfs.h>
+
+#include "dp_parser.h"
+#include "dp_power.h"
+#include "dp_catalog.h"
+#include "dp_aux.h"
+#include "dp_ctrl.h"
+#include "dp_debug.h"
+#include "drm_connector.h"
+#include "dp_display.h"
+
+#define DEBUG_NAME "drm_dp"
+
+struct dp_debug_private {
+ struct dentry *root;
+
+ struct dp_usbpd *usbpd;
+ struct dp_link *link;
+ struct dp_panel *panel;
+ struct drm_connector **connector;
+ struct device *dev;
+
+ struct dp_debug dp_debug;
+};
+
+static ssize_t dp_debug_write_hpd(struct file *file,
+ const char __user *user_buff, size_t count, loff_t *ppos)
+{
+ struct dp_debug_private *debug = file->private_data;
+ char buf[SZ_8];
+ size_t len = 0;
+ int hpd;
+
+ if (!debug)
+ return -ENODEV;
+
+ if (*ppos)
+ return 0;
+
+ /* Leave room for termination char */
+ len = min_t(size_t, count, SZ_8 - 1);
+ if (copy_from_user(buf, user_buff, len))
+ goto end;
+
+ buf[len] = '\0';
+
+ if (kstrtoint(buf, 10, &hpd) != 0)
+ goto end;
+
+ debug->usbpd->connect(debug->usbpd, hpd);
+end:
+ return -len;
+}
+
+static ssize_t dp_debug_write_edid_modes(struct file *file,
+ const char __user *user_buff, size_t count, loff_t *ppos)
+{
+ struct dp_debug_private *debug = file->private_data;
+ char buf[SZ_32];
+ size_t len = 0;
+ int hdisplay = 0, vdisplay = 0, vrefresh = 0;
+
+ if (!debug)
+ return -ENODEV;
+
+ if (*ppos)
+ goto end;
+
+ /* Leave room for termination char */
+ len = min_t(size_t, count, SZ_32 - 1);
+ if (copy_from_user(buf, user_buff, len))
+ goto clear;
+
+ buf[len] = '\0';
+
+ if (sscanf(buf, "%d %d %d", &hdisplay, &vdisplay, &vrefresh) != 3)
+ goto clear;
+
+ if (!hdisplay || !vdisplay || !vrefresh)
+ goto clear;
+
+ debug->dp_debug.debug_en = true;
+ debug->dp_debug.hdisplay = hdisplay;
+ debug->dp_debug.vdisplay = vdisplay;
+ debug->dp_debug.vrefresh = vrefresh;
+ goto end;
+clear:
+ pr_debug("clearing debug modes\n");
+ debug->dp_debug.debug_en = false;
+end:
+ return len;
+}
+
+static ssize_t dp_debug_read_connected(struct file *file,
+ char __user *user_buff, size_t count, loff_t *ppos)
+{
+ struct dp_debug_private *debug = file->private_data;
+ char buf[SZ_8];
+ u32 len = 0;
+
+ if (!debug)
+ return -ENODEV;
+
+ if (*ppos)
+ return 0;
+
+ len += snprintf(buf, SZ_8, "%d\n", debug->usbpd->hpd_high);
+
+ if (copy_to_user(user_buff, buf, len))
+ return -EFAULT;
+
+ *ppos += len;
+ return len;
+}
+
+static ssize_t dp_debug_read_edid_modes(struct file *file,
+ char __user *user_buff, size_t count, loff_t *ppos)
+{
+ struct dp_debug_private *debug = file->private_data;
+ char *buf;
+ u32 len = 0;
+ int rc = 0;
+ struct drm_connector *connector;
+ struct drm_display_mode *mode;
+
+ if (!debug) {
+ pr_err("invalid data\n");
+ rc = -ENODEV;
+ goto error;
+ }
+
+ connector = *debug->connector;
+
+ if (!connector) {
+ pr_err("connector is NULL\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ if (*ppos)
+ goto error;
+
+ buf = kzalloc(SZ_4K, GFP_KERNEL);
+ if (!buf) {
+ rc = -ENOMEM;
+ goto error;
+ }
+
+ list_for_each_entry(mode, &connector->modes, head) {
+ len += snprintf(buf + len, SZ_4K - len,
+ "%s %d %d %d %d %d %d %d %d %d 0x%x\n",
+ mode->name, mode->vrefresh, mode->hdisplay,
+ mode->hsync_start, mode->hsync_end, mode->htotal,
+ mode->vdisplay, mode->vsync_start, mode->vsync_end,
+ mode->vtotal, mode->flags);
+ }
+
+ if (copy_to_user(user_buff, buf, len)) {
+ kfree(buf);
+ rc = -EFAULT;
+ goto error;
+ }
+
+ *ppos += len;
+ kfree(buf);
+
+ return len;
+error:
+ return rc;
+}
+
+static int dp_debug_check_buffer_overflow(int rc, int *max_size, int *len)
+{
+ if (rc >= *max_size) {
+ pr_err("buffer overflow\n");
+ return -EINVAL;
+ }
+ *len += rc;
+ *max_size = SZ_4K - *len;
+
+ return 0;
+}
+
+static ssize_t dp_debug_read_info(struct file *file, char __user *user_buff,
+ size_t count, loff_t *ppos)
+{
+ struct dp_debug_private *debug = file->private_data;
+ char *buf;
+ u32 len = 0, rc = 0;
+ u64 lclk = 0;
+ u32 max_size = SZ_4K;
+
+ if (!debug)
+ return -ENODEV;
+
+ if (*ppos)
+ return 0;
+
+ buf = kzalloc(SZ_4K, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ rc = snprintf(buf + len, max_size, "\tname = %s\n", DEBUG_NAME);
+ if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+ goto error;
+
+ rc = snprintf(buf + len, max_size,
+ "\tdp_panel\n\t\tmax_pclk_khz = %d\n",
+ debug->panel->max_pclk_khz);
+ if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+ goto error;
+
+ rc = snprintf(buf + len, max_size,
+ "\tdrm_dp_link\n\t\trate = %u\n",
+ debug->panel->link_info.rate);
+ if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+ goto error;
+
+ rc = snprintf(buf + len, max_size,
+ "\t\tnum_lanes = %u\n",
+ debug->panel->link_info.num_lanes);
+ if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+ goto error;
+
+ rc = snprintf(buf + len, max_size,
+ "\t\tcapabilities = %lu\n",
+ debug->panel->link_info.capabilities);
+ if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+ goto error;
+
+ rc = snprintf(buf + len, max_size,
+ "\tdp_panel_info:\n\t\tactive = %dx%d\n",
+ debug->panel->pinfo.h_active,
+ debug->panel->pinfo.v_active);
+ if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+ goto error;
+
+ rc = snprintf(buf + len, max_size,
+ "\t\tback_porch = %dx%d\n",
+ debug->panel->pinfo.h_back_porch,
+ debug->panel->pinfo.v_back_porch);
+ if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+ goto error;
+
+ rc = snprintf(buf + len, max_size,
+ "\t\tfront_porch = %dx%d\n",
+ debug->panel->pinfo.h_front_porch,
+ debug->panel->pinfo.v_front_porch);
+ if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+ goto error;
+
+ rc = snprintf(buf + len, max_size,
+ "\t\tsync_width = %dx%d\n",
+ debug->panel->pinfo.h_sync_width,
+ debug->panel->pinfo.v_sync_width);
+ if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+ goto error;
+
+ rc = snprintf(buf + len, max_size,
+ "\t\tactive_low = %dx%d\n",
+ debug->panel->pinfo.h_active_low,
+ debug->panel->pinfo.v_active_low);
+ if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+ goto error;
+
+ rc = snprintf(buf + len, max_size,
+ "\t\th_skew = %d\n",
+ debug->panel->pinfo.h_skew);
+ if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+ goto error;
+
+ rc = snprintf(buf + len, max_size,
+ "\t\trefresh rate = %d\n",
+ debug->panel->pinfo.refresh_rate);
+ if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+ goto error;
+
+ rc = snprintf(buf + len, max_size,
+ "\t\tpixel clock khz = %d\n",
+ debug->panel->pinfo.pixel_clk_khz);
+ if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+ goto error;
+
+ rc = snprintf(buf + len, max_size,
+ "\t\tbpp = %d\n",
+ debug->panel->pinfo.bpp);
+ if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+ goto error;
+
+ /* Link Information */
+ rc = snprintf(buf + len, max_size,
+ "\tdp_link:\n\t\ttest_requested = %d\n",
+ debug->link->test_requested);
+ if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+ goto error;
+
+ rc = snprintf(buf + len, max_size,
+ "\t\tlane_count = %d\n", debug->link->lane_count);
+ if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+ goto error;
+
+ rc = snprintf(buf + len, max_size,
+ "\t\tbw_code = %d\n", debug->link->bw_code);
+ if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+ goto error;
+
+ lclk = drm_dp_bw_code_to_link_rate(debug->link->bw_code) * 1000;
+ rc = snprintf(buf + len, max_size,
+ "\t\tlclk = %lld\n", lclk);
+ if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+ goto error;
+
+ rc = snprintf(buf + len, max_size,
+ "\t\tv_level = %d\n", debug->link->v_level);
+ if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+ goto error;
+
+ rc = snprintf(buf + len, max_size,
+ "\t\tp_level = %d\n", debug->link->p_level);
+ if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+ goto error;
+
+ if (copy_to_user(user_buff, buf, len))
+ goto error;
+
+ *ppos += len;
+
+ kfree(buf);
+ return len;
+error:
+ kfree(buf);
+ return -EINVAL;
+}
+
+static const struct file_operations dp_debug_fops = {
+ .open = simple_open,
+ .read = dp_debug_read_info,
+};
+
+static const struct file_operations edid_modes_fops = {
+ .open = simple_open,
+ .read = dp_debug_read_edid_modes,
+ .write = dp_debug_write_edid_modes,
+};
+
+static const struct file_operations hpd_fops = {
+ .open = simple_open,
+ .write = dp_debug_write_hpd,
+};
+
+static const struct file_operations connected_fops = {
+ .open = simple_open,
+ .read = dp_debug_read_connected,
+};
+
+static int dp_debug_init(struct dp_debug *dp_debug)
+{
+ int rc = 0;
+ struct dp_debug_private *debug = container_of(dp_debug,
+ struct dp_debug_private, dp_debug);
+ struct dentry *dir, *file, *edid_modes;
+ struct dentry *hpd, *connected;
+ struct dentry *root = debug->root;
+
+ dir = debugfs_create_dir(DEBUG_NAME, NULL);
+ if (IS_ERR_OR_NULL(dir)) {
+ rc = PTR_ERR(dir);
+ pr_err("[%s] debugfs create dir failed, rc = %d\n",
+ DEBUG_NAME, rc);
+ goto error;
+ }
+
+ file = debugfs_create_file("dp_debug", 0444, dir,
+ debug, &dp_debug_fops);
+ if (IS_ERR_OR_NULL(file)) {
+ rc = PTR_ERR(file);
+ pr_err("[%s] debugfs create file failed, rc=%d\n",
+ DEBUG_NAME, rc);
+ goto error_remove_dir;
+ }
+
+ edid_modes = debugfs_create_file("edid_modes", 0644, dir,
+ debug, &edid_modes_fops);
+ if (IS_ERR_OR_NULL(edid_modes)) {
+ rc = PTR_ERR(edid_modes);
+ pr_err("[%s] debugfs create edid_modes failed, rc=%d\n",
+ DEBUG_NAME, rc);
+ goto error_remove_dir;
+ }
+
+ hpd = debugfs_create_file("hpd", 0644, dir,
+ debug, &hpd_fops);
+ if (IS_ERR_OR_NULL(hpd)) {
+ rc = PTR_ERR(hpd);
+ pr_err("[%s] debugfs hpd failed, rc=%d\n",
+ DEBUG_NAME, rc);
+ goto error_remove_dir;
+ }
+
+ connected = debugfs_create_file("connected", 0444, dir,
+ debug, &connected_fops);
+ if (IS_ERR_OR_NULL(connected)) {
+ rc = PTR_ERR(connected);
+ pr_err("[%s] debugfs connected failed, rc=%d\n",
+ DEBUG_NAME, rc);
+ goto error_remove_dir;
+ }
+
+ root = dir;
+ return rc;
+error_remove_dir:
+ debugfs_remove(dir);
+error:
+ return rc;
+}
+
+struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel,
+ struct dp_usbpd *usbpd, struct dp_link *link,
+ struct drm_connector **connector)
+{
+ int rc = 0;
+ struct dp_debug_private *debug;
+ struct dp_debug *dp_debug;
+
+ if (!dev || !panel || !usbpd || !link) {
+ pr_err("invalid input\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ debug = devm_kzalloc(dev, sizeof(*debug), GFP_KERNEL);
+ if (!debug) {
+ rc = -ENOMEM;
+ goto error;
+ }
+
+ debug->dp_debug.debug_en = false;
+ debug->usbpd = usbpd;
+ debug->link = link;
+ debug->panel = panel;
+ debug->dev = dev;
+ debug->connector = connector;
+
+ dp_debug = &debug->dp_debug;
+ dp_debug->vdisplay = 0;
+ dp_debug->hdisplay = 0;
+ dp_debug->vrefresh = 0;
+
+ dp_debug_init(dp_debug);
+
+ return dp_debug;
+error:
+ return ERR_PTR(rc);
+}
+
+static int dp_debug_deinit(struct dp_debug *dp_debug)
+{
+ struct dp_debug_private *debug;
+
+ if (!dp_debug)
+ return -EINVAL;
+
+ debug = container_of(dp_debug, struct dp_debug_private, dp_debug);
+
+ debugfs_remove(debug->root);
+
+ return 0;
+}
+
+void dp_debug_put(struct dp_debug *dp_debug)
+{
+ struct dp_debug_private *debug;
+
+ if (!dp_debug)
+ return;
+
+ debug = container_of(dp_debug, struct dp_debug_private, dp_debug);
+
+ dp_debug_deinit(dp_debug);
+
+ kzfree(debug);
+}
diff --git a/drivers/gpu/drm/msm/dp/dp_debug.h b/drivers/gpu/drm/msm/dp/dp_debug.h
new file mode 100644
index 0000000..7fd5330
--- /dev/null
+++ b/drivers/gpu/drm/msm/dp/dp_debug.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. 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 and
+ * only 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 _DP_DEBUG_H_
+#define _DP_DEBUG_H_
+
+#include "dp_panel.h"
+#include "dp_link.h"
+#include "dp_usbpd.h"
+
+/**
+ * struct dp_debug
+ * @debug_en: specifies whether debug mode enabled
+ * @vdisplay: used to filter out vdisplay value
+ * @hdisplay: used to filter out hdisplay value
+ * @vrefresh: used to filter out vrefresh value
+ */
+struct dp_debug {
+ bool debug_en;
+ int vdisplay;
+ int hdisplay;
+ int vrefresh;
+};
+
+/**
+ * dp_debug_get() - configure and get the DisplayPlot debug module data
+ *
+ * @dev: device instance of the caller
+ * @panel: instance of panel module
+ * @usbpd: instance of usbpd module
+ * @link: instance of link module
+ * @connector: double pointer to display connector
+ * return: pointer to allocated debug module data
+ *
+ * This function sets up the debug module and provides a way
+ * for debugfs input to be communicated with existing modules
+ */
+struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel,
+ struct dp_usbpd *usbpd, struct dp_link *link,
+ struct drm_connector **connector);
+/**
+ * dp_debug_put()
+ *
+ * Cleans up dp_debug instance
+ *
+ * @dp_debug: instance of dp_debug
+ */
+void dp_debug_put(struct dp_debug *dp_debug);
+#endif /* _DP_DEBUG_H_ */
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index b45cf4d..4dcf3b4 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -20,6 +20,7 @@
#include <linux/debugfs.h>
#include <linux/component.h>
#include <linux/of_irq.h>
+#include <linux/hdcp_qseecom.h>
#include "msm_drv.h"
#include "dp_usbpd.h"
@@ -30,10 +31,28 @@
#include "dp_link.h"
#include "dp_panel.h"
#include "dp_ctrl.h"
+#include "dp_audio.h"
#include "dp_display.h"
+#include "sde_hdcp.h"
+#include "dp_debug.h"
static struct dp_display *g_dp_display;
+struct dp_hdcp {
+ void *data;
+ struct sde_hdcp_ops *ops;
+
+ void *hdcp1;
+ void *hdcp2;
+
+ int enc_lvl;
+
+ bool auth_state;
+ bool hdcp1_present;
+ bool hdcp2_present;
+ bool feature_enabled;
+};
+
struct dp_display_private {
char *name;
int irq;
@@ -42,6 +61,7 @@
bool core_initialized;
bool power_on;
bool hpd_irq_on;
+ bool audio_supported;
struct platform_device *pdev;
struct dentry *root;
@@ -55,10 +75,19 @@
struct dp_link *link;
struct dp_panel *panel;
struct dp_ctrl *ctrl;
+ struct dp_audio *audio;
+ struct dp_debug *debug;
+
+ struct dp_hdcp hdcp;
struct dp_usbpd_cb usbpd_cb;
struct dp_display_mode mode;
struct dp_display dp_display;
+
+ struct workqueue_struct *hdcp_workqueue;
+ struct delayed_work hdcp_cb_work;
+ struct mutex hdcp_mutex;
+ int hdcp_status;
};
static const struct of_device_id dp_dt_match[] = {
@@ -66,6 +95,13 @@
{}
};
+static inline bool dp_display_is_hdcp_enabled(struct dp_display_private *dp)
+{
+ return dp->hdcp.feature_enabled &&
+ (dp->hdcp.hdcp1_present || dp->hdcp.hdcp2_present) &&
+ dp->hdcp.ops;
+}
+
static irqreturn_t dp_display_irq(int irq, void *dev_id)
{
struct dp_display_private *dp = dev_id;
@@ -81,81 +117,220 @@
/* DP aux isr */
dp->aux->isr(dp->aux);
+ /* HDCP isr */
+ if (dp_display_is_hdcp_enabled(dp) && dp->hdcp.ops->isr) {
+ if (dp->hdcp.ops->isr(dp->hdcp.data))
+ pr_err("dp_hdcp_isr failed\n");
+ }
+
return IRQ_HANDLED;
}
-static ssize_t debugfs_dp_info_read(struct file *file, char __user *buff,
- size_t count, loff_t *ppos)
+static void dp_display_hdcp_cb_work(struct work_struct *work)
{
- struct dp_display_private *dp = file->private_data;
- char *buf;
- u32 len = 0;
+ struct dp_display_private *dp;
+ struct delayed_work *dw = to_delayed_work(work);
+ struct sde_hdcp_ops *ops;
+ int rc = 0;
+ u32 hdcp_auth_state;
- if (!dp)
- return -ENODEV;
+ dp = container_of(dw, struct dp_display_private, hdcp_cb_work);
- if (*ppos)
- return 0;
-
- buf = kzalloc(SZ_4K, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- len += snprintf(buf + len, (SZ_4K - len), "name = %s\n", dp->name);
- len += snprintf(buf + len, (SZ_4K - len),
- "\tResolution = %dx%d\n",
- dp->panel->pinfo.h_active,
- dp->panel->pinfo.v_active);
-
- if (copy_to_user(buff, buf, len)) {
- kfree(buf);
- return -EFAULT;
+ rc = dp->catalog->ctrl.read_hdcp_status(&dp->catalog->ctrl);
+ if (rc >= 0) {
+ hdcp_auth_state = (rc >> 20) & 0x3;
+ pr_debug("hdcp auth state %d\n", hdcp_auth_state);
}
- *ppos += len;
+ ops = dp->hdcp.ops;
- kfree(buf);
- return len;
+ switch (dp->hdcp_status) {
+ case HDCP_STATE_AUTHENTICATING:
+ pr_debug("start authenticaton\n");
+
+ if (dp->hdcp.ops && dp->hdcp.ops->authenticate)
+ rc = dp->hdcp.ops->authenticate(dp->hdcp.data);
+
+ break;
+ case HDCP_STATE_AUTHENTICATED:
+ pr_debug("hdcp authenticated\n");
+ dp->hdcp.auth_state = true;
+ break;
+ case HDCP_STATE_AUTH_FAIL:
+ dp->hdcp.auth_state = false;
+
+ if (dp->power_on) {
+ pr_debug("Reauthenticating\n");
+ if (ops && ops->reauthenticate) {
+ rc = ops->reauthenticate(dp->hdcp.data);
+ if (rc)
+ pr_err("reauth failed rc=%d\n", rc);
+ }
+ } else {
+ pr_debug("not reauthenticating, cable disconnected\n");
+ }
+
+ break;
+ default:
+ break;
+ }
}
-static const struct file_operations dp_debug_fops = {
- .open = simple_open,
- .read = debugfs_dp_info_read,
-};
-
-static int dp_display_debugfs_init(struct dp_display_private *dp)
+static void dp_display_notify_hdcp_status_cb(void *ptr,
+ enum sde_hdcp_states status)
{
- int rc = 0;
- struct dentry *dir, *file;
+ struct dp_display_private *dp = ptr;
- dir = debugfs_create_dir(dp->name, NULL);
- if (IS_ERR_OR_NULL(dir)) {
- rc = PTR_ERR(dir);
- pr_err("[%s] debugfs create dir failed, rc = %d\n",
- dp->name, rc);
+ if (!dp) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ dp->hdcp_status = status;
+
+ if (dp->dp_display.is_connected)
+ queue_delayed_work(dp->hdcp_workqueue, &dp->hdcp_cb_work, HZ/4);
+}
+
+static int dp_display_create_hdcp_workqueue(struct dp_display_private *dp)
+{
+ dp->hdcp_workqueue = create_workqueue("sdm_dp_hdcp");
+ if (IS_ERR_OR_NULL(dp->hdcp_workqueue)) {
+ pr_err("Error creating hdcp_workqueue\n");
+ return -EPERM;
+ }
+
+ INIT_DELAYED_WORK(&dp->hdcp_cb_work, dp_display_hdcp_cb_work);
+
+ return 0;
+}
+
+static void dp_display_destroy_hdcp_workqueue(struct dp_display_private *dp)
+{
+ if (dp->hdcp_workqueue)
+ destroy_workqueue(dp->hdcp_workqueue);
+}
+
+static void dp_display_update_hdcp_info(struct dp_display_private *dp)
+{
+ void *fd = NULL;
+ struct sde_hdcp_ops *ops = NULL;
+
+ if (!dp) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ if (!dp->hdcp.feature_enabled) {
+ pr_debug("feature not enabled\n");
+ return;
+ }
+
+ fd = dp->hdcp.hdcp2;
+ if (fd)
+ ops = sde_dp_hdcp2p2_start(fd);
+
+ if (ops && ops->feature_supported)
+ dp->hdcp.hdcp2_present = ops->feature_supported(fd);
+ else
+ dp->hdcp.hdcp2_present = false;
+
+ pr_debug("hdcp2p2: %s\n",
+ dp->hdcp.hdcp2_present ? "supported" : "not supported");
+
+ if (!dp->hdcp.hdcp2_present) {
+ dp->hdcp.hdcp1_present = hdcp1_check_if_supported_load_app();
+
+ if (dp->hdcp.hdcp1_present) {
+ fd = dp->hdcp.hdcp1;
+ ops = sde_hdcp_1x_start(fd);
+ }
+ }
+
+ pr_debug("hdcp1x: %s\n",
+ dp->hdcp.hdcp1_present ? "supported" : "not supported");
+
+ if (dp->hdcp.hdcp2_present || dp->hdcp.hdcp1_present) {
+ dp->hdcp.data = fd;
+ dp->hdcp.ops = ops;
+ } else {
+ dp->hdcp.data = NULL;
+ dp->hdcp.ops = NULL;
+ }
+}
+
+static void dp_display_deinitialize_hdcp(struct dp_display_private *dp)
+{
+ if (!dp) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ sde_dp_hdcp2p2_deinit(dp->hdcp.data);
+ dp_display_destroy_hdcp_workqueue(dp);
+ if (&dp->hdcp_mutex)
+ mutex_destroy(&dp->hdcp_mutex);
+}
+
+static int dp_display_initialize_hdcp(struct dp_display_private *dp)
+{
+ struct sde_hdcp_init_data hdcp_init_data;
+ struct resource *res;
+ int rc = 0;
+
+ if (!dp) {
+ pr_err("invalid input\n");
+ return -EINVAL;
+ }
+
+ mutex_init(&dp->hdcp_mutex);
+
+ rc = dp_display_create_hdcp_workqueue(dp);
+ if (rc) {
+ pr_err("Failed to create HDCP workqueue\n");
goto error;
}
- file = debugfs_create_file("dp_debug", 0444, dir, dp, &dp_debug_fops);
- if (IS_ERR_OR_NULL(file)) {
- rc = PTR_ERR(file);
- pr_err("[%s] debugfs create file failed, rc=%d\n",
- dp->name, rc);
- goto error_remove_dir;
+ res = platform_get_resource_byname(dp->pdev,
+ IORESOURCE_MEM, "dp_ctrl");
+ if (!res) {
+ pr_err("Error getting dp ctrl resource\n");
+ rc = -EINVAL;
+ goto error;
}
- dp->root = dir;
- return rc;
-error_remove_dir:
- debugfs_remove(dir);
-error:
- return rc;
-}
+ hdcp_init_data.phy_addr = res->start;
+ hdcp_init_data.client_id = HDCP_CLIENT_DP;
+ hdcp_init_data.drm_aux = dp->aux->drm_aux;
+ hdcp_init_data.cb_data = (void *)dp;
+ hdcp_init_data.workq = dp->hdcp_workqueue;
+ hdcp_init_data.mutex = &dp->hdcp_mutex;
+ hdcp_init_data.sec_access = true;
+ hdcp_init_data.notify_status = dp_display_notify_hdcp_status_cb;
+ hdcp_init_data.core_io = &dp->parser->io.ctrl_io;
+ hdcp_init_data.qfprom_io = &dp->parser->io.qfprom_io;
+ hdcp_init_data.hdcp_io = &dp->parser->io.hdcp_io;
+ hdcp_init_data.revision = &dp->panel->link_info.revision;
-static int dp_display_debugfs_deinit(struct dp_display_private *dp)
-{
- debugfs_remove(dp->root);
+ dp->hdcp.hdcp1 = sde_hdcp_1x_init(&hdcp_init_data);
+ if (IS_ERR_OR_NULL(dp->hdcp.hdcp1)) {
+ pr_err("Error initializing HDCP 1.x\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ pr_debug("HDCP 1.3 initialized\n");
+
+ dp->hdcp.hdcp2 = sde_dp_hdcp2p2_init(&hdcp_init_data);
+ if (!IS_ERR_OR_NULL(dp->hdcp.hdcp2))
+ pr_debug("HDCP 2.2 initialized\n");
+
+ dp->hdcp.feature_enabled = true;
+
return 0;
+error:
+ dp_display_deinitialize_hdcp(dp);
+ return rc;
}
static int dp_display_bind(struct device *dev, struct device *master,
@@ -186,12 +361,6 @@
dp->dp_display.drm_dev = drm;
priv = drm->dev_private;
- rc = dp_display_debugfs_init(dp);
- if (rc) {
- pr_err("[%s]Debugfs init failed, rc=%d\n", dp->name, rc);
- goto end;
- }
-
rc = dp->parser->parse(dp->parser);
if (rc) {
pr_err("device tree parsing failed\n");
@@ -215,6 +384,12 @@
pr_err("Power client create failed\n");
goto end;
}
+
+ rc = dp_display_initialize_hdcp(dp);
+ if (rc) {
+ pr_err("HDCP initialization failed\n");
+ goto end;
+ }
end:
return rc;
}
@@ -239,7 +414,7 @@
(void)dp->power->power_client_deinit(dp->power);
(void)dp->panel->sde_edid_deregister(dp->panel);
(void)dp->aux->drm_aux_deregister(dp->aux);
- (void)dp_display_debugfs_deinit(dp);
+ dp_display_deinitialize_hdcp(dp);
}
static const struct component_ops dp_display_comp_ops = {
@@ -251,13 +426,15 @@
{
int rc = 0;
u32 max_pclk_from_edid = 0;
+ struct edid *edid;
- rc = dp->panel->read_dpcd(dp->panel);
+ rc = dp->panel->read_sink_caps(dp->panel, dp->dp_display.connector);
if (rc)
return rc;
- sde_get_edid(dp->dp_display.connector, &dp->aux->drm_aux->ddc,
- (void **)&dp->panel->edid_ctrl);
+ edid = dp->panel->edid_ctrl->edid;
+
+ dp->audio_supported = drm_detect_monitor_audio(edid);
max_pclk_from_edid = dp->panel->get_max_pclk(dp->panel);
@@ -313,6 +490,14 @@
/* cancel any pending request */
dp->ctrl->abort(dp->ctrl);
+ if (dp_display_is_hdcp_enabled(dp) && dp->hdcp.ops->off) {
+ cancel_delayed_work_sync(&dp->hdcp_cb_work);
+ dp->hdcp.ops->off(dp->hdcp.data);
+ }
+
+ if (dp->audio_supported)
+ dp->audio->off(dp->audio);
+
dp->dp_display.is_connected = false;
drm_helper_hpd_irq_event(dp->dp_display.connector->dev);
@@ -368,6 +553,9 @@
/* cancel any pending request */
dp->ctrl->abort(dp->ctrl);
+ if (dp->audio_supported)
+ dp->audio->off(dp->audio);
+
dp->dp_display.is_connected = false;
drm_helper_hpd_irq_event(dp->dp_display.connector->dev);
@@ -408,6 +596,12 @@
if (dp->usbpd->hpd_irq) {
dp->hpd_irq_on = true;
+
+ if (dp_display_is_hdcp_enabled(dp) && dp->hdcp.ops->cp_irq) {
+ if (!dp->hdcp.ops->cp_irq(dp->hdcp.data))
+ goto end;
+ }
+
rc = dp->link->process_request(dp->link);
dp->hpd_irq_on = false;
if (!rc)
@@ -468,7 +662,7 @@
goto err;
}
- dp->aux = dp_aux_get(dev, &dp->catalog->aux);
+ dp->aux = dp_aux_get(dev, &dp->catalog->aux, dp->parser->aux_cfg);
if (IS_ERR(dp->aux)) {
rc = PTR_ERR(dp->aux);
pr_err("failed to initialize aux, rc = %d\n", rc);
@@ -502,6 +696,20 @@
pr_err("failed to initialize ctrl, rc = %d\n", rc);
goto err;
}
+
+ dp->audio = dp_audio_get(dp->pdev, dp->panel, &dp->catalog->audio);
+ if (IS_ERR(dp->audio)) {
+ rc = PTR_ERR(dp->audio);
+ pr_err("failed to initialize audio, rc = %d\n", rc);
+ }
+
+ dp->debug = dp_debug_get(dev, dp->panel, dp->usbpd,
+ dp->link, &dp->dp_display.connector);
+ if (IS_ERR(dp->debug)) {
+ rc = PTR_ERR(dp->debug);
+ pr_err("failed to initialize debug, rc = %d\n", rc);
+ goto err;
+ }
err:
return rc;
}
@@ -563,7 +771,23 @@
dp = container_of(dp_display, struct dp_display_private, dp_display);
+ if (dp->audio_supported) {
+ dp->audio->bw_code = dp->link->bw_code;
+ dp->audio->lane_count = dp->link->lane_count;
+ dp->audio->on(dp->audio);
+ }
+
complete_all(&dp->notification_comp);
+
+ dp_display_update_hdcp_info(dp);
+
+ if (dp_display_is_hdcp_enabled(dp)) {
+ cancel_delayed_work_sync(&dp->hdcp_cb_work);
+
+ dp->hdcp_status = HDCP_STATE_AUTHENTICATING;
+ queue_delayed_work(dp->hdcp_workqueue,
+ &dp->hdcp_cb_work, HZ / 2);
+ }
end:
return rc;
}
@@ -581,6 +805,14 @@
dp = container_of(dp_display, struct dp_display_private, dp_display);
+ if (dp_display_is_hdcp_enabled(dp)) {
+ dp->hdcp_status = HDCP_STATE_INACTIVE;
+
+ cancel_delayed_work_sync(&dp->hdcp_cb_work);
+ if (dp->hdcp.ops->off)
+ dp->hdcp.ops->off(dp->hdcp.data);
+ }
+
dp->ctrl->push_idle(dp->ctrl);
error:
return rc;
@@ -640,6 +872,20 @@
return 0;
}
+static struct dp_debug *dp_get_debug(struct dp_display *dp_display)
+{
+ struct dp_display_private *dp;
+
+ if (!dp_display) {
+ pr_err("invalid input\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ dp = container_of(dp_display, struct dp_display_private, dp_display);
+
+ return dp->debug;
+}
+
static int dp_display_unprepare(struct dp_display *dp)
{
return 0;
@@ -703,6 +949,7 @@
g_dp_display->prepare = dp_display_prepare;
g_dp_display->unprepare = dp_display_unprepare;
g_dp_display->request_irq = dp_request_irq;
+ g_dp_display->get_debug = dp_get_debug;
rc = component_add(&pdev->dev, &dp_display_comp_ops);
if (rc)
@@ -734,6 +981,7 @@
static void dp_display_deinit_sub_modules(struct dp_display_private *dp)
{
+ dp_audio_put(dp->audio);
dp_ctrl_put(dp->ctrl);
dp_link_put(dp->link);
dp_panel_put(dp->panel);
@@ -742,6 +990,7 @@
dp_catalog_put(dp->catalog);
dp_parser_put(dp->parser);
dp_usbpd_put(dp->usbpd);
+ dp_debug_put(dp->debug);
}
static int dp_display_remove(struct platform_device *pdev)
diff --git a/drivers/gpu/drm/msm/dp/dp_display.h b/drivers/gpu/drm/msm/dp/dp_display.h
index 3caa277..5943629 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.h
+++ b/drivers/gpu/drm/msm/dp/dp_display.h
@@ -45,6 +45,7 @@
int (*prepare)(struct dp_display *dp_display);
int (*unprepare)(struct dp_display *dp_display);
int (*request_irq)(struct dp_display *dp_display);
+ struct dp_debug *(*get_debug)(struct dp_display *dp_display);
};
int dp_display_get_num_of_displays(void);
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
index 91aafdd..802f295 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_drm.c
@@ -22,6 +22,7 @@
#include "msm_kms.h"
#include "sde_connector.h"
#include "dp_drm.h"
+#include "dp_debug.h"
#define to_dp_bridge(x) container_of((x), struct dp_bridge, base)
@@ -296,24 +297,30 @@
return 0;
}
-int dp_connector_get_topology(const struct drm_display_mode *drm_mode,
- struct msm_display_topology *topology, u32 max_mixer_width)
+int dp_connector_get_mode_info(const struct drm_display_mode *drm_mode,
+ struct msm_mode_info *mode_info, u32 max_mixer_width)
{
const u32 dual_lm = 2;
const u32 single_lm = 1;
const u32 single_intf = 1;
const u32 no_enc = 0;
+ struct msm_display_topology *topology;
- if (!drm_mode || !topology || !max_mixer_width) {
+ if (!drm_mode || !mode_info || !max_mixer_width) {
pr_err("invalid params\n");
return -EINVAL;
}
+ topology = &mode_info->topology;
topology->num_lm = (max_mixer_width <= drm_mode->hdisplay) ?
dual_lm : single_lm;
topology->num_enc = no_enc;
topology->num_intf = single_intf;
+ mode_info->frame_rate = drm_mode->vrefresh;
+ mode_info->vtotal = drm_mode->vtotal;
+ mode_info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_NONE;
+
return 0;
}
@@ -331,7 +338,6 @@
info->num_of_h_tiles = 1;
info->h_tile_instance[0] = 0;
info->is_connected = display->is_connected;
- info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_NONE;
info->capabilities = MSM_DISPLAY_CAP_VID_MODE | MSM_DISPLAY_CAP_EDID |
MSM_DISPLAY_CAP_HOT_PLUG;
@@ -451,6 +457,7 @@
void *display)
{
struct dp_display *dp_disp;
+ struct dp_debug *debug;
if (!mode || !display) {
pr_err("invalid params\n");
@@ -458,9 +465,20 @@
}
dp_disp = display;
+ debug = dp_disp->get_debug(dp_disp);
- if (mode->clock > dp_disp->max_pclk_khz)
- return MODE_BAD;
- else
- return MODE_OK;
+ if (debug->debug_en) {
+ if (mode->hdisplay == debug->hdisplay &&
+ mode->vdisplay == debug->vdisplay &&
+ mode->vrefresh == debug->vrefresh &&
+ mode->clock <= dp_disp->max_pclk_khz)
+ return MODE_OK;
+ else
+ return MODE_ERROR;
+ } else {
+ if (mode->clock > dp_disp->max_pclk_khz)
+ return MODE_BAD;
+ else
+ return MODE_OK;
+ }
}
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.h b/drivers/gpu/drm/msm/dp/dp_drm.h
index bef3758..5918df1 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.h
+++ b/drivers/gpu/drm/msm/dp/dp_drm.h
@@ -74,14 +74,14 @@
void *display);
/**
- * dp_connector_get_topology - retrieve current topology for the mode selected
+ * dp_connector_get_mode_info - retrieve information of the mode selected
* @drm_mode: Display mode set for the display
- * @topology: Out parameter. Topology for the mode.
+ * @mode_info: Out parameter. Information of the mode
* @max_mixer_width: max width supported by HW layer mixer
* Returns: zero on success
*/
-int dp_connector_get_topology(const struct drm_display_mode *drm_mode,
- struct msm_display_topology *topology,
+int dp_connector_get_mode_info(const struct drm_display_mode *drm_mode,
+ struct msm_mode_info *mode_info,
u32 max_mixer_width);
int dp_connector_get_info(struct msm_display_info *info, void *display);
diff --git a/drivers/gpu/drm/msm/dp/dp_hdcp2p2.c b/drivers/gpu/drm/msm/dp/dp_hdcp2p2.c
new file mode 100644
index 0000000..061acee
--- /dev/null
+++ b/drivers/gpu/drm/msm/dp/dp_hdcp2p2.c
@@ -0,0 +1,925 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+#define pr_fmt(fmt) "[dp-hdcp2p2] %s: " fmt, __func__
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/stat.h>
+#include <linux/types.h>
+#include <linux/kthread.h>
+#include <linux/hdcp_qseecom.h>
+#include <drm/drm_dp_helper.h>
+
+#include "sde_hdcp.h"
+
+#define DP_INTR_STATUS2 (0x00000024)
+#define DP_INTR_STATUS3 (0x00000028)
+#define dp_read(offset) readl_relaxed((offset))
+#define dp_write(offset, data) writel_relaxed((data), (offset))
+
+enum dp_hdcp2p2_sink_status {
+ SINK_DISCONNECTED,
+ SINK_CONNECTED
+};
+
+enum dp_auth_status {
+ DP_HDCP_AUTH_STATUS_FAILURE,
+ DP_HDCP_AUTH_STATUS_SUCCESS
+};
+
+struct dp_hdcp2p2_ctrl {
+ atomic_t auth_state;
+ enum dp_hdcp2p2_sink_status sink_status; /* Is sink connected */
+ struct dp_hdcp2p2_interrupts *intr;
+ struct sde_hdcp_init_data init_data;
+ struct mutex mutex; /* mutex to protect access to ctrl */
+ struct mutex msg_lock; /* mutex to protect access to msg buffer */
+ struct mutex wakeup_mutex; /* mutex to protect access to wakeup call*/
+ struct sde_hdcp_ops *ops;
+ void *lib_ctx; /* Handle to HDCP 2.2 Trustzone library */
+ struct hdcp_txmtr_ops *lib; /* Ops for driver to call into TZ */
+ enum hdcp_wakeup_cmd wakeup_cmd;
+ enum dp_auth_status auth_status;
+
+ struct task_struct *thread;
+ struct kthread_worker worker;
+ struct kthread_work status;
+ struct kthread_work auth;
+ struct kthread_work send_msg;
+ struct kthread_work recv_msg;
+ struct kthread_work link;
+ char *msg_buf;
+ uint32_t send_msg_len; /* length of all parameters in msg */
+ uint32_t timeout;
+ uint32_t num_messages;
+ struct hdcp_msg_part msg_part[HDCP_MAX_MESSAGE_PARTS];
+ u8 sink_rx_status;
+ u8 rx_status;
+ char abort_mask;
+
+ bool cp_irq_done;
+ bool polling;
+};
+
+struct dp_hdcp2p2_int_set {
+ u32 interrupt;
+ char *name;
+ void (*func)(struct dp_hdcp2p2_ctrl *ctrl);
+};
+
+struct dp_hdcp2p2_interrupts {
+ u32 reg;
+ struct dp_hdcp2p2_int_set *int_set;
+};
+
+static inline bool dp_hdcp2p2_is_valid_state(struct dp_hdcp2p2_ctrl *ctrl)
+{
+ if (ctrl->wakeup_cmd == HDCP_WKUP_CMD_AUTHENTICATE)
+ return true;
+
+ if (atomic_read(&ctrl->auth_state) != HDCP_STATE_INACTIVE)
+ return true;
+
+ return false;
+}
+
+static int dp_hdcp2p2_copy_buf(struct dp_hdcp2p2_ctrl *ctrl,
+ struct hdcp_wakeup_data *data)
+{
+ int i = 0;
+
+ if (!data || !data->message_data)
+ return 0;
+
+ mutex_lock(&ctrl->msg_lock);
+
+ ctrl->timeout = data->timeout;
+ ctrl->num_messages = data->message_data->num_messages;
+ ctrl->send_msg_len = 0; /* Total len of all messages */
+
+ for (i = 0; i < ctrl->num_messages ; i++)
+ ctrl->send_msg_len += data->message_data->messages[i].length;
+
+ memcpy(ctrl->msg_part, data->message_data->messages,
+ sizeof(data->message_data->messages));
+
+ ctrl->rx_status = data->message_data->rx_status;
+ ctrl->abort_mask = data->abort_mask;
+
+ if (!data->send_msg_len) {
+ mutex_unlock(&ctrl->msg_lock);
+ return 0;
+ }
+
+ kzfree(ctrl->msg_buf);
+
+ ctrl->msg_buf = kzalloc(ctrl->send_msg_len, GFP_KERNEL);
+
+ if (!ctrl->msg_buf) {
+ mutex_unlock(&ctrl->msg_lock);
+ return -ENOMEM;
+ }
+
+ /* ignore first byte as it contains message id */
+ memcpy(ctrl->msg_buf, data->send_msg_buf + 1, ctrl->send_msg_len);
+
+ mutex_unlock(&ctrl->msg_lock);
+
+ return 0;
+}
+
+static int dp_hdcp2p2_wakeup(struct hdcp_wakeup_data *data)
+{
+ struct dp_hdcp2p2_ctrl *ctrl;
+ u32 const default_timeout_us = 500;
+
+ if (!data) {
+ pr_err("invalid input\n");
+ return -EINVAL;
+ }
+
+ ctrl = data->context;
+ if (!ctrl) {
+ pr_err("invalid ctrl\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&ctrl->wakeup_mutex);
+
+ ctrl->wakeup_cmd = data->cmd;
+
+ if (data->timeout)
+ ctrl->timeout = (data->timeout) * 2;
+ else
+ ctrl->timeout = default_timeout_us;
+
+ if (!dp_hdcp2p2_is_valid_state(ctrl)) {
+ pr_err("invalid state\n");
+ goto exit;
+ }
+
+ if (dp_hdcp2p2_copy_buf(ctrl, data))
+ goto exit;
+
+ if (ctrl->wakeup_cmd == HDCP_WKUP_CMD_STATUS_SUCCESS)
+ ctrl->auth_status = DP_HDCP_AUTH_STATUS_SUCCESS;
+ else if (ctrl->wakeup_cmd == HDCP_WKUP_CMD_STATUS_FAILED)
+ ctrl->auth_status = DP_HDCP_AUTH_STATUS_FAILURE;
+
+ switch (ctrl->wakeup_cmd) {
+ case HDCP_WKUP_CMD_SEND_MESSAGE:
+ kthread_queue_work(&ctrl->worker, &ctrl->send_msg);
+ break;
+ case HDCP_WKUP_CMD_RECV_MESSAGE:
+ kthread_queue_work(&ctrl->worker, &ctrl->recv_msg);
+ break;
+ case HDCP_WKUP_CMD_STATUS_SUCCESS:
+ case HDCP_WKUP_CMD_STATUS_FAILED:
+ kthread_queue_work(&ctrl->worker, &ctrl->status);
+ break;
+ case HDCP_WKUP_CMD_LINK_POLL:
+ if (ctrl->cp_irq_done)
+ kthread_queue_work(&ctrl->worker, &ctrl->recv_msg);
+ else
+ ctrl->polling = true;
+ break;
+ case HDCP_WKUP_CMD_AUTHENTICATE:
+ kthread_queue_work(&ctrl->worker, &ctrl->auth);
+ break;
+ default:
+ pr_err("invalid wakeup command %d\n", ctrl->wakeup_cmd);
+ }
+exit:
+ mutex_unlock(&ctrl->wakeup_mutex);
+
+ return 0;
+}
+
+static inline void dp_hdcp2p2_wakeup_lib(struct dp_hdcp2p2_ctrl *ctrl,
+ struct hdcp_lib_wakeup_data *data)
+{
+ int rc = 0;
+
+ if (ctrl && ctrl->lib && ctrl->lib->wakeup &&
+ data && (data->cmd != HDCP_LIB_WKUP_CMD_INVALID)) {
+ rc = ctrl->lib->wakeup(data);
+ if (rc)
+ pr_err("error sending %s to lib\n",
+ hdcp_lib_cmd_to_str(data->cmd));
+ }
+}
+
+static void dp_hdcp2p2_reset(struct dp_hdcp2p2_ctrl *ctrl)
+{
+ if (!ctrl) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ ctrl->sink_status = SINK_DISCONNECTED;
+ atomic_set(&ctrl->auth_state, HDCP_STATE_INACTIVE);
+}
+
+static void dp_hdcp2p2_set_interrupts(struct dp_hdcp2p2_ctrl *ctrl, bool enable)
+{
+ void __iomem *base = ctrl->init_data.core_io->base;
+ struct dp_hdcp2p2_interrupts *intr = ctrl->intr;
+
+ while (intr && intr->reg) {
+ struct dp_hdcp2p2_int_set *int_set = intr->int_set;
+ u32 interrupts = 0;
+
+ while (int_set && int_set->interrupt) {
+ interrupts |= int_set->interrupt;
+ int_set++;
+ }
+
+ if (enable)
+ dp_write(base + intr->reg,
+ dp_read(base + intr->reg) | interrupts);
+ else
+ dp_write(base + intr->reg,
+ dp_read(base + intr->reg) & ~interrupts);
+ intr++;
+ }
+}
+
+static void dp_hdcp2p2_off(void *input)
+{
+ struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)input;
+ struct hdcp_wakeup_data cdata = {HDCP_WKUP_CMD_AUTHENTICATE};
+
+ if (!ctrl) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) {
+ pr_err("hdcp is off\n");
+ return;
+ }
+
+ dp_hdcp2p2_set_interrupts(ctrl, false);
+
+ dp_hdcp2p2_reset(ctrl);
+
+ kthread_flush_worker(&ctrl->worker);
+
+ cdata.context = input;
+ dp_hdcp2p2_wakeup(&cdata);
+}
+
+static int dp_hdcp2p2_authenticate(void *input)
+{
+ struct dp_hdcp2p2_ctrl *ctrl = input;
+ struct hdcp_wakeup_data cdata = {HDCP_WKUP_CMD_AUTHENTICATE};
+ int rc = 0;
+
+ kthread_flush_worker(&ctrl->worker);
+
+ dp_hdcp2p2_set_interrupts(ctrl, true);
+
+ ctrl->sink_status = SINK_CONNECTED;
+ atomic_set(&ctrl->auth_state, HDCP_STATE_AUTHENTICATING);
+
+ cdata.context = input;
+ dp_hdcp2p2_wakeup(&cdata);
+
+ return rc;
+}
+
+static int dp_hdcp2p2_reauthenticate(void *input)
+{
+ struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)input;
+
+ if (!ctrl) {
+ pr_err("invalid input\n");
+ return -EINVAL;
+ }
+
+ dp_hdcp2p2_reset((struct dp_hdcp2p2_ctrl *)input);
+
+ return dp_hdcp2p2_authenticate(input);
+}
+
+static void dp_hdcp2p2_min_level_change(void *client_ctx,
+ int min_enc_level)
+{
+ struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)client_ctx;
+ struct hdcp_lib_wakeup_data cdata = {
+ HDCP_LIB_WKUP_CMD_QUERY_STREAM_TYPE};
+ bool enc_notify = true;
+ int enc_lvl;
+
+ if (!ctrl) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ switch (min_enc_level) {
+ case 0:
+ enc_lvl = HDCP_STATE_AUTH_ENC_NONE;
+ break;
+ case 1:
+ enc_lvl = HDCP_STATE_AUTH_ENC_1X;
+ break;
+ case 2:
+ enc_lvl = HDCP_STATE_AUTH_ENC_2P2;
+ break;
+ default:
+ enc_notify = false;
+ }
+
+ pr_debug("enc level changed %d\n", min_enc_level);
+
+ cdata.context = ctrl->lib_ctx;
+ dp_hdcp2p2_wakeup_lib(ctrl, &cdata);
+
+ if (enc_notify && ctrl->init_data.notify_status)
+ ctrl->init_data.notify_status(ctrl->init_data.cb_data, enc_lvl);
+}
+
+static void dp_hdcp2p2_auth_failed(struct dp_hdcp2p2_ctrl *ctrl)
+{
+ if (!ctrl) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ dp_hdcp2p2_set_interrupts(ctrl, false);
+
+ atomic_set(&ctrl->auth_state, HDCP_STATE_AUTH_FAIL);
+
+ /* notify DP about HDCP failure */
+ ctrl->init_data.notify_status(ctrl->init_data.cb_data,
+ HDCP_STATE_AUTH_FAIL);
+}
+
+static int dp_hdcp2p2_aux_read_message(struct dp_hdcp2p2_ctrl *ctrl,
+ u8 *buf, int size, int offset, u32 timeout)
+{
+ int const max_size = 16;
+ int rc = 0, read_size = 0, bytes_read = 0;
+
+ if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) {
+ pr_err("hdcp is off\n");
+ return -EINVAL;
+ }
+
+ do {
+ read_size = min(size, max_size);
+
+ bytes_read = drm_dp_dpcd_read(ctrl->init_data.drm_aux,
+ offset, buf, read_size);
+ if (bytes_read != read_size) {
+ pr_err("fail: offset(0x%x), size(0x%x), rc(0x%x)\n",
+ offset, read_size, bytes_read);
+ break;
+ }
+
+ buf += read_size;
+ offset += read_size;
+ size -= read_size;
+ } while (size > 0);
+
+ return rc;
+}
+
+static int dp_hdcp2p2_aux_write_message(struct dp_hdcp2p2_ctrl *ctrl,
+ u8 *buf, int size, uint offset, uint timeout)
+{
+ int const max_size = 16;
+ int rc = 0, write_size = 0, bytes_written = 0;
+
+ do {
+ write_size = min(size, max_size);
+
+ bytes_written = drm_dp_dpcd_write(ctrl->init_data.drm_aux,
+ offset, buf, write_size);
+ if (bytes_written != write_size) {
+ pr_err("fail: offset(0x%x), size(0x%x), rc(0x%x)\n",
+ offset, write_size, bytes_written);
+ break;
+ }
+
+ buf += write_size;
+ offset += write_size;
+ size -= write_size;
+ } while (size > 0);
+
+ return rc;
+}
+
+static bool dp_hdcp2p2_feature_supported(void *input)
+{
+ struct dp_hdcp2p2_ctrl *ctrl = input;
+ struct hdcp_txmtr_ops *lib = NULL;
+ bool supported = false;
+
+ if (!ctrl) {
+ pr_err("invalid input\n");
+ goto end;
+ }
+
+ lib = ctrl->lib;
+ if (!lib) {
+ pr_err("invalid lib ops data\n");
+ goto end;
+ }
+
+ if (lib->feature_supported)
+ supported = lib->feature_supported(
+ ctrl->lib_ctx);
+end:
+ return supported;
+}
+
+static void dp_hdcp2p2_send_msg_work(struct kthread_work *work)
+{
+ int rc = 0;
+ struct dp_hdcp2p2_ctrl *ctrl = container_of(work,
+ struct dp_hdcp2p2_ctrl, send_msg);
+ struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_INVALID};
+
+ if (!ctrl) {
+ pr_err("invalid input\n");
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ cdata.context = ctrl->lib_ctx;
+
+ if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) {
+ pr_err("hdcp is off\n");
+ goto exit;
+ }
+
+ mutex_lock(&ctrl->msg_lock);
+
+ rc = dp_hdcp2p2_aux_write_message(ctrl, ctrl->msg_buf,
+ ctrl->send_msg_len, ctrl->msg_part->offset,
+ ctrl->timeout);
+ if (rc) {
+ pr_err("Error sending msg to sink %d\n", rc);
+ mutex_unlock(&ctrl->msg_lock);
+ goto exit;
+ }
+
+ cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS;
+ cdata.timeout = ctrl->timeout;
+ mutex_unlock(&ctrl->msg_lock);
+
+exit:
+ if (rc == -ETIMEDOUT)
+ cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_RECV_TIMEOUT;
+ else if (rc)
+ cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_RECV_FAILED;
+
+ dp_hdcp2p2_wakeup_lib(ctrl, &cdata);
+}
+
+static int dp_hdcp2p2_get_msg_from_sink(struct dp_hdcp2p2_ctrl *ctrl)
+{
+ int rc = 0;
+ char *recvd_msg_buf = NULL;
+ struct hdcp_lib_wakeup_data cdata = { HDCP_LIB_WKUP_CMD_INVALID };
+
+ cdata.context = ctrl->lib_ctx;
+
+ recvd_msg_buf = kzalloc(ctrl->send_msg_len, GFP_KERNEL);
+ if (!recvd_msg_buf) {
+ rc = -ENOMEM;
+ goto exit;
+ }
+
+ rc = dp_hdcp2p2_aux_read_message(ctrl, recvd_msg_buf,
+ ctrl->send_msg_len, ctrl->msg_part->offset,
+ ctrl->timeout);
+ if (rc) {
+ pr_err("error reading message %d\n", rc);
+ goto exit;
+ }
+
+ cdata.recvd_msg_buf = recvd_msg_buf;
+ cdata.recvd_msg_len = ctrl->send_msg_len;
+ cdata.timeout = ctrl->timeout;
+exit:
+ if (rc == -ETIMEDOUT)
+ cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_RECV_TIMEOUT;
+ else if (rc)
+ cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_RECV_FAILED;
+ else
+ cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_RECV_SUCCESS;
+
+ dp_hdcp2p2_wakeup_lib(ctrl, &cdata);
+ kfree(recvd_msg_buf);
+
+ return rc;
+}
+
+static void dp_hdcp2p2_recv_msg_work(struct kthread_work *work)
+{
+ struct hdcp_lib_wakeup_data cdata = { HDCP_LIB_WKUP_CMD_INVALID };
+ struct dp_hdcp2p2_ctrl *ctrl = container_of(work,
+ struct dp_hdcp2p2_ctrl, recv_msg);
+
+ cdata.context = ctrl->lib_ctx;
+
+ if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) {
+ pr_err("hdcp is off\n");
+ return;
+ }
+
+ if (ctrl->rx_status) {
+ if (!ctrl->cp_irq_done) {
+ pr_debug("waiting for CP_IRQ\n");
+ ctrl->polling = true;
+ return;
+ }
+
+ if (ctrl->rx_status & ctrl->sink_rx_status) {
+ ctrl->cp_irq_done = false;
+ ctrl->sink_rx_status = 0;
+ ctrl->rx_status = 0;
+ }
+ }
+
+ dp_hdcp2p2_get_msg_from_sink(ctrl);
+}
+
+static void dp_hdcp2p2_auth_status_work(struct kthread_work *work)
+{
+ struct dp_hdcp2p2_ctrl *ctrl = container_of(work,
+ struct dp_hdcp2p2_ctrl, status);
+
+ if (!ctrl) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) {
+ pr_err("hdcp is off\n");
+ return;
+ }
+
+ if (ctrl->auth_status == DP_HDCP_AUTH_STATUS_SUCCESS) {
+ ctrl->init_data.notify_status(ctrl->init_data.cb_data,
+ HDCP_STATE_AUTHENTICATED);
+
+ atomic_set(&ctrl->auth_state, HDCP_STATE_AUTHENTICATED);
+ } else {
+ dp_hdcp2p2_auth_failed(ctrl);
+ }
+}
+
+static void dp_hdcp2p2_link_work(struct kthread_work *work)
+{
+ int rc = 0;
+ struct dp_hdcp2p2_ctrl *ctrl = container_of(work,
+ struct dp_hdcp2p2_ctrl, link);
+ struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_INVALID};
+
+ if (!ctrl) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ if (atomic_read(&ctrl->auth_state) == HDCP_STATE_AUTH_FAIL ||
+ atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) {
+ pr_err("invalid hdcp state\n");
+ return;
+ }
+
+ cdata.context = ctrl->lib_ctx;
+
+ if (ctrl->sink_rx_status & ctrl->abort_mask) {
+ if (ctrl->sink_rx_status & BIT(3))
+ pr_err("reauth_req set by sink\n");
+
+ if (ctrl->sink_rx_status & BIT(4))
+ pr_err("link failure reported by sink\n");
+
+ ctrl->sink_rx_status = 0;
+ ctrl->rx_status = 0;
+
+ rc = -ENOLINK;
+
+ cdata.cmd = HDCP_LIB_WKUP_CMD_LINK_FAILED;
+ atomic_set(&ctrl->auth_state, HDCP_STATE_AUTH_FAIL);
+ goto exit;
+ }
+
+ if (ctrl->polling && (ctrl->sink_rx_status & ctrl->rx_status)) {
+ ctrl->sink_rx_status = 0;
+ ctrl->rx_status = 0;
+
+ dp_hdcp2p2_get_msg_from_sink(ctrl);
+
+ ctrl->polling = false;
+ } else {
+ ctrl->cp_irq_done = true;
+ }
+exit:
+ if (rc)
+ dp_hdcp2p2_wakeup_lib(ctrl, &cdata);
+}
+
+static void dp_hdcp2p2_auth_work(struct kthread_work *work)
+{
+ struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_INVALID};
+ struct dp_hdcp2p2_ctrl *ctrl = container_of(work,
+ struct dp_hdcp2p2_ctrl, auth);
+
+ cdata.context = ctrl->lib_ctx;
+
+ if (atomic_read(&ctrl->auth_state) == HDCP_STATE_AUTHENTICATING)
+ cdata.cmd = HDCP_LIB_WKUP_CMD_START;
+ else
+ cdata.cmd = HDCP_LIB_WKUP_CMD_STOP;
+
+ dp_hdcp2p2_wakeup_lib(ctrl, &cdata);
+}
+
+static int dp_hdcp2p2_read_rx_status(struct dp_hdcp2p2_ctrl *ctrl,
+ u8 *rx_status)
+{
+ u32 const cp_irq_dpcd_offset = 0x201;
+ u32 const rxstatus_dpcd_offset = 0x69493;
+ ssize_t const bytes_to_read = 1;
+ ssize_t bytes_read = 0;
+ u8 buf = 0;
+ int rc = 0;
+ bool cp_irq = 0;
+
+ *rx_status = 0;
+
+ bytes_read = drm_dp_dpcd_read(ctrl->init_data.drm_aux,
+ cp_irq_dpcd_offset, &buf, bytes_to_read);
+ if (bytes_read != bytes_to_read) {
+ pr_err("cp irq read failed\n");
+ rc = bytes_read;
+ goto error;
+ }
+
+ cp_irq = buf & BIT(2);
+ pr_debug("cp_irq=0x%x\n", cp_irq);
+ buf = 0;
+
+ if (cp_irq) {
+ bytes_read = drm_dp_dpcd_read(ctrl->init_data.drm_aux,
+ rxstatus_dpcd_offset, &buf, bytes_to_read);
+ if (bytes_read != bytes_to_read) {
+ pr_err("rxstatus read failed\n");
+ rc = bytes_read;
+ goto error;
+ }
+ *rx_status = buf;
+ pr_debug("rx_status=0x%x\n", *rx_status);
+ }
+
+error:
+ return rc;
+}
+
+static int dp_hdcp2p2_cp_irq(void *input)
+{
+ int rc = 0;
+ struct dp_hdcp2p2_ctrl *ctrl = input;
+
+ if (!ctrl) {
+ pr_err("invalid input\n");
+ return -EINVAL;
+ }
+
+ if (atomic_read(&ctrl->auth_state) == HDCP_STATE_AUTH_FAIL ||
+ atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) {
+ pr_err("invalid hdcp state\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ ctrl->sink_rx_status = 0;
+ rc = dp_hdcp2p2_read_rx_status(ctrl, &ctrl->sink_rx_status);
+ if (rc) {
+ pr_err("failed to read rx status\n");
+ goto error;
+ }
+
+ pr_debug("sink_rx_status=0x%x\n", ctrl->sink_rx_status);
+
+ if (!ctrl->sink_rx_status) {
+ pr_debug("not a hdcp 2.2 irq\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ kthread_queue_work(&ctrl->worker, &ctrl->link);
+
+ return 0;
+error:
+ return rc;
+}
+
+static int dp_hdcp2p2_isr(void *input)
+{
+ struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)input;
+ int rc = 0;
+ struct dss_io_data *io;
+ struct dp_hdcp2p2_interrupts *intr;
+ u32 hdcp_int_val = 0;
+
+ if (!ctrl || !ctrl->init_data.core_io) {
+ pr_err("invalid input\n");
+ rc = -EINVAL;
+ goto end;
+ }
+
+ io = ctrl->init_data.core_io;
+ intr = ctrl->intr;
+
+ while (intr && intr->reg) {
+ struct dp_hdcp2p2_int_set *int_set = intr->int_set;
+
+ hdcp_int_val = dp_read(io->base + intr->reg);
+
+ while (int_set && int_set->interrupt) {
+ if (hdcp_int_val & (int_set->interrupt >> 2)) {
+ pr_debug("%s\n", int_set->name);
+
+ if (int_set->func)
+ int_set->func(ctrl);
+
+ dp_write(io->base + intr->reg, hdcp_int_val |
+ (int_set->interrupt >> 1));
+ }
+ int_set++;
+ }
+ intr++;
+ }
+end:
+ return rc;
+}
+
+void sde_dp_hdcp2p2_deinit(void *input)
+{
+ struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)input;
+ struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_INVALID};
+
+ if (!ctrl) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ cdata.cmd = HDCP_LIB_WKUP_CMD_STOP;
+ cdata.context = ctrl->lib_ctx;
+ dp_hdcp2p2_wakeup_lib(ctrl, &cdata);
+
+ kthread_stop(ctrl->thread);
+
+ mutex_destroy(&ctrl->mutex);
+ mutex_destroy(&ctrl->msg_lock);
+ mutex_destroy(&ctrl->wakeup_mutex);
+ kzfree(ctrl->msg_buf);
+ kfree(ctrl);
+}
+
+void *sde_dp_hdcp2p2_init(struct sde_hdcp_init_data *init_data)
+{
+ int rc;
+ struct dp_hdcp2p2_ctrl *ctrl;
+ static struct hdcp_txmtr_ops txmtr_ops;
+ struct hdcp_register_data register_data;
+ static struct sde_hdcp_ops ops = {
+ .isr = dp_hdcp2p2_isr,
+ .reauthenticate = dp_hdcp2p2_reauthenticate,
+ .authenticate = dp_hdcp2p2_authenticate,
+ .feature_supported = dp_hdcp2p2_feature_supported,
+ .off = dp_hdcp2p2_off,
+ .cp_irq = dp_hdcp2p2_cp_irq,
+ };
+
+ static struct hdcp_client_ops client_ops = {
+ .wakeup = dp_hdcp2p2_wakeup,
+ .notify_lvl_change = dp_hdcp2p2_min_level_change,
+ };
+ static struct dp_hdcp2p2_int_set int_set1[] = {
+ {BIT(17), "authentication successful", NULL},
+ {BIT(20), "authentication failed", NULL},
+ {BIT(24), "encryption enabled", NULL},
+ {BIT(27), "encryption disabled", NULL},
+ {0},
+ };
+ static struct dp_hdcp2p2_int_set int_set2[] = {
+ {BIT(2), "key fifo underflow", NULL},
+ {0},
+ };
+ static struct dp_hdcp2p2_interrupts intr[] = {
+ {DP_INTR_STATUS2, int_set1},
+ {DP_INTR_STATUS3, int_set2},
+ {0}
+ };
+
+ if (!init_data || !init_data->cb_data ||
+ !init_data->notify_status || !init_data->drm_aux) {
+ pr_err("invalid input\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
+ if (!ctrl)
+ return ERR_PTR(-ENOMEM);
+
+ ctrl->init_data = *init_data;
+ ctrl->lib = &txmtr_ops;
+ ctrl->msg_buf = NULL;
+
+ ctrl->sink_status = SINK_DISCONNECTED;
+ ctrl->intr = intr;
+
+ atomic_set(&ctrl->auth_state, HDCP_STATE_INACTIVE);
+
+ ctrl->ops = &ops;
+ mutex_init(&ctrl->mutex);
+ mutex_init(&ctrl->msg_lock);
+ mutex_init(&ctrl->wakeup_mutex);
+
+ register_data.hdcp_ctx = &ctrl->lib_ctx;
+ register_data.client_ops = &client_ops;
+ register_data.txmtr_ops = &txmtr_ops;
+ register_data.device_type = HDCP_TXMTR_DP;
+ register_data.client_ctx = ctrl;
+
+ rc = hdcp_library_register(®ister_data);
+ if (rc) {
+ pr_err("Unable to register with HDCP 2.2 library\n");
+ goto error;
+ }
+
+ kthread_init_worker(&ctrl->worker);
+
+ kthread_init_work(&ctrl->auth, dp_hdcp2p2_auth_work);
+ kthread_init_work(&ctrl->send_msg, dp_hdcp2p2_send_msg_work);
+ kthread_init_work(&ctrl->recv_msg, dp_hdcp2p2_recv_msg_work);
+ kthread_init_work(&ctrl->status, dp_hdcp2p2_auth_status_work);
+ kthread_init_work(&ctrl->link, dp_hdcp2p2_link_work);
+
+ ctrl->thread = kthread_run(kthread_worker_fn,
+ &ctrl->worker, "dp_hdcp2p2");
+
+ if (IS_ERR(ctrl->thread)) {
+ pr_err("unable to start DP hdcp2p2 thread\n");
+ rc = PTR_ERR(ctrl->thread);
+ ctrl->thread = NULL;
+ goto error;
+ }
+
+ return ctrl;
+error:
+ kfree(ctrl);
+ return ERR_PTR(rc);
+}
+
+static bool dp_hdcp2p2_supported(struct dp_hdcp2p2_ctrl *ctrl)
+{
+ u32 const rxcaps_dpcd_offset = 0x6921d;
+ ssize_t const bytes_to_read = 1;
+ ssize_t bytes_read = 0;
+ u8 buf = 0;
+
+ bytes_read = drm_dp_dpcd_read(ctrl->init_data.drm_aux,
+ rxcaps_dpcd_offset, &buf, bytes_to_read);
+ if (bytes_read != bytes_to_read) {
+ pr_err("RxCaps read failed\n");
+ goto error;
+ }
+
+ pr_debug("rxcaps 0x%x\n", buf);
+
+ if (buf & BIT(1))
+ return true;
+error:
+ return false;
+}
+
+struct sde_hdcp_ops *sde_dp_hdcp2p2_start(void *input)
+{
+ struct dp_hdcp2p2_ctrl *ctrl = input;
+
+ pr_debug("Checking sink capability\n");
+ if (dp_hdcp2p2_supported(ctrl))
+ return ctrl->ops;
+ else
+ return NULL;
+}
+
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c
index 5f25b2d..2e21033 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.c
+++ b/drivers/gpu/drm/msm/dp/dp_panel.c
@@ -28,6 +28,7 @@
struct dp_aux *aux;
struct dp_catalog_panel *catalog;
bool lane_switch_supported;
+ bool aux_cfg_update_done;
};
static int dp_panel_read_dpcd(struct dp_panel *dp_panel)
@@ -80,11 +81,76 @@
return rc;
}
+
+static int dp_panel_read_edid(struct dp_panel *dp_panel,
+ struct drm_connector *connector)
+{
+ int retry_cnt = 0;
+ const int max_retry = 10;
+ struct dp_panel_private *panel;
+
+ if (!dp_panel) {
+ pr_err("invalid input\n");
+ return -EINVAL;
+ }
+
+ panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
+
+ do {
+ sde_get_edid(connector, &panel->aux->drm_aux->ddc,
+ (void **)&dp_panel->edid_ctrl);
+ if (!dp_panel->edid_ctrl->edid) {
+ pr_err("EDID read failed\n");
+ retry_cnt++;
+ panel->aux->reconfig(panel->aux);
+ panel->aux_cfg_update_done = true;
+ } else {
+ return 0;
+ }
+ } while (retry_cnt < max_retry);
+
+ return -EINVAL;
+}
+
+static int dp_panel_read_sink_caps(struct dp_panel *dp_panel,
+ struct drm_connector *connector)
+{
+ int rc = 0;
+ struct dp_panel_private *panel;
+
+ if (!dp_panel || !connector) {
+ pr_err("invalid input\n");
+ return -EINVAL;
+ }
+
+ panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
+
+ rc = dp_panel_read_dpcd(dp_panel);
+ if (rc) {
+ pr_err("panel dpcd read failed\n");
+ return rc;
+ }
+
+ rc = dp_panel_read_edid(dp_panel, connector);
+ if (rc) {
+ pr_err("panel edid read failed\n");
+ return rc;
+ }
+
+ if (panel->aux_cfg_update_done) {
+ pr_debug("read DPCD with updated AUX config\n");
+ dp_panel_read_dpcd(dp_panel);
+ panel->aux_cfg_update_done = false;
+ }
+
+ return 0;
+}
+
static u32 dp_panel_get_max_pclk(struct dp_panel *dp_panel)
{
struct drm_dp_link *link_info;
const u8 num_components = 3;
- u32 bpc, bpp, max_data_rate_khz, max_pclk_rate_khz;
+ u32 bpc = 0, bpp = 0, max_data_rate_khz = 0, max_pclk_rate_khz = 0;
if (!dp_panel) {
pr_err("invalid input\n");
@@ -290,12 +356,13 @@
panel->catalog = catalog;
dp_panel = &panel->dp_panel;
+ panel->aux_cfg_update_done = false;
dp_panel->sde_edid_register = dp_panel_edid_register;
dp_panel->sde_edid_deregister = dp_panel_edid_deregister;
dp_panel->init_info = dp_panel_init_panel_info;
dp_panel->timing_cfg = dp_panel_timing_cfg;
- dp_panel->read_dpcd = dp_panel_read_dpcd;
+ dp_panel->read_sink_caps = dp_panel_read_sink_caps;
dp_panel->get_min_req_link_rate = dp_panel_get_min_req_link_rate;
dp_panel->get_max_pclk = dp_panel_get_max_pclk;
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h
index 6cca0f1..ab9a451 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.h
+++ b/drivers/gpu/drm/msm/dp/dp_panel.h
@@ -43,6 +43,7 @@
struct drm_dp_link link_info;
struct sde_edid_ctrl *edid_ctrl;
+ struct drm_connector *connector;
struct dp_panel_info pinfo;
u32 vic;
@@ -52,7 +53,8 @@
void (*sde_edid_deregister)(struct dp_panel *dp_panel);
int (*init_info)(struct dp_panel *dp_panel);
int (*timing_cfg)(struct dp_panel *dp_panel);
- int (*read_dpcd)(struct dp_panel *dp_panel);
+ int (*read_sink_caps)(struct dp_panel *dp_panel,
+ struct drm_connector *connector);
u32 (*get_min_req_link_rate)(struct dp_panel *dp_panel);
u32 (*get_max_pclk)(struct dp_panel *dp_panel);
};
diff --git a/drivers/gpu/drm/msm/dp/dp_parser.c b/drivers/gpu/drm/msm/dp/dp_parser.c
index e81bbb3..c85c2a2 100644
--- a/drivers/gpu/drm/msm/dp/dp_parser.c
+++ b/drivers/gpu/drm/msm/dp/dp_parser.c
@@ -101,23 +101,85 @@
return rc;
}
+static const char *dp_get_phy_aux_config_property(u32 cfg_type)
+{
+ switch (cfg_type) {
+ case PHY_AUX_CFG0:
+ return "qcom,aux-cfg0-settings";
+ case PHY_AUX_CFG1:
+ return "qcom,aux-cfg1-settings";
+ case PHY_AUX_CFG2:
+ return "qcom,aux-cfg2-settings";
+ case PHY_AUX_CFG3:
+ return "qcom,aux-cfg3-settings";
+ case PHY_AUX_CFG4:
+ return "qcom,aux-cfg4-settings";
+ case PHY_AUX_CFG5:
+ return "qcom,aux-cfg5-settings";
+ case PHY_AUX_CFG6:
+ return "qcom,aux-cfg6-settings";
+ case PHY_AUX_CFG7:
+ return "qcom,aux-cfg7-settings";
+ case PHY_AUX_CFG8:
+ return "qcom,aux-cfg8-settings";
+ case PHY_AUX_CFG9:
+ return "qcom,aux-cfg9-settings";
+ default:
+ return "unknown";
+ }
+}
+
+static void dp_parser_phy_aux_cfg_reset(struct dp_parser *parser)
+{
+ int i = 0;
+
+ for (i = 0; i < PHY_AUX_CFG_MAX; i++)
+ parser->aux_cfg[i] = (const struct dp_aux_cfg){ 0 };
+}
+
static int dp_parser_aux(struct dp_parser *parser)
{
- int len = 0, i = 0, rc = 0;
struct device_node *of_node = parser->pdev->dev.of_node;
+ int len = 0, i = 0, j = 0, config_count = 0;
const char *data;
+ int const minimum_config_count = 1;
- data = of_get_property(of_node, "qcom,aux-cfg-settings", &len);
- if (!data || (len != AUX_CFG_LEN)) {
- pr_err("Unable to read DP AUX CFG settings\n");
- rc = -EINVAL;
- goto end;
+ for (i = 0; i < PHY_AUX_CFG_MAX; i++) {
+ const char *property = dp_get_phy_aux_config_property(i);
+
+ data = of_get_property(of_node, property, &len);
+ if (!data) {
+ pr_err("Unable to read %s\n", property);
+ goto error;
+ }
+
+ config_count = len - 1;
+ if ((config_count < minimum_config_count) ||
+ (config_count > DP_AUX_CFG_MAX_VALUE_CNT)) {
+ pr_err("Invalid config count (%d) configs for %s\n",
+ config_count, property);
+ goto error;
+ }
+
+ parser->aux_cfg[i].offset = data[0];
+ parser->aux_cfg[i].cfg_cnt = config_count;
+ pr_debug("%s offset=0x%x, cfg_cnt=%d\n",
+ property,
+ parser->aux_cfg[i].offset,
+ parser->aux_cfg[i].cfg_cnt);
+ for (j = 1; j < len; j++) {
+ parser->aux_cfg[i].lut[j - 1] = data[j];
+ pr_debug("%s lut[%d]=0x%x\n",
+ property,
+ i,
+ parser->aux_cfg[i].lut[j - 1]);
+ }
}
+ return 0;
- for (i = 0; i < len; i++)
- parser->aux_cfg[i] = data[i];
-end:
- return rc;
+error:
+ dp_parser_phy_aux_cfg_reset(parser);
+ return -EINVAL;
}
static int dp_parser_misc(struct dp_parser *parser)
diff --git a/drivers/gpu/drm/msm/dp/dp_parser.h b/drivers/gpu/drm/msm/dp/dp_parser.h
index fdcdd3a..7794da5 100644
--- a/drivers/gpu/drm/msm/dp/dp_parser.h
+++ b/drivers/gpu/drm/msm/dp/dp_parser.h
@@ -93,6 +93,66 @@
struct pinctrl_state *state_suspend;
};
+#define DP_ENUM_STR(x) #x
+#define DP_AUX_CFG_MAX_VALUE_CNT 3
+/**
+ * struct dp_aux_cfg - DP's AUX configuration settings
+ *
+ * @cfg_cnt: count of the configurable settings for the AUX register
+ * @current_index: current index of the AUX config lut
+ * @offset: register offset of the AUX config register
+ * @lut: look up table for the AUX config values for this register
+ */
+struct dp_aux_cfg {
+ u32 cfg_cnt;
+ u32 current_index;
+ u32 offset;
+ u32 lut[DP_AUX_CFG_MAX_VALUE_CNT];
+};
+
+/* PHY AUX config registers */
+enum dp_phy_aux_config_type {
+ PHY_AUX_CFG0,
+ PHY_AUX_CFG1,
+ PHY_AUX_CFG2,
+ PHY_AUX_CFG3,
+ PHY_AUX_CFG4,
+ PHY_AUX_CFG5,
+ PHY_AUX_CFG6,
+ PHY_AUX_CFG7,
+ PHY_AUX_CFG8,
+ PHY_AUX_CFG9,
+ PHY_AUX_CFG_MAX,
+};
+
+static inline char *dp_phy_aux_config_type_to_string(u32 cfg_type)
+{
+ switch (cfg_type) {
+ case PHY_AUX_CFG0:
+ return DP_ENUM_STR(PHY_AUX_CFG0);
+ case PHY_AUX_CFG1:
+ return DP_ENUM_STR(PHY_AUX_CFG1);
+ case PHY_AUX_CFG2:
+ return DP_ENUM_STR(PHY_AUX_CFG2);
+ case PHY_AUX_CFG3:
+ return DP_ENUM_STR(PHY_AUX_CFG3);
+ case PHY_AUX_CFG4:
+ return DP_ENUM_STR(PHY_AUX_CFG4);
+ case PHY_AUX_CFG5:
+ return DP_ENUM_STR(PHY_AUX_CFG5);
+ case PHY_AUX_CFG6:
+ return DP_ENUM_STR(PHY_AUX_CFG6);
+ case PHY_AUX_CFG7:
+ return DP_ENUM_STR(PHY_AUX_CFG7);
+ case PHY_AUX_CFG8:
+ return DP_ENUM_STR(PHY_AUX_CFG8);
+ case PHY_AUX_CFG9:
+ return DP_ENUM_STR(PHY_AUX_CFG9);
+ default:
+ return "unknown";
+ }
+}
+
/**
* struct dp_parser - DP parser's data exposed to clients
*
@@ -111,7 +171,7 @@
struct dp_display_data disp_data;
u8 l_map[4];
- u32 aux_cfg[AUX_CFG_LEN];
+ struct dp_aux_cfg aux_cfg[AUX_CFG_LEN];
u32 max_pclk_khz;
int (*parse)(struct dp_parser *parser);
diff --git a/drivers/gpu/drm/msm/dp/dp_reg.h b/drivers/gpu/drm/msm/dp/dp_reg.h
new file mode 100644
index 0000000..30377a0
--- /dev/null
+++ b/drivers/gpu/drm/msm/dp/dp_reg.h
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. 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 and
+ * only 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 _DP_REG_H_
+#define _DP_REG_H_
+
+/* DP_TX Registers */
+#define DP_HW_VERSION (0x00000000)
+#define DP_SW_RESET (0x00000010)
+#define DP_PHY_CTRL (0x00000014)
+#define DP_CLK_CTRL (0x00000018)
+#define DP_CLK_ACTIVE (0x0000001C)
+#define DP_INTR_STATUS (0x00000020)
+#define DP_INTR_STATUS2 (0x00000024)
+#define DP_INTR_STATUS3 (0x00000028)
+
+#define DP_DP_HPD_CTRL (0x00000200)
+#define DP_DP_HPD_INT_STATUS (0x00000204)
+#define DP_DP_HPD_INT_ACK (0x00000208)
+#define DP_DP_HPD_INT_MASK (0x0000020C)
+#define DP_DP_HPD_REFTIMER (0x00000218)
+#define DP_DP_HPD_EVENT_TIME_0 (0x0000021C)
+#define DP_DP_HPD_EVENT_TIME_1 (0x00000220)
+#define DP_AUX_CTRL (0x00000230)
+#define DP_AUX_DATA (0x00000234)
+#define DP_AUX_TRANS_CTRL (0x00000238)
+#define DP_TIMEOUT_COUNT (0x0000023C)
+#define DP_AUX_LIMITS (0x00000240)
+#define DP_AUX_STATUS (0x00000244)
+
+#define DP_DPCD_CP_IRQ (0x201)
+#define DP_DPCD_RXSTATUS (0x69493)
+
+#define DP_INTERRUPT_TRANS_NUM (0x000002A0)
+
+#define DP_MAINLINK_CTRL (0x00000400)
+#define DP_STATE_CTRL (0x00000404)
+#define DP_CONFIGURATION_CTRL (0x00000408)
+#define DP_SOFTWARE_MVID (0x00000410)
+#define DP_SOFTWARE_NVID (0x00000418)
+#define DP_TOTAL_HOR_VER (0x0000041C)
+#define DP_START_HOR_VER_FROM_SYNC (0x00000420)
+#define DP_HSYNC_VSYNC_WIDTH_POLARITY (0x00000424)
+#define DP_ACTIVE_HOR_VER (0x00000428)
+#define DP_MISC1_MISC0 (0x0000042C)
+#define DP_VALID_BOUNDARY (0x00000430)
+#define DP_VALID_BOUNDARY_2 (0x00000434)
+#define DP_LOGICAL2PHYSCIAL_LANE_MAPPING (0x00000438)
+
+#define DP_MAINLINK_READY (0x00000440)
+#define DP_MAINLINK_LEVELS (0x00000444)
+#define DP_TU (0x0000044C)
+
+#define DP_HBR2_COMPLIANCE_SCRAMBLER_RESET (0x00000454)
+#define DP_TEST_80BIT_CUSTOM_PATTERN_REG0 (0x000004C0)
+#define DP_TEST_80BIT_CUSTOM_PATTERN_REG1 (0x000004C4)
+#define DP_TEST_80BIT_CUSTOM_PATTERN_REG2 (0x000004C8)
+
+#define MMSS_DP_MISC1_MISC0 (0x0000042C)
+#define MMSS_DP_AUDIO_TIMING_GEN (0x00000480)
+#define MMSS_DP_AUDIO_TIMING_RBR_32 (0x00000484)
+#define MMSS_DP_AUDIO_TIMING_HBR_32 (0x00000488)
+#define MMSS_DP_AUDIO_TIMING_RBR_44 (0x0000048C)
+#define MMSS_DP_AUDIO_TIMING_HBR_44 (0x00000490)
+#define MMSS_DP_AUDIO_TIMING_RBR_48 (0x00000494)
+#define MMSS_DP_AUDIO_TIMING_HBR_48 (0x00000498)
+
+#define MMSS_DP_PSR_CRC_RG (0x00000554)
+#define MMSS_DP_PSR_CRC_B (0x00000558)
+
+#define MMSS_DP_AUDIO_CFG (0x00000600)
+#define MMSS_DP_AUDIO_STATUS (0x00000604)
+#define MMSS_DP_AUDIO_PKT_CTRL (0x00000608)
+#define MMSS_DP_AUDIO_PKT_CTRL2 (0x0000060C)
+#define MMSS_DP_AUDIO_ACR_CTRL (0x00000610)
+#define MMSS_DP_AUDIO_CTRL_RESET (0x00000614)
+
+#define MMSS_DP_SDP_CFG (0x00000628)
+#define MMSS_DP_SDP_CFG2 (0x0000062C)
+#define MMSS_DP_AUDIO_TIMESTAMP_0 (0x00000630)
+#define MMSS_DP_AUDIO_TIMESTAMP_1 (0x00000634)
+
+#define MMSS_DP_AUDIO_STREAM_0 (0x00000640)
+#define MMSS_DP_AUDIO_STREAM_1 (0x00000644)
+
+#define MMSS_DP_EXTENSION_0 (0x00000650)
+#define MMSS_DP_EXTENSION_1 (0x00000654)
+#define MMSS_DP_EXTENSION_2 (0x00000658)
+#define MMSS_DP_EXTENSION_3 (0x0000065C)
+#define MMSS_DP_EXTENSION_4 (0x00000660)
+#define MMSS_DP_EXTENSION_5 (0x00000664)
+#define MMSS_DP_EXTENSION_6 (0x00000668)
+#define MMSS_DP_EXTENSION_7 (0x0000066C)
+#define MMSS_DP_EXTENSION_8 (0x00000670)
+#define MMSS_DP_EXTENSION_9 (0x00000674)
+#define MMSS_DP_AUDIO_COPYMANAGEMENT_0 (0x00000678)
+#define MMSS_DP_AUDIO_COPYMANAGEMENT_1 (0x0000067C)
+#define MMSS_DP_AUDIO_COPYMANAGEMENT_2 (0x00000680)
+#define MMSS_DP_AUDIO_COPYMANAGEMENT_3 (0x00000684)
+#define MMSS_DP_AUDIO_COPYMANAGEMENT_4 (0x00000688)
+#define MMSS_DP_AUDIO_COPYMANAGEMENT_5 (0x0000068C)
+#define MMSS_DP_AUDIO_ISRC_0 (0x00000690)
+#define MMSS_DP_AUDIO_ISRC_1 (0x00000694)
+#define MMSS_DP_AUDIO_ISRC_2 (0x00000698)
+#define MMSS_DP_AUDIO_ISRC_3 (0x0000069C)
+#define MMSS_DP_AUDIO_ISRC_4 (0x000006A0)
+#define MMSS_DP_AUDIO_ISRC_5 (0x000006A4)
+#define MMSS_DP_AUDIO_INFOFRAME_0 (0x000006A8)
+#define MMSS_DP_AUDIO_INFOFRAME_1 (0x000006AC)
+#define MMSS_DP_AUDIO_INFOFRAME_2 (0x000006B0)
+
+#define MMSS_DP_GENERIC0_0 (0x00000700)
+#define MMSS_DP_GENERIC0_1 (0x00000704)
+#define MMSS_DP_GENERIC0_2 (0x00000708)
+#define MMSS_DP_GENERIC0_3 (0x0000070C)
+#define MMSS_DP_GENERIC0_4 (0x00000710)
+#define MMSS_DP_GENERIC0_5 (0x00000714)
+#define MMSS_DP_GENERIC0_6 (0x00000718)
+#define MMSS_DP_GENERIC0_7 (0x0000071C)
+#define MMSS_DP_GENERIC0_8 (0x00000720)
+#define MMSS_DP_GENERIC0_9 (0x00000724)
+#define MMSS_DP_GENERIC1_0 (0x00000728)
+#define MMSS_DP_GENERIC1_1 (0x0000072C)
+#define MMSS_DP_GENERIC1_2 (0x00000730)
+#define MMSS_DP_GENERIC1_3 (0x00000734)
+#define MMSS_DP_GENERIC1_4 (0x00000738)
+#define MMSS_DP_GENERIC1_5 (0x0000073C)
+#define MMSS_DP_GENERIC1_6 (0x00000740)
+#define MMSS_DP_GENERIC1_7 (0x00000744)
+#define MMSS_DP_GENERIC1_8 (0x00000748)
+#define MMSS_DP_GENERIC1_9 (0x0000074C)
+
+#define MMSS_DP_TIMING_ENGINE_EN (0x00000A10)
+#define MMSS_DP_ASYNC_FIFO_CONFIG (0x00000A88)
+
+/*DP PHY Register offsets */
+#define DP_PHY_REVISION_ID0 (0x00000000)
+#define DP_PHY_REVISION_ID1 (0x00000004)
+#define DP_PHY_REVISION_ID2 (0x00000008)
+#define DP_PHY_REVISION_ID3 (0x0000000C)
+
+#define DP_PHY_CFG (0x00000010)
+#define DP_PHY_PD_CTL (0x00000018)
+#define DP_PHY_MODE (0x0000001C)
+
+#define DP_PHY_AUX_CFG0 (0x00000020)
+#define DP_PHY_AUX_CFG1 (0x00000024)
+#define DP_PHY_AUX_CFG2 (0x00000028)
+#define DP_PHY_AUX_CFG3 (0x0000002C)
+#define DP_PHY_AUX_CFG4 (0x00000030)
+#define DP_PHY_AUX_CFG5 (0x00000034)
+#define DP_PHY_AUX_CFG6 (0x00000038)
+#define DP_PHY_AUX_CFG7 (0x0000003C)
+#define DP_PHY_AUX_CFG8 (0x00000040)
+#define DP_PHY_AUX_CFG9 (0x00000044)
+#define DP_PHY_AUX_INTERRUPT_MASK (0x00000048)
+#define DP_PHY_AUX_INTERRUPT_CLEAR (0x0000004C)
+
+#define DP_PHY_SPARE0 (0x00AC)
+
+#define TXn_TX_EMP_POST1_LVL (0x000C)
+#define TXn_TX_DRV_LVL (0x001C)
+
+#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN (0x004)
+
+/* DP MMSS_CC registers */
+#define MMSS_DP_LINK_CMD_RCGR (0x0138)
+#define MMSS_DP_LINK_CFG_RCGR (0x013C)
+#define MMSS_DP_PIXEL_M (0x0174)
+#define MMSS_DP_PIXEL_N (0x0178)
+
+/* DP HDCP 1.3 registers */
+#define DP_HDCP_CTRL (0x0A0)
+#define DP_HDCP_STATUS (0x0A4)
+#define DP_HDCP_SW_UPPER_AKSV (0x298)
+#define DP_HDCP_SW_LOWER_AKSV (0x29C)
+#define DP_HDCP_ENTROPY_CTRL0 (0x750)
+#define DP_HDCP_ENTROPY_CTRL1 (0x75C)
+#define DP_HDCP_SHA_STATUS (0x0C8)
+#define DP_HDCP_RCVPORT_DATA2_0 (0x0B0)
+#define DP_HDCP_RCVPORT_DATA3 (0x2A4)
+#define DP_HDCP_RCVPORT_DATA4 (0x2A8)
+#define DP_HDCP_RCVPORT_DATA5 (0x0C0)
+#define DP_HDCP_RCVPORT_DATA6 (0x0C4)
+
+#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_CTRL (0x024)
+#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_DATA (0x028)
+#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA0 (0x004)
+#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA1 (0x008)
+#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA7 (0x00C)
+#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA8 (0x010)
+#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA9 (0x014)
+#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA10 (0x018)
+#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA11 (0x01C)
+#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA12 (0x020)
+
+#endif /* _DP_REG_H_ */
diff --git a/drivers/gpu/drm/msm/dp/dp_usbpd.c b/drivers/gpu/drm/msm/dp/dp_usbpd.c
index 7bc1433..df43267 100644
--- a/drivers/gpu/drm/msm/dp/dp_usbpd.c
+++ b/drivers/gpu/drm/msm/dp/dp_usbpd.c
@@ -73,6 +73,8 @@
struct dp_usbpd dp_usbpd;
enum dp_usbpd_alt_mode alt_mode;
u32 dp_usbpd_config;
+
+ bool forced_disconnect;
};
static const char *dp_usbpd_pin_name(u8 pin)
@@ -342,6 +344,9 @@
dp_usbpd_send_event(pd, DP_USBPD_EVT_STATUS);
break;
case USBPD_SVDM_ATTENTION:
+ if (pd->forced_disconnect)
+ break;
+
pd->vdo = *vdos;
dp_usbpd_get_status(pd);
@@ -378,12 +383,38 @@
}
}
+static int dp_usbpd_connect(struct dp_usbpd *dp_usbpd, bool hpd)
+{
+ int rc = 0;
+ struct dp_usbpd_private *pd;
+
+ if (!dp_usbpd) {
+ pr_err("invalid input\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ pd = container_of(dp_usbpd, struct dp_usbpd_private, dp_usbpd);
+
+ dp_usbpd->hpd_high = hpd;
+ pd->forced_disconnect = !hpd;
+
+ if (hpd)
+ pd->dp_cb->configure(pd->dev);
+ else
+ pd->dp_cb->disconnect(pd->dev);
+
+error:
+ return rc;
+}
+
struct dp_usbpd *dp_usbpd_get(struct device *dev, struct dp_usbpd_cb *cb)
{
int rc = 0;
const char *pd_phandle = "qcom,dp-usbpd-detection";
struct usbpd *pd = NULL;
struct dp_usbpd_private *usbpd;
+ struct dp_usbpd *dp_usbpd;
struct usbpd_svid_handler svid_handler = {
.svid = USB_C_DP_SID,
.vdm_received = NULL,
@@ -423,7 +454,11 @@
kfree(usbpd);
goto error;
}
- return &usbpd->dp_usbpd;
+
+ dp_usbpd = &usbpd->dp_usbpd;
+ dp_usbpd->connect = dp_usbpd_connect;
+
+ return dp_usbpd;
error:
return ERR_PTR(rc);
}
diff --git a/drivers/gpu/drm/msm/dp/dp_usbpd.h b/drivers/gpu/drm/msm/dp/dp_usbpd.h
index 67f380a..2682e98 100644
--- a/drivers/gpu/drm/msm/dp/dp_usbpd.h
+++ b/drivers/gpu/drm/msm/dp/dp_usbpd.h
@@ -48,6 +48,8 @@
* @hpd_high: Hot Plug Detect signal is high.
* @hpd_irq: Change in the status since last message
* @alt_mode_cfg_done: bool to specify alt mode status
+ * @debug_en: bool to specify debug mode
+ * @connect: simulate disconnect or connect for debug mode
*/
struct dp_usbpd {
enum dp_usbpd_port port;
@@ -60,6 +62,9 @@
bool hpd_high;
bool hpd_irq;
bool alt_mode_cfg_done;
+ bool debug_en;
+
+ int (*connect)(struct dp_usbpd *dp_usbpd, bool hpd);
};
/**
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
index 3625ed0..e9dabb1 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
@@ -56,6 +56,8 @@
dsi_ctrl_hw_cmn_trigger_cmd_test_pattern;
ctrl->ops.clear_phy0_ln_err = dsi_ctrl_hw_dln0_phy_err;
ctrl->ops.phy_reset_config = dsi_ctrl_hw_cmn_phy_reset_config;
+ ctrl->ops.setup_misr = dsi_ctrl_hw_cmn_setup_misr;
+ ctrl->ops.collect_misr = dsi_ctrl_hw_cmn_collect_misr;
switch (version) {
case DSI_CTRL_VERSION_1_4:
@@ -106,14 +108,15 @@
* @ctrl: Pointer to DSI controller hw object.
* @version: DSI controller version.
* @index: DSI controller instance ID.
+ * @phy_isolation_enabled: DSI controller works isolated from phy.
*
* This function setups the catalog information in the dsi_ctrl_hw object.
*
* return: error code for failure and 0 for success.
*/
int dsi_catalog_ctrl_setup(struct dsi_ctrl_hw *ctrl,
- enum dsi_ctrl_version version,
- u32 index)
+ enum dsi_ctrl_version version, u32 index,
+ bool phy_isolation_enabled)
{
int rc = 0;
@@ -133,8 +136,11 @@
switch (version) {
case DSI_CTRL_VERSION_1_4:
+ dsi_catalog_cmn_init(ctrl, version);
+ break;
case DSI_CTRL_VERSION_2_0:
case DSI_CTRL_VERSION_2_2:
+ ctrl->phy_isolation_enabled = phy_isolation_enabled;
dsi_catalog_cmn_init(ctrl, version);
break;
default:
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
index 2d7b174..e8d594c 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
@@ -23,14 +23,15 @@
* @ctrl: Pointer to DSI controller hw object.
* @version: DSI controller version.
* @index: DSI controller instance ID.
+ * @phy_isolation_enabled: DSI controller works isolated from phy.
*
* This function setups the catalog information in the dsi_ctrl_hw object.
*
* return: error code for failure and 0 for success.
*/
int dsi_catalog_ctrl_setup(struct dsi_ctrl_hw *ctrl,
- enum dsi_ctrl_version version,
- u32 index);
+ enum dsi_ctrl_version version, u32 index,
+ bool phy_isolation_enabled);
/**
* dsi_catalog_phy_setup() - return catalog info for dsi phy hardware
@@ -147,6 +148,12 @@
void dsi_ctrl_hw_cmn_phy_sw_reset(struct dsi_ctrl_hw *ctrl);
void dsi_ctrl_hw_cmn_soft_reset(struct dsi_ctrl_hw *ctrl);
+void dsi_ctrl_hw_cmn_setup_misr(struct dsi_ctrl_hw *ctrl,
+ enum dsi_op_mode panel_mode,
+ bool enable, u32 frame_count);
+u32 dsi_ctrl_hw_cmn_collect_misr(struct dsi_ctrl_hw *ctrl,
+ enum dsi_op_mode panel_mode);
+
void dsi_ctrl_hw_cmn_kickoff_command(struct dsi_ctrl_hw *ctrl,
struct dsi_ctrl_cmd_dma_info *cmd,
u32 flags);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
index b2aef9c..dcde566 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
@@ -1262,13 +1262,41 @@
return 0;
}
+static int dsi_ctrl_dts_parse(struct dsi_ctrl *dsi_ctrl,
+ struct device_node *of_node)
+{
+ u32 index = 0;
+ int rc = 0;
+
+ if (!dsi_ctrl || !of_node) {
+ pr_err("invalid dsi_ctrl:%d or of_node:%d\n",
+ dsi_ctrl != NULL, of_node != NULL);
+ return -EINVAL;
+ }
+
+ rc = of_property_read_u32(of_node, "cell-index", &index);
+ if (rc) {
+ pr_debug("cell index not set, default to 0\n");
+ index = 0;
+ }
+
+ dsi_ctrl->cell_index = index;
+ dsi_ctrl->name = of_get_property(of_node, "label", NULL);
+ if (!dsi_ctrl->name)
+ dsi_ctrl->name = DSI_CTRL_DEFAULT_LABEL;
+
+ dsi_ctrl->phy_isolation_enabled = of_property_read_bool(of_node,
+ "qcom,dsi-phy-isolation-enabled");
+
+ return 0;
+}
+
static int dsi_ctrl_dev_probe(struct platform_device *pdev)
{
struct dsi_ctrl *dsi_ctrl;
struct dsi_ctrl_list_item *item;
const struct of_device_id *id;
enum dsi_ctrl_version version;
- u32 index = 0;
int rc = 0;
id = of_match_node(msm_dsi_of_match, pdev->dev.of_node);
@@ -1285,22 +1313,18 @@
if (!dsi_ctrl)
return -ENOMEM;
- rc = of_property_read_u32(pdev->dev.of_node, "cell-index", &index);
- if (rc) {
- pr_debug("cell index not set, default to 0\n");
- index = 0;
- }
-
- dsi_ctrl->cell_index = index;
dsi_ctrl->version = version;
dsi_ctrl->irq_info.irq_num = -1;
dsi_ctrl->irq_info.irq_stat_mask = 0x0;
spin_lock_init(&dsi_ctrl->irq_info.irq_lock);
- dsi_ctrl->name = of_get_property(pdev->dev.of_node, "label", NULL);
- if (!dsi_ctrl->name)
- dsi_ctrl->name = DSI_CTRL_DEFAULT_LABEL;
+ rc = dsi_ctrl_dts_parse(dsi_ctrl, pdev->dev.of_node);
+ if (rc) {
+ pr_err("ctrl:%d dts parse failed, rc = %d\n",
+ dsi_ctrl->cell_index, rc);
+ goto fail;
+ }
rc = dsi_ctrl_init_regmap(pdev, dsi_ctrl);
if (rc) {
@@ -1321,7 +1345,7 @@
}
rc = dsi_catalog_ctrl_setup(&dsi_ctrl->hw, dsi_ctrl->version,
- dsi_ctrl->cell_index);
+ dsi_ctrl->cell_index, dsi_ctrl->phy_isolation_enabled);
if (rc) {
pr_err("Catalog does not support version (%d)\n",
dsi_ctrl->version);
@@ -1945,6 +1969,36 @@
spin_unlock_irqrestore(&dsi_ctrl->irq_info.irq_lock, flags);
}
+int dsi_ctrl_host_timing_update(struct dsi_ctrl *dsi_ctrl)
+{
+ if (!dsi_ctrl) {
+ pr_err("Invalid params\n");
+ return -EINVAL;
+ }
+
+ if (dsi_ctrl->hw.ops.host_setup)
+ dsi_ctrl->hw.ops.host_setup(&dsi_ctrl->hw,
+ &dsi_ctrl->host_config.common_config);
+
+ if (dsi_ctrl->host_config.panel_mode == DSI_OP_CMD_MODE) {
+ if (dsi_ctrl->hw.ops.cmd_engine_setup)
+ dsi_ctrl->hw.ops.cmd_engine_setup(&dsi_ctrl->hw,
+ &dsi_ctrl->host_config.common_config,
+ &dsi_ctrl->host_config.u.cmd_engine);
+
+ if (dsi_ctrl->hw.ops.setup_cmd_stream)
+ dsi_ctrl->hw.ops.setup_cmd_stream(&dsi_ctrl->hw,
+ &dsi_ctrl->host_config.video_timing,
+ dsi_ctrl->host_config.video_timing.h_active * 3,
+ 0x0, NULL);
+ } else {
+ pr_err("invalid panel mode for resolution switch\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
/**
* dsi_ctrl_host_init() - Initialize DSI host hardware.
* @dsi_ctrl: DSI controller handle.
@@ -2002,8 +2056,6 @@
dsi_ctrl->hw.ops.enable_status_interrupts(&dsi_ctrl->hw, 0x0);
dsi_ctrl->hw.ops.enable_error_interrupts(&dsi_ctrl->hw, 0x0);
- /* Perform a soft reset before enabling dsi controller */
- dsi_ctrl->hw.ops.soft_reset(&dsi_ctrl->hw);
pr_debug("[DSI_%d]Host initialization complete\n",
dsi_ctrl->cell_index);
dsi_ctrl_update_state(dsi_ctrl, DSI_CTRL_OP_HOST_INIT, 0x1);
@@ -2258,6 +2310,28 @@
}
/**
+ * _dsi_ctrl_cache_misr - Cache frame MISR value
+ * @dsi_ctrl: Pointer to associated dsi_ctrl structure
+ */
+static void _dsi_ctrl_cache_misr(struct dsi_ctrl *dsi_ctrl)
+{
+ u32 misr;
+
+ if (!dsi_ctrl || !dsi_ctrl->hw.ops.collect_misr)
+ return;
+
+ misr = dsi_ctrl->hw.ops.collect_misr(&dsi_ctrl->hw,
+ dsi_ctrl->host_config.panel_mode);
+
+ if (misr)
+ dsi_ctrl->misr_cache = misr;
+
+ pr_debug("DSI_%d misr_cache = %x\n", dsi_ctrl->cell_index,
+ dsi_ctrl->misr_cache);
+
+}
+
+/**
* dsi_ctrl_set_power_state() - set power state for dsi controller
* @dsi_ctrl: DSI controller handle.
* @state: Power state.
@@ -2295,6 +2369,9 @@
goto error;
}
} else if (state == DSI_CTRL_POWER_VREG_OFF) {
+ if (dsi_ctrl->misr_enable)
+ _dsi_ctrl_cache_misr(dsi_ctrl);
+
rc = dsi_ctrl_enable_supplies(dsi_ctrl, false);
if (rc) {
pr_err("[%d]failed to disable vreg supplies, rc=%d\n",
@@ -2609,6 +2686,59 @@
}
/**
+ * dsi_ctrl_setup_misr() - Setup frame MISR
+ * @dsi_ctrl: DSI controller handle.
+ * @enable: enable/disable MISR.
+ * @frame_count: Number of frames to accumulate MISR.
+ *
+ * Return: error code.
+ */
+int dsi_ctrl_setup_misr(struct dsi_ctrl *dsi_ctrl,
+ bool enable,
+ u32 frame_count)
+{
+ if (!dsi_ctrl) {
+ pr_err("Invalid params\n");
+ return -EINVAL;
+ }
+
+ if (!dsi_ctrl->hw.ops.setup_misr)
+ return 0;
+
+ mutex_lock(&dsi_ctrl->ctrl_lock);
+ dsi_ctrl->misr_enable = enable;
+ dsi_ctrl->hw.ops.setup_misr(&dsi_ctrl->hw,
+ dsi_ctrl->host_config.panel_mode,
+ enable, frame_count);
+ mutex_unlock(&dsi_ctrl->ctrl_lock);
+ return 0;
+}
+
+/**
+ * dsi_ctrl_collect_misr() - Read frame MISR
+ * @dsi_ctrl: DSI controller handle.
+ *
+ * Return: MISR value.
+ */
+u32 dsi_ctrl_collect_misr(struct dsi_ctrl *dsi_ctrl)
+{
+ u32 misr;
+
+ if (!dsi_ctrl || !dsi_ctrl->hw.ops.collect_misr)
+ return 0;
+
+ misr = dsi_ctrl->hw.ops.collect_misr(&dsi_ctrl->hw,
+ dsi_ctrl->host_config.panel_mode);
+ if (!misr)
+ misr = dsi_ctrl->misr_cache;
+
+ pr_debug("DSI_%d cached misr = %x, final = %x\n",
+ dsi_ctrl->cell_index, dsi_ctrl->misr_cache, misr);
+
+ return misr;
+}
+
+/**
* dsi_ctrl_drv_register() - register platform driver for dsi controller
*/
void dsi_ctrl_drv_register(void)
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
index ec535ce11..f10c7a6 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
@@ -188,6 +188,10 @@
* @vaddr: CPU virtual address of cmd buffer.
* @cmd_buffer_size: Size of command buffer.
* @debugfs_root: Root for debugfs entries.
+ * @misr_enable: Frame MISR enable/disable
+ * @misr_cache: Cached Frame MISR value
+ * @phy_isolation_enabled: A boolean property allows to isolate the phy from
+ * dsi controller and run only dsi controller.
*/
struct dsi_ctrl {
struct platform_device *pdev;
@@ -226,6 +230,11 @@
/* Debug Information */
struct dentry *debugfs_root;
+ /* MISR */
+ bool misr_enable;
+ u32 misr_cache;
+
+ bool phy_isolation_enabled;
};
/**
@@ -354,6 +363,17 @@
int dsi_ctrl_soft_reset(struct dsi_ctrl *dsi_ctrl);
/**
+ * dsi_ctrl_host_timing_update - reinitialize host with new timing values
+ * @dsi_ctrl: DSI controller handle.
+ *
+ * Reinitialize DSI controller hardware with new display timing values
+ * when resolution is switched dynamically.
+ *
+ * Return: error code
+ */
+int dsi_ctrl_host_timing_update(struct dsi_ctrl *dsi_ctrl);
+
+/**
* dsi_ctrl_host_init() - Initialize DSI host hardware.
* @dsi_ctrl: DSI controller handle.
*
@@ -571,6 +591,26 @@
struct dsi_ctrl *dsi_ctrl, uint32_t intr_idx);
/**
+ * dsi_ctrl_setup_misr() - Setup frame MISR
+ * @dsi_ctrl: DSI controller handle.
+ * @enable: enable/disable MISR.
+ * @frame_count: Number of frames to accumulate MISR.
+ *
+ * Return: error code.
+ */
+int dsi_ctrl_setup_misr(struct dsi_ctrl *dsi_ctrl,
+ bool enable,
+ u32 frame_count);
+
+/**
+ * dsi_ctrl_collect_misr() - Read frame MISR
+ * @dsi_ctrl: DSI controller handle.
+ *
+ * Return: MISR value.
+ */
+u32 dsi_ctrl_collect_misr(struct dsi_ctrl *dsi_ctrl);
+
+/**
* dsi_ctrl_drv_register() - register platform driver for dsi controller
*/
void dsi_ctrl_drv_register(void);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
index 74be279..57f9bcd 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
@@ -675,6 +675,26 @@
ssize_t (*reg_dump_to_buffer)(struct dsi_ctrl_hw *ctrl,
char *buf,
u32 size);
+
+ /**
+ * setup_misr() - Setup frame MISR
+ * @ctrl: Pointer to the controller host hardware.
+ * @panel_mode: CMD or VIDEO mode indicator
+ * @enable: Enable/disable MISR.
+ * @frame_count: Number of frames to accumulate MISR.
+ */
+ void (*setup_misr)(struct dsi_ctrl_hw *ctrl,
+ enum dsi_op_mode panel_mode,
+ bool enable, u32 frame_count);
+
+ /**
+ * collect_misr() - Read frame MISR
+ * @ctrl: Pointer to the controller host hardware.
+ * @panel_mode: CMD or VIDEO mode indicator
+ */
+ u32 (*collect_misr)(struct dsi_ctrl_hw *ctrl,
+ enum dsi_op_mode panel_mode);
+
};
/*
@@ -691,6 +711,8 @@
* controller.
* @supported_interrupts: Number of supported interrupts.
* @supported_errors: Number of supported errors.
+ * @phy_isolation_enabled: A boolean property allows to isolate the phy from
+ * dsi controller and run only dsi controller.
*/
struct dsi_ctrl_hw {
void __iomem *base;
@@ -708,6 +730,8 @@
/* capabilities */
u32 supported_interrupts;
u64 supported_errors;
+
+ bool phy_isolation_enabled;
};
#endif /* _DSI_CTRL_HW_H_ */
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_2_0.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_2_0.c
index c22849a..6421dc2 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_2_0.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_2_0.c
@@ -157,6 +157,10 @@
len += snprintf((buf + len), (size - len),
DUMP_REG_VALUE(DSI_RESET_SW_TRIGGER));
len += snprintf((buf + len), (size - len),
+ DUMP_REG_VALUE(DSI_MISR_CMD_CTRL));
+ len += snprintf((buf + len), (size - len),
+ DUMP_REG_VALUE(DSI_MISR_VIDEO_CTRL));
+ len += snprintf((buf + len), (size - len),
DUMP_REG_VALUE(DSI_LANE_STATUS));
len += snprintf((buf + len), (size - len),
DUMP_REG_VALUE(DSI_LANE_CTRL));
@@ -193,6 +197,12 @@
len += snprintf((buf + len), (size - len),
DUMP_REG_VALUE(DSI_AXI2AHB_CTRL));
len += snprintf((buf + len), (size - len),
+ DUMP_REG_VALUE(DSI_MISR_CMD_MDP0_32BIT));
+ len += snprintf((buf + len), (size - len),
+ DUMP_REG_VALUE(DSI_MISR_CMD_MDP1_32BIT));
+ len += snprintf((buf + len), (size - len),
+ DUMP_REG_VALUE(DSI_MISR_VIDEO_32BIT));
+ len += snprintf((buf + len), (size - len),
DUMP_REG_VALUE(DSI_COMMAND_MODE_MDP_CTRL2));
len += snprintf((buf + len), (size - len),
DUMP_REG_VALUE(DSI_COMMAND_MODE_MDP_STREAM2_CTRL));
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c
index 0af6f25..3fec296 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c
@@ -20,9 +20,12 @@
#include "dsi_ctrl_reg.h"
#include "dsi_hw.h"
#include "dsi_panel.h"
+#include "dsi_catalog.h"
#define MMSS_MISC_CLAMP_REG_OFF 0x0014
#define DSI_CTRL_DYNAMIC_FORCE_ON (0x23F|BIT(8)|BIT(9)|BIT(11)|BIT(21))
+#define DSI_CTRL_CMD_MISR_ENABLE BIT(28)
+#define DSI_CTRL_VIDEO_MISR_ENABLE BIT(16)
/* Unsupported formats default to RGB888 */
static const u8 cmd_mode_format_map[DSI_PIXEL_FORMAT_MAX] = {
@@ -76,7 +79,7 @@
DSI_W32(ctrl, DSI_CLK_CTRL, 0x23F);
/* Setup DSI control register */
- reg_value = 0;
+ reg_value = DSI_R32(ctrl, DSI_CTRL);
reg_value |= (cfg->en_crc_check ? BIT(24) : 0);
reg_value |= (cfg->en_ecc_check ? BIT(20) : 0);
reg_value |= BIT(8); /* Clock lane */
@@ -87,6 +90,8 @@
DSI_W32(ctrl, DSI_CTRL, reg_value);
+ if (ctrl->phy_isolation_enabled)
+ DSI_W32(ctrl, DSI_DEBUG_CTRL, BIT(28));
pr_debug("[DSI_%d]Host configuration complete\n", ctrl->index);
}
@@ -149,6 +154,70 @@
}
/**
+ * setup_misr() - Setup frame MISR
+ * @ctrl: Pointer to the controller host hardware.
+ * @panel_mode: CMD or VIDEO mode indicator
+ * @enable: Enable/disable MISR.
+ * @frame_count: Number of frames to accumulate MISR.
+ */
+void dsi_ctrl_hw_cmn_setup_misr(struct dsi_ctrl_hw *ctrl,
+ enum dsi_op_mode panel_mode,
+ bool enable,
+ u32 frame_count)
+{
+ u32 addr;
+ u32 config = 0;
+
+ if (panel_mode == DSI_OP_CMD_MODE) {
+ addr = DSI_MISR_CMD_CTRL;
+ if (enable)
+ config = DSI_CTRL_CMD_MISR_ENABLE;
+ } else {
+ addr = DSI_MISR_VIDEO_CTRL;
+ if (enable)
+ config = DSI_CTRL_VIDEO_MISR_ENABLE;
+ if (frame_count > 255)
+ frame_count = 255;
+ config |= frame_count << 8;
+ }
+
+ pr_debug("[DSI_%d] MISR ctrl: 0x%x\n", ctrl->index,
+ config);
+ DSI_W32(ctrl, addr, config);
+ wmb(); /* make sure MISR is configured */
+}
+
+/**
+ * collect_misr() - Read frame MISR
+ * @ctrl: Pointer to the controller host hardware.
+ * @panel_mode: CMD or VIDEO mode indicator
+ */
+u32 dsi_ctrl_hw_cmn_collect_misr(struct dsi_ctrl_hw *ctrl,
+ enum dsi_op_mode panel_mode)
+{
+ u32 addr;
+ u32 enabled;
+ u32 misr = 0;
+
+ if (panel_mode == DSI_OP_CMD_MODE) {
+ addr = DSI_MISR_CMD_MDP0_32BIT;
+ enabled = DSI_R32(ctrl, DSI_MISR_CMD_CTRL) &
+ DSI_CTRL_CMD_MISR_ENABLE;
+ } else {
+ addr = DSI_MISR_VIDEO_32BIT;
+ enabled = DSI_R32(ctrl, DSI_MISR_VIDEO_CTRL) &
+ DSI_CTRL_VIDEO_MISR_ENABLE;
+ }
+
+ if (enabled)
+ misr = DSI_R32(ctrl, addr);
+
+ pr_debug("[DSI_%d] MISR enabled %x value: 0x%x\n", ctrl->index,
+ enabled, misr);
+ return misr;
+}
+
+/**
* set_video_timing() - set up the timing for video frame
* @ctrl: Pointer to controller host hardware.
* @mode: Video mode information.
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_reg.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_reg.h
index 34e9e72..f8f7e13 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_reg.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_reg.h
@@ -184,6 +184,7 @@
#define DSI_DESKEW_CTRL (0x02BC)
#define DSI_DESKEW_DELAY_CTRL (0x02C0)
#define DSI_DESKEW_SW_TRIGGER (0x02C4)
+#define DSI_DEBUG_CTRL (0x02C8)
#define DSI_SECURE_DISPLAY_STATUS (0x02CC)
#define DSI_SECURE_DISPLAY_BLOCK_COMMAND_COLOR (0x02D0)
#define DSI_SECURE_DISPLAY_BLOCK_VIDEO_COLOR (0x02D4)
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h b/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h
index 1e6727b..fcc59ef 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h
@@ -15,6 +15,7 @@
#define _DSI_DEFS_H_
#include <linux/types.h>
+#include <drm/drm_mipi_dsi.h>
#include "msm_drv.h"
#define DSI_H_TOTAL(t) (((t)->h_active) + ((t)->h_back_porch) + \
@@ -75,11 +76,13 @@
* @DSI_MODE_FLAG_SEAMLESS: Seamless transition requested by user
* @DSI_MODE_FLAG_DFPS: Seamless transition is DynamicFPS
* @DSI_MODE_FLAG_VBLANK_PRE_MODESET: Transition needs VBLANK before Modeset
+ * @DSI_MODE_FLAG_DMS: Seamless transition is dynamic mode switch
*/
enum dsi_mode_flags {
DSI_MODE_FLAG_SEAMLESS = BIT(0),
DSI_MODE_FLAG_DFPS = BIT(1),
- DSI_MODE_FLAG_VBLANK_PRE_MODESET = BIT(2)
+ DSI_MODE_FLAG_VBLANK_PRE_MODESET = BIT(2),
+ DSI_MODE_FLAG_DMS = BIT(3),
};
/**
@@ -214,6 +217,68 @@
};
/**
+ * enum dsi_cmd_set_type - DSI command set type
+ * @DSI_CMD_SET_PRE_ON: Panel pre on
+ * @DSI_CMD_SET_ON: Panel on
+ * @DSI_CMD_SET_POST_ON: Panel post on
+ * @DSI_CMD_SET_PRE_OFF: Panel pre off
+ * @DSI_CMD_SET_OFF: Panel off
+ * @DSI_CMD_SET_POST_OFF: Panel post off
+ * @DSI_CMD_SET_PRE_RES_SWITCH: Pre resolution switch
+ * @DSI_CMD_SET_RES_SWITCH: Resolution switch
+ * @DSI_CMD_SET_POST_RES_SWITCH: Post resolution switch
+ * @DSI_CMD_SET_CMD_TO_VID_SWITCH: Cmd to video mode switch
+ * @DSI_CMD_SET_POST_CMD_TO_VID_SWITCH: Post cmd to vid switch
+ * @DSI_CMD_SET_VID_TO_CMD_SWITCH: Video to cmd mode switch
+ * @DSI_CMD_SET_POST_VID_TO_CMD_SWITCH: Post vid to cmd switch
+ * @DSI_CMD_SET_PANEL_STATUS: Panel status
+ * @DSI_CMD_SET_LP1: Low power mode 1
+ * @DSI_CMD_SET_LP2: Low power mode 2
+ * @DSI_CMD_SET_NOLP: Low power mode disable
+ * @DSI_CMD_SET_PPS: DSC PPS command
+ * @DSI_CMD_SET_ROI: Panel ROI update
+ * @DSI_CMD_SET_TIMING_SWITCH: Timing switch
+ * @DSI_CMD_SET_POST_TIMING_SWITCH: Post timing switch
+ * @DSI_CMD_SET_MAX
+ */
+enum dsi_cmd_set_type {
+ DSI_CMD_SET_PRE_ON = 0,
+ DSI_CMD_SET_ON,
+ DSI_CMD_SET_POST_ON,
+ DSI_CMD_SET_PRE_OFF,
+ DSI_CMD_SET_OFF,
+ DSI_CMD_SET_POST_OFF,
+ DSI_CMD_SET_PRE_RES_SWITCH,
+ DSI_CMD_SET_RES_SWITCH,
+ DSI_CMD_SET_POST_RES_SWITCH,
+ DSI_CMD_SET_CMD_TO_VID_SWITCH,
+ DSI_CMD_SET_POST_CMD_TO_VID_SWITCH,
+ DSI_CMD_SET_VID_TO_CMD_SWITCH,
+ DSI_CMD_SET_POST_VID_TO_CMD_SWITCH,
+ DSI_CMD_SET_PANEL_STATUS,
+ DSI_CMD_SET_LP1,
+ DSI_CMD_SET_LP2,
+ DSI_CMD_SET_NOLP,
+ DSI_CMD_SET_PPS,
+ DSI_CMD_SET_ROI,
+ DSI_CMD_SET_TIMING_SWITCH,
+ DSI_CMD_SET_POST_TIMING_SWITCH,
+ DSI_CMD_SET_MAX
+};
+
+/**
+ * enum dsi_cmd_set_state - command set state
+ * @DSI_CMD_SET_STATE_LP: dsi low power mode
+ * @DSI_CMD_SET_STATE_HS: dsi high speed mode
+ * @DSI_CMD_SET_STATE_MAX
+ */
+enum dsi_cmd_set_state {
+ DSI_CMD_SET_STATE_LP = 0,
+ DSI_CMD_SET_STATE_HS,
+ DSI_CMD_SET_STATE_MAX
+};
+
+/**
* enum dsi_phy_type - DSI phy types
* @DSI_PHY_TYPE_DPHY:
* @DSI_PHY_TYPE_CPHY:
@@ -246,6 +311,34 @@
};
/**
+ * struct dsi_cmd_desc - description of a dsi command
+ * @msg: dsi mipi msg packet
+ * @last_command: indicates whether the cmd is the last one to send
+ * @post_wait_ms: post wait duration
+ */
+struct dsi_cmd_desc {
+ struct mipi_dsi_msg msg;
+ bool last_command;
+ u32 post_wait_ms;
+};
+
+/**
+ * struct dsi_panel_cmd_set - command set of the panel
+ * @type: type of the command
+ * @state: state of the command
+ * @count: number of cmds
+ * @ctrl_idx: index of the dsi control
+ * @cmds: arry of cmds
+ */
+struct dsi_panel_cmd_set {
+ enum dsi_cmd_set_type type;
+ enum dsi_cmd_set_state state;
+ u32 count;
+ u32 ctrl_idx;
+ struct dsi_cmd_desc *cmds;
+};
+
+/**
* struct dsi_mode_info - video mode information dsi frame
* @h_active: Active width of one frame in pixels.
* @h_back_porch: Horizontal back porch in pixels.
@@ -397,18 +490,44 @@
};
/**
+ * struct dsi_display_mode_priv_info - private mode info that will be attached
+ * with each drm mode
+ * @cmd_sets: Command sets of the mode
+ * @phy_timing_val: Phy timing values
+ * @phy_timing_len: Phy timing array length
+ * @panel_jitter: Panel jitter for RSC backoff
+ * @panel_prefill_lines: Panel prefill lines for RSC
+ * @topology: Topology selected for the panel
+ * @dsc: DSC compression info
+ * @dsc_enabled: DSC compression enabled
+ */
+struct dsi_display_mode_priv_info {
+ struct dsi_panel_cmd_set cmd_sets[DSI_CMD_SET_MAX];
+
+ u32 *phy_timing_val;
+ u32 phy_timing_len;
+
+ u32 panel_jitter_numer;
+ u32 panel_jitter_denom;
+ u32 panel_prefill_lines;
+
+ struct msm_display_topology topology;
+ struct msm_display_dsc_info dsc;
+ bool dsc_enabled;
+};
+
+/**
* struct dsi_display_mode - specifies mode for dsi display
* @timing: Timing parameters for the panel.
* @pixel_clk_khz: Pixel clock in Khz.
- * @panel_mode: Panel operation mode.
* @dsi_mode_flags: Flags to signal other drm components via private flags
+ * @priv_info: Mode private info
*/
struct dsi_display_mode {
struct dsi_mode_info timing;
u32 pixel_clk_khz;
- enum dsi_op_mode panel_mode;
u32 dsi_mode_flags;
- struct msm_mode_info *mode_info;
+ struct dsi_display_mode_priv_info *priv_info;
};
/**
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
index a4a9fb5..04dd6a5 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
@@ -31,6 +31,9 @@
#define to_dsi_display(x) container_of(x, struct dsi_display, host)
#define INT_BASE_10 10
+#define NO_OVERRIDE -1
+
+#define MISR_BUFF_SIZE 256
static DEFINE_MUTEX(dsi_display_list_lock);
static LIST_HEAD(dsi_display_list);
@@ -128,9 +131,45 @@
return format;
}
+static void _dsi_display_setup_misr(struct dsi_display *display)
+{
+ int i;
+
+ for (i = 0; i < display->ctrl_count; i++) {
+ dsi_ctrl_setup_misr(display->ctrl[i].ctrl,
+ display->misr_enable,
+ display->misr_frame_count);
+ }
+}
+
+int dsi_display_set_power(struct drm_connector *connector,
+ int power_mode, void *disp)
+{
+ struct dsi_display *display = disp;
+ int rc = 0;
+
+ if (!display || !display->panel) {
+ pr_err("invalid display/panel\n");
+ return -EINVAL;
+ }
+
+ switch (power_mode) {
+ case SDE_MODE_DPMS_LP1:
+ rc = dsi_panel_set_lp1(display->panel);
+ break;
+ case SDE_MODE_DPMS_LP2:
+ rc = dsi_panel_set_lp2(display->panel);
+ break;
+ default:
+ rc = dsi_panel_set_nolp(display->panel);
+ break;
+ }
+ return rc;
+}
+
static ssize_t debugfs_dump_info_read(struct file *file,
- char __user *buff,
- size_t count,
+ char __user *user_buf,
+ size_t user_len,
loff_t *ppos)
{
struct dsi_display *display = file->private_data;
@@ -168,7 +207,7 @@
"\tClock master = %s\n",
display->ctrl[display->clk_master_idx].ctrl->name);
- if (copy_to_user(buff, buf, len)) {
+ if (copy_to_user(user_buf, buf, len)) {
kfree(buf);
return -EFAULT;
}
@@ -179,16 +218,151 @@
return len;
}
+static ssize_t debugfs_misr_setup(struct file *file,
+ const char __user *user_buf,
+ size_t user_len,
+ loff_t *ppos)
+{
+ struct dsi_display *display = file->private_data;
+ char *buf;
+ int rc = 0;
+ size_t len;
+ u32 enable, frame_count;
+
+ if (!display)
+ return -ENODEV;
+
+ if (*ppos)
+ return 0;
+
+ buf = kzalloc(MISR_BUFF_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ /* leave room for termination char */
+ len = min_t(size_t, user_len, MISR_BUFF_SIZE - 1);
+ if (copy_from_user(buf, user_buf, len)) {
+ rc = -EINVAL;
+ goto error;
+ }
+
+ buf[len] = '\0'; /* terminate the string */
+
+ if (sscanf(buf, "%u %u", &enable, &frame_count) != 2) {
+ rc = -EINVAL;
+ goto error;
+ }
+
+ display->misr_enable = enable;
+ display->misr_frame_count = frame_count;
+
+ mutex_lock(&display->display_lock);
+ rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
+ DSI_CORE_CLK, DSI_CLK_ON);
+ if (rc) {
+ pr_err("[%s] failed to enable DSI core clocks, rc=%d\n",
+ display->name, rc);
+ goto unlock;
+ }
+
+ _dsi_display_setup_misr(display);
+
+ rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
+ DSI_CORE_CLK, DSI_CLK_OFF);
+ if (rc) {
+ pr_err("[%s] failed to disable DSI core clocks, rc=%d\n",
+ display->name, rc);
+ goto unlock;
+ }
+
+ rc = user_len;
+unlock:
+ mutex_unlock(&display->display_lock);
+error:
+ kfree(buf);
+ return rc;
+}
+
+static ssize_t debugfs_misr_read(struct file *file,
+ char __user *user_buf,
+ size_t user_len,
+ loff_t *ppos)
+{
+ struct dsi_display *display = file->private_data;
+ char *buf;
+ u32 len = 0;
+ int rc = 0;
+ struct dsi_ctrl *dsi_ctrl;
+ int i;
+ u32 misr;
+ size_t max_len = min_t(size_t, user_len, MISR_BUFF_SIZE);
+
+ if (!display)
+ return -ENODEV;
+
+ if (*ppos)
+ return 0;
+
+ buf = kzalloc(max_len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ mutex_lock(&display->display_lock);
+ rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
+ DSI_CORE_CLK, DSI_CLK_ON);
+ if (rc) {
+ pr_err("[%s] failed to enable DSI core clocks, rc=%d\n",
+ display->name, rc);
+ goto error;
+ }
+
+ for (i = 0; i < display->ctrl_count; i++) {
+ dsi_ctrl = display->ctrl[i].ctrl;
+ misr = dsi_ctrl_collect_misr(display->ctrl[i].ctrl);
+
+ len += snprintf((buf + len), max_len - len,
+ "DSI_%d MISR: 0x%x\n", dsi_ctrl->cell_index, misr);
+
+ if (len >= max_len)
+ break;
+ }
+
+ rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
+ DSI_CORE_CLK, DSI_CLK_OFF);
+ if (rc) {
+ pr_err("[%s] failed to disable DSI core clocks, rc=%d\n",
+ display->name, rc);
+ goto error;
+ }
+
+ if (copy_to_user(user_buf, buf, len)) {
+ rc = -EFAULT;
+ goto error;
+ }
+
+ *ppos += len;
+
+error:
+ mutex_unlock(&display->display_lock);
+ kfree(buf);
+ return len;
+}
static const struct file_operations dump_info_fops = {
.open = simple_open,
.read = debugfs_dump_info_read,
};
+static const struct file_operations misr_data_fops = {
+ .open = simple_open,
+ .read = debugfs_misr_read,
+ .write = debugfs_misr_setup,
+};
+
static int dsi_display_debugfs_init(struct dsi_display *display)
{
int rc = 0;
- struct dentry *dir, *dump_file;
+ struct dentry *dir, *dump_file, *misr_data;
dir = debugfs_create_dir(display->name, NULL);
if (IS_ERR_OR_NULL(dir)) {
@@ -199,13 +373,25 @@
}
dump_file = debugfs_create_file("dump_info",
- 0444,
+ 0400,
dir,
display,
&dump_info_fops);
if (IS_ERR_OR_NULL(dump_file)) {
rc = PTR_ERR(dump_file);
- pr_err("[%s] debugfs create file failed, rc=%d\n",
+ pr_err("[%s] debugfs create dump info file failed, rc=%d\n",
+ display->name, rc);
+ goto error_remove_dir;
+ }
+
+ misr_data = debugfs_create_file("misr_data",
+ 0600,
+ dir,
+ display,
+ &misr_data_fops);
+ if (IS_ERR_OR_NULL(misr_data)) {
+ rc = PTR_ERR(misr_data);
+ pr_err("[%s] debugfs create misr datafile failed, rc=%d\n",
display->name, rc);
goto error_remove_dir;
}
@@ -615,29 +801,46 @@
return rc;
}
-static int dsi_display_parse_cmdline_topology(unsigned int display_type)
+static void dsi_display_parse_cmdline_topology(struct dsi_display *display,
+ unsigned int display_type)
{
+ char *boot_str = NULL;
char *str = NULL;
- int top_index = -1;
+ unsigned long value;
if (display_type >= MAX_DSI_ACTIVE_DISPLAY) {
pr_err("display_type=%d not supported\n", display_type);
- return -EINVAL;
+ return;
}
+
if (display_type == DSI_PRIMARY)
- str = strnstr(dsi_display_primary,
- ":config", strlen(dsi_display_primary));
+ boot_str = dsi_display_primary;
else
- str = strnstr(dsi_display_secondary,
- ":config", strlen(dsi_display_secondary));
+ boot_str = dsi_display_secondary;
+
+ str = strnstr(boot_str, ":config", strlen(boot_str));
if (!str)
- return -EINVAL;
+ return;
if (kstrtol(str + strlen(":config"), INT_BASE_10,
- (unsigned long *)&top_index))
- return -EINVAL;
+ (unsigned long *)&value)) {
+ pr_err("invalid config index override: %s\n", boot_str);
+ return;
+ }
+ display->cmdline_topology = value;
- return top_index;
+ str = strnstr(boot_str, ":timing", strlen(boot_str));
+ if (!str)
+ return;
+
+ if (kstrtol(str + strlen(":timing"), INT_BASE_10,
+ (unsigned long *)&value)) {
+ pr_err("invalid timing index override: %s. resetting both timing and config\n",
+ boot_str);
+ display->cmdline_topology = NO_OVERRIDE;
+ return;
+ }
+ display->cmdline_timing = value;
}
/**
@@ -904,6 +1107,32 @@
return 0;
}
+static int dsi_display_ctrl_update(struct dsi_display *display)
+{
+ int rc = 0;
+ int i;
+ struct dsi_display_ctrl *ctrl;
+
+ for (i = 0 ; i < display->ctrl_count; i++) {
+ ctrl = &display->ctrl[i];
+ rc = dsi_ctrl_host_timing_update(ctrl->ctrl);
+ if (rc) {
+ pr_err("[%s] failed to update host_%d, rc=%d\n",
+ display->name, i, rc);
+ goto error_host_deinit;
+ }
+ }
+
+ return 0;
+error_host_deinit:
+ for (i = i - 1; i >= 0; i--) {
+ ctrl = &display->ctrl[i];
+ (void)dsi_ctrl_host_deinit(ctrl->ctrl);
+ }
+
+ return rc;
+}
+
static int dsi_display_ctrl_init(struct dsi_display *display)
{
int rc = 0;
@@ -2054,17 +2283,6 @@
goto error_ctrl_put;
}
- if (display->panel->phy_timing_len) {
- for (i = 0; i < display->ctrl_count; i++) {
- ctrl = &display->ctrl[i];
- rc = dsi_phy_set_timing_params(ctrl->phy,
- display->panel->phy_timing_val,
- display->panel->phy_timing_len);
- if (rc)
- pr_err("failed to add DSI PHY timing params");
- }
- }
-
rc = dsi_display_parse_lane_map(display);
if (rc) {
pr_err("Lane map not found, rc=%d\n", rc);
@@ -2103,6 +2321,9 @@
dsi_ctrl_put(ctrl->ctrl);
}
+ if (display->panel)
+ dsi_panel_put(display->panel);
+
return rc;
}
@@ -2141,12 +2362,12 @@
{
struct dsi_display_mode *cur;
- if (!display || !tgt) {
+ if (!display || !tgt || !display->panel) {
pr_err("Invalid params\n");
return false;
}
- cur = &display->panel->mode;
+ cur = display->panel->cur_mode;
if (cur->timing.h_active != tgt->timing.h_active) {
pr_debug("timing.h_active differs %d %d\n",
@@ -2225,12 +2446,6 @@
pr_debug("pixel_clk_khz differs %d %d\n",
cur->pixel_clk_khz, tgt->pixel_clk_khz);
- if (cur->panel_mode != tgt->panel_mode) {
- pr_debug("panel_mode differs %d %d\n",
- cur->panel_mode, tgt->panel_mode);
- return false;
- }
-
if (cur->dsi_mode_flags != tgt->dsi_mode_flags)
pr_debug("flags differs %d %d\n",
cur->dsi_mode_flags, tgt->dsi_mode_flags);
@@ -2248,7 +2463,7 @@
int rc = 0;
int i = 0;
- if (!display || !dsi_mode) {
+ if (!display || !dsi_mode || !display->panel) {
pr_err("Invalid params\n");
return -EINVAL;
}
@@ -2291,7 +2506,7 @@
}
}
- panel_mode = &display->panel->mode;
+ panel_mode = display->panel->cur_mode;
memcpy(panel_mode, dsi_mode, sizeof(*panel_mode));
/*
* dsi_mode_flags flags are used to communicate with other drm driver
@@ -2446,6 +2661,14 @@
int rc = 0;
int i;
struct dsi_display_ctrl *ctrl;
+ struct dsi_display_mode_priv_info *priv_info;
+
+ priv_info = mode->priv_info;
+ if (!priv_info) {
+ pr_err("[%s] failed to get private info of the display mode",
+ display->name);
+ return -EINVAL;
+ }
rc = dsi_panel_get_host_cfg_for_mode(display->panel,
mode,
@@ -2478,6 +2701,17 @@
goto error;
}
}
+
+ if (priv_info->phy_timing_len) {
+ for (i = 0; i < display->ctrl_count; i++) {
+ ctrl = &display->ctrl[i];
+ rc = dsi_phy_set_timing_params(ctrl->phy,
+ priv_info->phy_timing_val,
+ priv_info->phy_timing_len);
+ if (rc)
+ pr_err("failed to add DSI PHY timing params");
+ }
+ }
error:
return rc;
}
@@ -2704,19 +2938,10 @@
goto error_host_deinit;
}
- rc = dsi_panel_get_mode_count(display->panel, &display->num_of_modes);
- if (rc) {
- pr_err("[%s] failed to get mode count, rc=%d\n",
- display->name, rc);
- goto error_panel_deinit;
- }
-
pr_info("Successfully bind display panel '%s'\n", display->name);
display->drm_dev = drm;
goto error;
-error_panel_deinit:
- (void)dsi_panel_drv_deinit(display->panel);
error_host_deinit:
(void)dsi_display_mipi_host_deinit(display);
error_clk_client_deinit:
@@ -2833,8 +3058,10 @@
boot_displays_parsed = true;
}
- /* Initialize cmdline_topology to use default topology */
- display->cmdline_topology = -1;
+ /* use default topology of every mode if not overridden */
+ display->cmdline_topology = NO_OVERRIDE;
+ display->cmdline_timing = 0;
+
if ((!display_from_cmdline) &&
(boot_displays[DSI_PRIMARY].boot_disp_en)) {
display->is_active = dsi_display_name_compare(pdev->dev.of_node,
@@ -2860,8 +3087,8 @@
pr_debug("cmdline primary dsi: %s\n",
display->name);
display_from_cmdline = true;
- display->cmdline_topology =
- dsi_display_parse_cmdline_topology(DSI_PRIMARY);
+ dsi_display_parse_cmdline_topology(display,
+ DSI_PRIMARY);
primary_np = pdev->dev.of_node;
}
}
@@ -2876,9 +3103,8 @@
if (primary_np) {
if (validate_dsi_display_selection()) {
display->is_active = true;
- display->cmdline_topology =
dsi_display_parse_cmdline_topology
- (DSI_SECONDARY);
+ (display, DSI_SECONDARY);
} else {
boot_displays[DSI_SECONDARY]
.boot_disp_en = false;
@@ -3079,7 +3305,6 @@
{
struct dsi_display *display;
struct dsi_panel_phy_props phy_props;
- struct dsi_mode_info *timing;
int i, rc;
if (!info || !disp) {
@@ -3103,32 +3328,18 @@
memset(info, 0, sizeof(struct msm_display_info));
info->intf_type = DRM_MODE_CONNECTOR_DSI;
- timing = &display->panel->mode.timing;
-
info->num_of_h_tiles = display->ctrl_count;
for (i = 0; i < info->num_of_h_tiles; i++)
info->h_tile_instance[i] = display->ctrl[i].ctrl->cell_index;
info->is_connected = true;
info->is_primary = true;
- info->frame_rate = timing->refresh_rate;
- info->vtotal = DSI_V_TOTAL(timing);
- info->prefill_lines = display->panel->panel_prefill_lines;
- info->jitter_numer = display->panel->panel_jitter_numer;
- info->jitter_denom = display->panel->panel_jitter_denom;
info->width_mm = phy_props.panel_width_mm;
info->height_mm = phy_props.panel_height_mm;
info->max_width = 1920;
info->max_height = 1080;
- info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_NONE;
- if (display->panel->dsc_enabled) {
- info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_DSC;
- memcpy(&info->comp_info.dsc_info, &display->panel->dsc,
- sizeof(struct msm_display_dsc_info));
- }
-
- switch (display->panel->mode.panel_mode) {
+ switch (display->panel->panel_mode) {
case DSI_OP_VIDEO_MODE:
info->capabilities |= MSM_DISPLAY_CAP_VID_MODE;
break;
@@ -3139,7 +3350,7 @@
break;
default:
pr_err("unknwown dsi panel mode %d\n",
- display->panel->mode.panel_mode);
+ display->panel->panel_mode);
break;
}
@@ -3151,16 +3362,57 @@
return rc;
}
-int dsi_display_get_modes(struct dsi_display *display,
- struct dsi_display_mode *modes,
- u32 *count)
+int dsi_display_get_mode_count(struct dsi_display *display,
+ u32 *count)
{
- int rc = 0;
- int i;
struct dsi_dfps_capabilities dfps_caps;
- int num_dfps_rates;
+ int num_dfps_rates, rc = 0;
- if (!display || !count) {
+ if (!display || !display->panel) {
+ pr_err("invalid display:%d panel:%d\n", display != NULL,
+ display ? display->panel != NULL : 0);
+ return -EINVAL;
+ }
+
+ mutex_lock(&display->display_lock);
+
+ *count = display->panel->num_timing_nodes;
+
+ rc = dsi_panel_get_dfps_caps(display->panel, &dfps_caps);
+ if (rc) {
+ pr_err("[%s] failed to get dfps caps from panel\n",
+ display->name);
+ goto done;
+ }
+
+ num_dfps_rates = !dfps_caps.dfps_support ? 1 :
+ dfps_caps.max_refresh_rate -
+ dfps_caps.min_refresh_rate + 1;
+
+ /* Inflate num_of_modes by fps in dfps */
+ *count = display->panel->num_timing_nodes * num_dfps_rates;
+
+done:
+ mutex_unlock(&display->display_lock);
+
+ return 0;
+}
+
+void dsi_display_put_mode(struct dsi_display *display,
+ struct dsi_display_mode *mode)
+{
+ dsi_panel_put_mode(mode);
+}
+
+int dsi_display_get_modes(struct dsi_display *display,
+ struct dsi_display_mode *modes)
+{
+ struct dsi_dfps_capabilities dfps_caps;
+ u32 num_dfps_rates, panel_mode_count;
+ u32 mode_idx, array_idx = 0;
+ int i, rc = 0;
+
+ if (!display || !modes) {
pr_err("Invalid params\n");
return -EINVAL;
}
@@ -3178,41 +3430,55 @@
dfps_caps.max_refresh_rate -
dfps_caps.min_refresh_rate + 1;
- if (!modes) {
- /* Inflate num_of_modes by fps in dfps */
- *count = display->num_of_modes * num_dfps_rates;
- goto error;
- }
+ panel_mode_count = display->panel->num_timing_nodes;
- for (i = 0; i < *count; i++) {
- /* Insert the dfps "sub-modes" between main panel modes */
- int panel_mode_idx = i / num_dfps_rates;
+ for (mode_idx = 0; mode_idx < panel_mode_count; mode_idx++) {
+ struct dsi_display_mode panel_mode;
+ int topology_override = NO_OVERRIDE;
- rc = dsi_panel_get_mode(display->panel, panel_mode_idx, modes);
+ if (display->cmdline_timing == mode_idx)
+ topology_override = display->cmdline_topology;
+
+ memset(&panel_mode, 0, sizeof(panel_mode));
+
+ rc = dsi_panel_get_mode(display->panel, mode_idx,
+ &panel_mode, topology_override);
if (rc) {
- pr_err("[%s] failed to get mode from panel\n",
- display->name);
+ pr_err("[%s] failed to get mode idx %d from panel\n",
+ display->name, mode_idx);
goto error;
}
- if (dfps_caps.dfps_support) {
- modes->timing.refresh_rate = dfps_caps.min_refresh_rate
- + (i % num_dfps_rates);
- modes->pixel_clk_khz = (DSI_H_TOTAL(&modes->timing) *
- DSI_V_TOTAL(&modes->timing) *
- modes->timing.refresh_rate) / 1000;
- }
-
if (display->ctrl_count > 1) { /* TODO: remove if */
- modes->timing.h_active *= display->ctrl_count;
- modes->timing.h_front_porch *= display->ctrl_count;
- modes->timing.h_sync_width *= display->ctrl_count;
- modes->timing.h_back_porch *= display->ctrl_count;
- modes->timing.h_skew *= display->ctrl_count;
- modes->pixel_clk_khz *= display->ctrl_count;
+ panel_mode.timing.h_active *= display->ctrl_count;
+ panel_mode.timing.h_front_porch *= display->ctrl_count;
+ panel_mode.timing.h_sync_width *= display->ctrl_count;
+ panel_mode.timing.h_back_porch *= display->ctrl_count;
+ panel_mode.timing.h_skew *= display->ctrl_count;
+ panel_mode.pixel_clk_khz *= display->ctrl_count;
}
- modes++;
+ for (i = 0; i < num_dfps_rates; i++) {
+ struct dsi_display_mode *sub_mode = &modes[array_idx];
+
+ if (!sub_mode) {
+ pr_err("invalid mode data\n");
+ return -EFAULT;
+ }
+
+ memcpy(sub_mode, &panel_mode, sizeof(panel_mode));
+
+ if (dfps_caps.dfps_support) {
+ sub_mode->timing.refresh_rate =
+ dfps_caps.min_refresh_rate +
+ (i % num_dfps_rates);
+ sub_mode->pixel_clk_khz =
+ (DSI_H_TOTAL(&sub_mode->timing) *
+ DSI_V_TOTAL(&sub_mode->timing) *
+ sub_mode->timing.refresh_rate) / 1000;
+ }
+ array_idx++;
+ }
}
error:
@@ -3285,7 +3551,7 @@
int rc = 0;
struct dsi_display_mode adj_mode;
- if (!display || !mode) {
+ if (!display || !mode || !display->panel) {
pr_err("Invalid params\n");
return -EINVAL;
}
@@ -3306,6 +3572,17 @@
pr_err("[%s] failed to set mode\n", display->name);
goto error;
}
+
+ if (!display->panel->cur_mode) {
+ display->panel->cur_mode =
+ kzalloc(sizeof(struct dsi_display_mode), GFP_KERNEL);
+ if (!display->panel->cur_mode) {
+ rc = -ENOMEM;
+ goto error;
+ }
+ }
+
+ memcpy(display->panel->cur_mode, &adj_mode, sizeof(adj_mode));
error:
mutex_unlock(&display->display_lock);
return rc;
@@ -3337,17 +3614,80 @@
return rc;
}
+static int dsi_display_pre_switch(struct dsi_display *display)
+{
+ int rc = 0;
+
+ rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
+ DSI_CORE_CLK, DSI_CLK_ON);
+ if (rc) {
+ pr_err("[%s] failed to enable DSI core clocks, rc=%d\n",
+ display->name, rc);
+ goto error;
+ }
+
+ rc = dsi_display_ctrl_update(display);
+ if (rc) {
+ pr_err("[%s] failed to update DSI controller, rc=%d\n",
+ display->name, rc);
+ goto error_ctrl_clk_off;
+ }
+
+ rc = dsi_display_set_clk_src(display);
+ if (rc) {
+ pr_err("[%s] failed to set DSI link clock source, rc=%d\n",
+ display->name, rc);
+ goto error_ctrl_deinit;
+ }
+
+ rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
+ DSI_LINK_CLK, DSI_CLK_ON);
+ if (rc) {
+ pr_err("[%s] failed to enable DSI link clocks, rc=%d\n",
+ display->name, rc);
+ goto error_ctrl_deinit;
+ }
+
+ goto error;
+
+error_ctrl_deinit:
+ (void)dsi_display_ctrl_deinit(display);
+error_ctrl_clk_off:
+ (void)dsi_display_clk_ctrl(display->dsi_clk_handle,
+ DSI_CORE_CLK, DSI_CLK_OFF);
+error:
+ return rc;
+}
+
int dsi_display_prepare(struct dsi_display *display)
{
int rc = 0;
+ struct dsi_display_mode *mode;
if (!display) {
pr_err("Invalid params\n");
return -EINVAL;
}
+ if (!display->panel->cur_mode) {
+ pr_err("no valid mode set for the display");
+ return -EINVAL;
+ }
+
mutex_lock(&display->display_lock);
+ mode = display->panel->cur_mode;
+
+ if (mode->dsi_mode_flags & DSI_MODE_FLAG_DMS) {
+ /* update dsi ctrl for new mode */
+ rc = dsi_display_pre_switch(display);
+ if (rc)
+ pr_err("[%s] panel pre-prepare-res-switch failed, rc=%d\n",
+ display->name, rc);
+
+ goto error;
+ }
+
rc = dsi_panel_pre_prepare(display->panel);
if (rc) {
pr_err("[%s] panel pre-prepare failed, rc=%d\n",
@@ -3376,6 +3716,13 @@
goto error_ctrl_clk_off;
}
+ rc = dsi_display_set_clk_src(display);
+ if (rc) {
+ pr_err("[%s] failed to set DSI link clock source, rc=%d\n",
+ display->name, rc);
+ goto error_phy_disable;
+ }
+
rc = dsi_display_ctrl_init(display);
if (rc) {
pr_err("[%s] failed to setup DSI controller, rc=%d\n",
@@ -3383,10 +3730,10 @@
goto error_phy_disable;
}
- rc = dsi_display_set_clk_src(display);
+ rc = dsi_display_ctrl_host_enable(display);
if (rc) {
- pr_err("[%s] failed to set DSI link clock source, rc=%d\n",
- display->name, rc);
+ pr_err("[%s] failed to enable DSI host, rc=%d\n",
+ display->name, rc);
goto error_ctrl_deinit;
}
@@ -3395,29 +3742,28 @@
if (rc) {
pr_err("[%s] failed to enable DSI link clocks, rc=%d\n",
display->name, rc);
- goto error_ctrl_deinit;
+ goto error_host_engine_off;
}
- rc = dsi_display_ctrl_host_enable(display);
+ rc = dsi_display_soft_reset(display);
if (rc) {
- pr_err("[%s] failed to enable DSI host, rc=%d\n",
- display->name, rc);
+ pr_err("[%s] failed soft reset, rc=%d\n", display->name, rc);
goto error_ctrl_link_off;
}
rc = dsi_panel_prepare(display->panel);
if (rc) {
pr_err("[%s] panel prepare failed, rc=%d\n", display->name, rc);
- goto error_host_engine_off;
+ goto error_ctrl_link_off;
}
goto error;
-error_host_engine_off:
- (void)dsi_display_ctrl_host_disable(display);
error_ctrl_link_off:
(void)dsi_display_clk_ctrl(display->dsi_clk_handle,
DSI_LINK_CLK, DSI_CLK_OFF);
+error_host_engine_off:
+ (void)dsi_display_ctrl_host_disable(display);
error_ctrl_deinit:
(void)dsi_display_ctrl_deinit(display);
error_phy_disable:
@@ -3533,6 +3879,10 @@
{
int rc = 0;
+ /* check and setup MISR */
+ if (display->misr_enable)
+ _dsi_display_setup_misr(display);
+
rc = dsi_display_set_roi(display, params->rois);
return rc;
@@ -3541,23 +3891,40 @@
int dsi_display_enable(struct dsi_display *display)
{
int rc = 0;
+ struct dsi_display_mode *mode;
- if (!display) {
+ if (!display || !display->panel) {
pr_err("Invalid params\n");
return -EINVAL;
}
+ if (!display->panel->cur_mode) {
+ pr_err("no valid mode set for the display");
+ return -EINVAL;
+ }
+
mutex_lock(&display->display_lock);
- rc = dsi_panel_enable(display->panel);
- if (rc) {
- pr_err("[%s] failed to enable DSI panel, rc=%d\n",
- display->name, rc);
- goto error;
+ mode = display->panel->cur_mode;
+
+ if (mode->dsi_mode_flags & DSI_MODE_FLAG_DMS) {
+ rc = dsi_panel_post_switch(display->panel);
+ if (rc) {
+ pr_err("[%s] failed to switch DSI panel mode, rc=%d\n",
+ display->name, rc);
+ goto error;
+ }
+ } else {
+ rc = dsi_panel_enable(display->panel);
+ if (rc) {
+ pr_err("[%s] failed to enable DSI panel, rc=%d\n",
+ display->name, rc);
+ goto error;
+ }
}
- if (display->panel->dsc_enabled) {
- display->panel->dsc.pic_width *= display->ctrl_count;
+ if (mode->priv_info->dsc_enabled) {
+ mode->priv_info->dsc.pic_width *= display->ctrl_count;
rc = dsi_panel_update_pps(display->panel);
if (rc) {
pr_err("[%s] panel pps cmd update failed, rc=%d\n",
@@ -3566,6 +3933,15 @@
}
}
+ if (mode->dsi_mode_flags & DSI_MODE_FLAG_DMS) {
+ rc = dsi_panel_switch(display->panel);
+ if (rc)
+ pr_err("[%s] failed to switch DSI panel mode, rc=%d\n",
+ display->name, rc);
+
+ goto error;
+ }
+
if (display->config.panel_mode == DSI_OP_VIDEO_MODE) {
rc = dsi_display_vid_engine_enable(display);
if (rc) {
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
index b382e4a..1c30b9c 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
@@ -141,8 +141,8 @@
* @clock_info: Clock sourcing for DSI display.
* @config: DSI host configuration information.
* @lane_map: Lane mapping between DSI host and Panel.
- * @num_of_modes: Number of modes supported by display.
* @cmdline_topology: Display topology shared from kernel command line.
+ * @cmdline_timing: Display timing shared from kernel command line.
* @is_tpg_enabled: TPG state.
* @ulps_enabled: ulps state.
* @clamp_enabled: clamp state.
@@ -154,6 +154,8 @@
* @dsi_clk_handle: DSI clock handle.
* @mdp_clk_handle: MDP clock handle.
* @root: Debugfs root directory
+ * @misr_enable Frame MISR enable/disable
+ * @misr_frame_count Number of frames to accumulate the MISR value
*/
struct dsi_display {
struct platform_device *pdev;
@@ -180,8 +182,8 @@
struct dsi_display_clk_info clock_info;
struct dsi_host_config config;
struct dsi_lane_map lane_map;
- u32 num_of_modes;
int cmdline_topology;
+ int cmdline_timing;
bool is_tpg_enabled;
bool ulps_enabled;
bool clamp_enabled;
@@ -201,6 +203,9 @@
/* DEBUG FS */
struct dentry *root;
+
+ bool misr_enable;
+ u32 misr_frame_count;
};
int dsi_display_dev_probe(struct platform_device *pdev);
@@ -275,21 +280,36 @@
int dsi_display_get_info(struct msm_display_info *info, void *disp);
/**
+ * dsi_display_get_mode_count() - get number of modes supported by the display
+ * @display: Handle to display.
+ * @count: Number of modes supported
+ *
+ * Return: error code.
+ */
+int dsi_display_get_mode_count(struct dsi_display *display, u32 *count);
+
+/**
* dsi_display_get_modes() - get modes supported by display
* @display: Handle to display.
* @modes; Pointer to array of modes. Memory allocated should be
* big enough to store (count * struct dsi_display_mode)
* elements. If modes pointer is NULL, number of modes will
* be stored in the memory pointed to by count.
- * @count: If modes is NULL, number of modes will be stored. If
- * not, mode information will be copied (number of modes
- * copied will be equal to *count).
*
* Return: error code.
*/
int dsi_display_get_modes(struct dsi_display *display,
- struct dsi_display_mode *modes,
- u32 *count);
+ struct dsi_display_mode *modes);
+
+/**
+ * dsi_display_put_mode() - free up mode created for the display
+ * @display: Handle to display.
+ * @mode: Display mode to be freed up
+ *
+ * Return: error code.
+ */
+void dsi_display_put_mode(struct dsi_display *display,
+ struct dsi_display_mode *mode);
/**
* dsi_display_validate_mode() - validates if mode is supported by display
@@ -472,6 +492,22 @@
*/
int dsi_display_soft_reset(void *display);
+/**
+ * dsi_display_set_power - update power/dpms setting
+ * @connector: Pointer to drm connector structure
+ * @power_mode: One of the following,
+ * SDE_MODE_DPMS_ON
+ * SDE_MODE_DPMS_LP1
+ * SDE_MODE_DPMS_LP2
+ * SDE_MODE_DPMS_STANDBY
+ * SDE_MODE_DPMS_SUSPEND
+ * SDE_MODE_DPMS_OFF
+ * @display: Pointer to private display structure
+ * Returns: Zero on success
+ */
+int dsi_display_set_power(struct drm_connector *connector,
+ int power_mode, void *display);
+
/*
* dsi_display_pre_kickoff - program kickoff-time features
* @display: Pointer to private display structure
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display_test.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display_test.c
index 93fb041..6e41f36 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display_test.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display_test.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017, The Linux Foundation. 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 and
@@ -34,7 +34,7 @@
test = container_of(work, struct dsi_display_test, test_work);
display = test->display;
- rc = dsi_display_get_modes(display, NULL, &count);
+ rc = dsi_display_get_mode_count(display, &count);
if (rc) {
pr_err("failed to get modes count, rc=%d\n", rc);
goto test_fail;
@@ -47,7 +47,7 @@
goto test_fail;
}
- rc = dsi_display_get_modes(display, modes, &count);
+ rc = dsi_display_get_modes(display, modes);
if (rc) {
pr_err("failed to get modes, rc=%d\n", rc);
goto test_fail_free_modes;
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c
index b499bd6..30e5f02 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c
@@ -49,9 +49,9 @@
dsi_mode->timing.refresh_rate = drm_mode->vrefresh;
dsi_mode->pixel_clk_khz = drm_mode->clock;
- dsi_mode->panel_mode = 0; /* TODO: Panel Mode */
- dsi_mode->mode_info = (struct msm_mode_info *)drm_mode->private;
+ dsi_mode->priv_info =
+ (struct dsi_display_mode_priv_info *)drm_mode->private;
if (msm_is_mode_seamless(drm_mode))
dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_SEAMLESS;
@@ -59,6 +59,8 @@
dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_DFPS;
if (msm_needs_vblank_pre_modeset(drm_mode))
dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_VBLANK_PRE_MODESET;
+ if (msm_is_mode_seamless_dms(drm_mode))
+ dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_DMS;
}
static void convert_to_drm_mode(const struct dsi_display_mode *dsi_mode,
@@ -84,7 +86,7 @@
drm_mode->vrefresh = dsi_mode->timing.refresh_rate;
drm_mode->clock = dsi_mode->pixel_clk_khz;
- drm_mode->private = (int *)dsi_mode->mode_info;
+ drm_mode->private = (int *)dsi_mode->priv_info;
if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_SEAMLESS)
drm_mode->flags |= DRM_MODE_FLAG_SEAMLESS;
@@ -92,6 +94,8 @@
drm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_DYNAMIC_FPS;
if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_VBLANK_PRE_MODESET)
drm_mode->private_flags |= MSM_MODE_FLAG_VBLANK_PRE_MODESET;
+ if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_DMS)
+ drm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_DMS;
drm_mode_set_name(drm_mode);
}
@@ -237,10 +241,6 @@
memset(&(c_bridge->dsi_mode), 0x0, sizeof(struct dsi_display_mode));
convert_to_dsi_mode(adjusted_mode, &(c_bridge->dsi_mode));
-
- pr_debug("note: using panel cmd/vid mode instead of user val\n");
- c_bridge->dsi_mode.panel_mode =
- c_bridge->display->panel->mode.panel_mode;
}
static bool dsi_bridge_mode_fixup(struct drm_bridge *bridge,
@@ -248,9 +248,9 @@
struct drm_display_mode *adjusted_mode)
{
int rc = 0;
- bool ret = true;
struct dsi_bridge *c_bridge = to_dsi_bridge(bridge);
struct dsi_display_mode dsi_mode;
+ struct drm_display_mode cur_mode;
if (!bridge || !mode || !adjusted_mode) {
pr_err("Invalid params\n");
@@ -263,31 +263,55 @@
DSI_VALIDATE_FLAG_ALLOW_ADJUST);
if (rc) {
pr_err("[%d] mode is not valid, rc=%d\n", c_bridge->id, rc);
- ret = false;
- } else {
- convert_to_drm_mode(&dsi_mode, adjusted_mode);
+ return false;
}
- return ret;
+ if (bridge->encoder && bridge->encoder->crtc) {
+ cur_mode = bridge->encoder->crtc->mode;
+
+ if (!drm_mode_equal(&cur_mode, adjusted_mode))
+ dsi_mode.dsi_mode_flags |= DSI_MODE_FLAG_DMS;
+ }
+
+ convert_to_drm_mode(&dsi_mode, adjusted_mode);
+
+ return true;
}
-int dsi_conn_get_topology(const struct drm_display_mode *drm_mode,
- struct msm_display_topology *topology,
+int dsi_conn_get_mode_info(const struct drm_display_mode *drm_mode,
+ struct msm_mode_info *mode_info,
u32 max_mixer_width)
{
struct dsi_display_mode dsi_mode;
+ struct dsi_mode_info *timing;
- if (!drm_mode || !topology)
+ if (!drm_mode || !mode_info)
return -EINVAL;
convert_to_dsi_mode(drm_mode, &dsi_mode);
- if (!dsi_mode.mode_info)
+ if (!dsi_mode.priv_info)
return -EINVAL;
- memcpy(topology, &dsi_mode.mode_info->topology,
+ memset(mode_info, 0, sizeof(*mode_info));
+
+ timing = &dsi_mode.timing;
+ mode_info->frame_rate = dsi_mode.timing.refresh_rate;
+ mode_info->vtotal = DSI_V_TOTAL(timing);
+ mode_info->prefill_lines = dsi_mode.priv_info->panel_prefill_lines;
+ mode_info->jitter_numer = dsi_mode.priv_info->panel_jitter_numer;
+ mode_info->jitter_denom = dsi_mode.priv_info->panel_jitter_denom;
+
+ memcpy(&mode_info->topology, &dsi_mode.priv_info->topology,
sizeof(struct msm_display_topology));
+ mode_info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_NONE;
+ if (dsi_mode.priv_info->dsc_enabled) {
+ mode_info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_DSC;
+ memcpy(&mode_info->comp_info.dsc_info, &dsi_mode.priv_info->dsc,
+ sizeof(dsi_mode.priv_info->dsc));
+ }
+
return 0;
}
@@ -343,7 +367,7 @@
panel = dsi_display->panel;
sde_kms_info_add_keystr(info, "panel name", panel->name);
- switch (panel->mode.panel_mode) {
+ switch (panel->panel_mode) {
case DSI_OP_VIDEO_MODE:
sde_kms_info_add_keystr(info, "panel mode", "video");
break;
@@ -353,7 +377,7 @@
panel->cmd_config.mdp_transfer_time_us);
break;
default:
- pr_debug("invalid panel type:%d\n", panel->mode.panel_mode);
+ pr_debug("invalid panel type:%d\n", panel->panel_mode);
break;
}
sde_kms_info_add_keystr(info, "dfps support",
@@ -449,6 +473,21 @@
return status;
}
+void dsi_connector_put_modes(struct drm_connector *connector,
+ void *display)
+{
+ struct drm_display_mode *drm_mode;
+ struct dsi_display_mode dsi_mode;
+
+ if (!connector || !display)
+ return;
+
+ list_for_each_entry(drm_mode, &connector->modes, head) {
+ convert_to_dsi_mode(drm_mode, &dsi_mode);
+ dsi_display_put_mode(display, &dsi_mode);
+ }
+}
+
int dsi_connector_get_modes(struct drm_connector *connector,
void *display)
{
@@ -466,7 +505,7 @@
*/
goto end;
}
- rc = dsi_display_get_modes(display, NULL, &count);
+ rc = dsi_display_get_mode_count(display, &count);
if (rc) {
pr_err("failed to get num of modes, rc=%d\n", rc);
goto error;
@@ -479,7 +518,7 @@
goto end;
}
- rc = dsi_display_get_modes(display, modes, &count);
+ rc = dsi_display_get_modes(display, modes);
if (rc) {
pr_err("failed to get modes, rc=%d\n", rc);
count = 0;
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h
index 45feec9..793f8f1 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h
@@ -64,15 +64,22 @@
void *display);
/**
- * dsi_conn_get_topology - retrieve current topology for the mode selected
+ * dsi_connector_put_modes - callback to free up drm modes of the connector
+ * @connector: Pointer to drm connector structure
+ * @display: Pointer to private display handle
+ */
+void dsi_connector_put_modes(struct drm_connector *connector,
+ void *display);
+
+/**
+ * dsi_conn_get_mode_info - retrieve information on the mode selected
* @drm_mode: Display mode set for the display
- * @topology: Out parameter. Topology for the mode.
+ * @mode_info: Out parameter. information of the mode.
* @max_mixer_width: max width supported by HW layer mixer
* Returns: Zero on success
*/
-int dsi_conn_get_topology(const struct drm_display_mode *drm_mode,
- struct msm_display_topology *topology,
- u32 max_mixer_width);
+int dsi_conn_get_mode_info(const struct drm_display_mode *drm_mode,
+ struct msm_mode_info *mode_info, u32 max_mixer_width);
/**
* dsi_conn_mode_valid - callback to determine if specified mode is valid
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
index 8bc82f5..f7b0d7f 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
@@ -471,11 +471,21 @@
{
int rc = 0, i = 0;
ssize_t len;
- struct dsi_cmd_desc *cmds = panel->cmd_sets[type].cmds;
- u32 count = panel->cmd_sets[type].count;
- enum dsi_cmd_set_state state = panel->cmd_sets[type].state;
+ struct dsi_cmd_desc *cmds;
+ u32 count;
+ enum dsi_cmd_set_state state;
+ struct dsi_display_mode *mode;
const struct mipi_dsi_host_ops *ops = panel->host->ops;
+ if (!panel || !panel->cur_mode)
+ return -EINVAL;
+
+ mode = panel->cur_mode;
+
+ cmds = mode->priv_info->cmd_sets[type].cmds;
+ count = mode->priv_info->cmd_sets[type].count;
+ state = mode->priv_info->cmd_sets[type].state;
+
if (count == 0) {
pr_debug("[%s] No commands to be sent for state(%d)\n",
panel->name, type);
@@ -971,7 +981,7 @@
panel->name);
if (rc) {
pr_err("[%s] failed to get pixel format, rc=%d\n",
- panel->name, rc);
+ panel->name, rc);
goto error;
}
@@ -1266,7 +1276,7 @@
}
}
- panel->mode.panel_mode = panel_mode;
+ panel->panel_mode = panel_mode;
error:
return rc;
}
@@ -1333,8 +1343,13 @@
"qcom,video-to-cmd-mode-switch-commands",
"qcom,video-to-cmd-mode-post-switch-commands",
"qcom,mdss-dsi-panel-status-command",
+ "qcom,mdss-dsi-lp1-command",
+ "qcom,mdss-dsi-lp2-command",
+ "qcom,mdss-dsi-nolp-command",
"PPS not parsed from DTSI, generated dynamically",
"ROI not parsed from DTSI, generated dynamically",
+ "qcom,mdss-dsi-timing-switch-command",
+ "qcom,mdss-dsi-post-mode-switch-on-command",
};
const char *cmd_set_state_map[DSI_CMD_SET_MAX] = {
@@ -1352,8 +1367,13 @@
"qcom,video-to-cmd-mode-switch-commands-state",
"qcom,video-to-cmd-mode-post-switch-commands-state",
"qcom,mdss-dsi-panel-status-command-state",
+ "qcom,mdss-dsi-lp1-command-state",
+ "qcom,mdss-dsi-lp2-command-state",
+ "qcom,mdss-dsi-nolp-command-state",
"PPS not parsed from DTSI, generated dynamically",
"ROI not parsed from DTSI, generated dynamically",
+ "qcom,mdss-dsi-timing-switch-command-state",
+ "qcom,mdss-dsi-post-mode-switch-on-command-state",
};
static int dsi_panel_get_cmd_pkt_count(const char *data, u32 length, u32 *cnt)
@@ -1510,29 +1530,34 @@
}
-static int dsi_panel_parse_cmd_sets(struct dsi_panel *panel,
- struct device_node *of_node)
+static int dsi_panel_parse_cmd_sets(
+ struct dsi_display_mode_priv_info *priv_info,
+ struct device_node *of_node)
{
int rc = 0;
struct dsi_panel_cmd_set *set;
u32 i;
+ if (!priv_info) {
+ pr_err("invalid mode priv info\n");
+ return -EINVAL;
+ }
+
for (i = DSI_CMD_SET_PRE_ON; i < DSI_CMD_SET_MAX; i++) {
- set = &panel->cmd_sets[i];
+ set = &priv_info->cmd_sets[i];
set->type = i;
set->count = 0;
if (i == DSI_CMD_SET_PPS) {
rc = dsi_panel_alloc_cmd_packets(set, 1);
if (rc)
- pr_err("[%s] failed to allocate cmd set %d, rc = %d\n",
- panel->name, i, rc);
+ pr_err("failed to allocate cmd set %d, rc = %d\n",
+ i, rc);
set->state = DSI_CMD_SET_STATE_LP;
} else {
rc = dsi_panel_parse_cmd_sets_sub(set, i, of_node);
if (rc)
- pr_debug("[%s] failed to parse set %d\n",
- panel->name, i);
+ pr_debug("failed to parse set %d\n", i);
}
}
@@ -1621,13 +1646,17 @@
return 0;
}
-static int dsi_panel_parse_jitter_config(struct dsi_panel *panel,
- struct device_node *of_node)
+static int dsi_panel_parse_jitter_config(
+ struct dsi_display_mode *mode,
+ struct device_node *of_node)
{
int rc;
+ struct dsi_display_mode_priv_info *priv_info;
u32 jitter[DEFAULT_PANEL_JITTER_ARRAY_SIZE] = {0, 0};
u64 jitter_val = 0;
+ priv_info = mode->priv_info;
+
rc = of_property_read_u32_array(of_node, "qcom,mdss-dsi-panel-jitter",
jitter, DEFAULT_PANEL_JITTER_ARRAY_SIZE);
if (rc) {
@@ -1638,23 +1667,25 @@
}
if (rc || !jitter_val || (jitter_val > MAX_PANEL_JITTER)) {
- panel->panel_jitter_numer = DEFAULT_PANEL_JITTER_NUMERATOR;
- panel->panel_jitter_denom = DEFAULT_PANEL_JITTER_DENOMINATOR;
+ priv_info->panel_jitter_numer = DEFAULT_PANEL_JITTER_NUMERATOR;
+ priv_info->panel_jitter_denom =
+ DEFAULT_PANEL_JITTER_DENOMINATOR;
} else {
- panel->panel_jitter_numer = jitter[0];
- panel->panel_jitter_denom = jitter[1];
+ priv_info->panel_jitter_numer = jitter[0];
+ priv_info->panel_jitter_denom = jitter[1];
}
rc = of_property_read_u32(of_node, "qcom,mdss-dsi-panel-prefill-lines",
- &panel->panel_prefill_lines);
+ &priv_info->panel_prefill_lines);
if (rc) {
pr_debug("panel prefill lines are not defined rc=%d\n", rc);
- panel->panel_prefill_lines = DEFAULT_PANEL_PREFILL_LINES;
- } else if (panel->panel_prefill_lines >=
- DSI_V_TOTAL(&panel->mode.timing)) {
+ priv_info->panel_prefill_lines = DEFAULT_PANEL_PREFILL_LINES;
+ } else if (priv_info->panel_prefill_lines >=
+ DSI_V_TOTAL(&mode->timing)) {
pr_debug("invalid prefill lines config=%d setting to:%d\n",
- panel->panel_prefill_lines, DEFAULT_PANEL_PREFILL_LINES);
- panel->panel_prefill_lines = DEFAULT_PANEL_PREFILL_LINES;
+ priv_info->panel_prefill_lines, DEFAULT_PANEL_PREFILL_LINES);
+
+ priv_info->panel_prefill_lines = DEFAULT_PANEL_PREFILL_LINES;
}
return 0;
@@ -2041,38 +2072,85 @@
return 0;
}
-int dsi_panel_parse_dsc_params(struct dsi_panel *panel,
+
+static int dsi_panel_parse_phy_timing(struct dsi_display_mode *mode,
+ struct device_node *of_node)
+{
+ const char *data;
+ u32 len, i;
+ int rc = 0;
+ struct dsi_display_mode_priv_info *priv_info;
+
+ priv_info = mode->priv_info;
+
+ data = of_get_property(of_node,
+ "qcom,mdss-dsi-panel-phy-timings", &len);
+ if (!data) {
+ pr_debug("Unable to read Phy timing settings");
+ } else {
+ priv_info->phy_timing_val =
+ kzalloc((sizeof(u32) * len), GFP_KERNEL);
+ if (!priv_info->phy_timing_val)
+ return -EINVAL;
+
+ for (i = 0; i < len; i++)
+ priv_info->phy_timing_val[i] = data[i];
+
+ priv_info->phy_timing_len = len;
+ };
+
+ mode->pixel_clk_khz = (DSI_H_TOTAL(&mode->timing) *
+ DSI_V_TOTAL(&mode->timing) *
+ mode->timing.refresh_rate) / 1000;
+ return rc;
+}
+
+static int dsi_panel_parse_dsc_params(struct dsi_display_mode *mode,
struct device_node *of_node)
{
u32 data;
int rc = -EINVAL;
int intf_width;
+ const char *compression;
+ struct dsi_display_mode_priv_info *priv_info;
- if (!panel->dsc_enabled)
+ if (!mode || !mode->priv_info)
+ return -EINVAL;
+
+ priv_info = mode->priv_info;
+
+ priv_info->dsc_enabled = false;
+ compression = of_get_property(of_node, "qcom,compression-mode", NULL);
+ if (compression && !strcmp(compression, "dsc"))
+ priv_info->dsc_enabled = true;
+
+ if (!priv_info->dsc_enabled) {
+ pr_debug("dsc compression is not enabled for the mode");
return 0;
+ }
rc = of_property_read_u32(of_node, "qcom,mdss-dsc-slice-height", &data);
if (rc) {
pr_err("failed to parse qcom,mdss-dsc-slice-height\n");
goto error;
}
- panel->dsc.slice_height = data;
+ priv_info->dsc.slice_height = data;
rc = of_property_read_u32(of_node, "qcom,mdss-dsc-slice-width", &data);
if (rc) {
pr_err("failed to parse qcom,mdss-dsc-slice-width\n");
goto error;
}
- panel->dsc.slice_width = data;
+ priv_info->dsc.slice_width = data;
- intf_width = panel->mode.timing.h_active;
- if (intf_width % panel->dsc.slice_width) {
+ intf_width = mode->timing.h_active;
+ if (intf_width % priv_info->dsc.slice_width) {
pr_err("invalid slice width for the panel\n");
goto error;
}
- panel->dsc.pic_width = panel->mode.timing.h_active;
- panel->dsc.pic_height = panel->mode.timing.v_active;
+ priv_info->dsc.pic_width = mode->timing.h_active;
+ priv_info->dsc.pic_height = mode->timing.v_active;
rc = of_property_read_u32(of_node, "qcom,mdss-dsc-slice-per-pkt",
&data);
@@ -2080,7 +2158,7 @@
pr_err("failed to parse qcom,mdss-dsc-slice-per-pkt\n");
goto error;
}
- panel->dsc.slice_per_pkt = data;
+ priv_info->dsc.slice_per_pkt = data;
rc = of_property_read_u32(of_node, "qcom,mdss-dsc-bit-per-component",
&data);
@@ -2088,7 +2166,7 @@
pr_err("failed to parse qcom,mdss-dsc-bit-per-component\n");
goto error;
}
- panel->dsc.bpc = data;
+ priv_info->dsc.bpc = data;
rc = of_property_read_u32(of_node, "qcom,mdss-dsc-bit-per-pixel",
&data);
@@ -2096,16 +2174,16 @@
pr_err("failed to parse qcom,mdss-dsc-bit-per-pixel\n");
goto error;
}
- panel->dsc.bpp = data;
+ priv_info->dsc.bpp = data;
- panel->dsc.block_pred_enable = of_property_read_bool(of_node,
+ priv_info->dsc.block_pred_enable = of_property_read_bool(of_node,
"qcom,mdss-dsc-block-prediction-enable");
- panel->dsc.full_frame_slices = DIV_ROUND_UP(intf_width,
- panel->dsc.slice_width);
+ priv_info->dsc.full_frame_slices = DIV_ROUND_UP(intf_width,
+ priv_info->dsc.slice_width);
- dsi_dsc_populate_static_param(&panel->dsc);
- dsi_dsc_pclk_param_calc(&panel->dsc, intf_width);
+ dsi_dsc_populate_static_param(&priv_info->dsc);
+ dsi_dsc_pclk_param_calc(&priv_info->dsc, intf_width);
error:
return rc;
@@ -2157,9 +2235,9 @@
return 0;
}
-static int dsi_panel_parse_topology(struct dsi_panel *panel,
- struct device_node *of_node,
- int topology_override)
+static int dsi_panel_parse_topology(
+ struct dsi_display_mode_priv_info *priv_info,
+ struct device_node *of_node, int topology_override)
{
struct msm_display_topology *topology;
u32 top_count, top_sel, *array = NULL;
@@ -2230,9 +2308,7 @@
topology[top_sel].num_intf);
parse_done:
- panel->mode.mode_info = kzalloc(sizeof(struct msm_mode_info),
- GFP_KERNEL);
- memcpy(&panel->mode.mode_info->topology, &topology[top_sel],
+ memcpy(&priv_info->topology, &topology[top_sel],
sizeof(struct msm_display_topology));
parse_fail:
kfree(topology);
@@ -2323,14 +2399,40 @@
return rc;
}
+static int dsi_panel_parse_dms_info(struct dsi_panel *panel,
+ struct device_node *of_node)
+{
+ int dms_enabled;
+ const char *data;
+
+ if (!of_node || !panel) {
+ pr_err("invalid params\n");
+ return -EINVAL;
+ }
+
+ panel->dms_mode = DSI_DMS_MODE_DISABLED;
+ dms_enabled = of_property_read_bool(of_node,
+ "qcom,dynamic-mode-switch-enabled");
+ if (!dms_enabled)
+ return 0;
+
+ data = of_get_property(of_node, "qcom,dynamic-mode-switch-type", NULL);
+ if (data && !strcmp(data, "dynamic-resolution-switch-immediate")) {
+ panel->dms_mode = DSI_DMS_MODE_RES_SWITCH_IMMEDIATE;
+ } else {
+ pr_err("[%s] unsupported dynamic switch mode: %s\n",
+ panel->name, data);
+ return -EINVAL;
+ }
+
+ return 0;
+};
+
struct dsi_panel *dsi_panel_get(struct device *parent,
struct device_node *of_node,
int topology_override)
{
struct dsi_panel *panel;
- const char *data;
- const char *compression;
- u32 len = 0;
int rc = 0;
panel = kzalloc(sizeof(*panel), GFP_KERNEL);
@@ -2342,52 +2444,6 @@
if (!panel->name)
panel->name = DSI_PANEL_DEFAULT_LABEL;
- panel->dsc_enabled = false;
- compression = of_get_property(of_node, "qcom,compression-mode", NULL);
- if (compression && !strcmp(compression, "dsc"))
- panel->dsc_enabled = true;
-
- rc = dsi_panel_parse_timing(&panel->mode.timing, of_node);
- if (rc) {
- pr_err("failed to parse panel timing, rc=%d\n", rc);
- goto error;
- }
-
- rc = dsi_panel_parse_dsc_params(panel, of_node);
- if (rc) {
- pr_err("failed to parse dsc params, rc=%d\n", rc);
- goto error;
- }
-
- data = of_get_property(of_node,
- "qcom,mdss-dsi-panel-phy-timings", &len);
- if (!data) {
- pr_debug("%s:%d, Unable to read Phy timing settings",
- __func__, __LINE__);
- } else {
- int i = 0;
-
- panel->phy_timing_val = kzalloc((sizeof(u32) * len),
- GFP_KERNEL);
- if (!panel->phy_timing_val) {
- kfree(panel);
- return ERR_PTR(-ENOMEM);
- }
- for (i = 0; i < len; i++)
- panel->phy_timing_val[i] = data[i];
- }
- panel->phy_timing_len = len;
-
- panel->mode.pixel_clk_khz = (DSI_H_TOTAL(&panel->mode.timing) *
- DSI_V_TOTAL(&panel->mode.timing) *
- panel->mode.timing.refresh_rate) / 1000;
-
- rc = dsi_panel_parse_topology(panel, of_node, topology_override);
- if (rc) {
- pr_err("failed to parse panel topology, rc=%d\n", rc);
- goto error;
- }
-
rc = dsi_panel_parse_host_config(panel, of_node);
if (rc) {
pr_err("failed to parse host configuration, rc=%d\n", rc);
@@ -2410,12 +2466,6 @@
goto error;
}
- rc = dsi_panel_parse_cmd_sets(panel, of_node);
- if (rc) {
- pr_err("failed to parse command sets, rc=%d\n", rc);
- goto error;
- }
-
rc = dsi_panel_parse_power_cfg(parent, panel, of_node);
if (rc)
pr_err("failed to parse power config, rc=%d\n", rc);
@@ -2428,13 +2478,10 @@
if (rc)
pr_err("failed to parse backlight config, rc=%d\n", rc);
- rc = dsi_panel_parse_jitter_config(panel, of_node);
- if (rc)
- pr_err("failed to parse panel jitter config, rc=%d\n", rc);
rc = dsi_panel_parse_misc_features(panel, of_node);
if (rc)
- pr_err("failed to parse panel features, rc=%d\n", rc);
+ pr_err("failed to parse misc features, rc=%d\n", rc);
rc = dsi_panel_parse_hdr_config(panel, of_node);
if (rc)
@@ -2444,6 +2491,16 @@
if (rc)
pr_debug("failed to partial update caps, rc=%d\n", rc);
+ rc = dsi_panel_get_mode_count(panel, of_node);
+ if (rc) {
+ pr_err("failed to get mode count, rc=%d\n", rc);
+ goto error;
+ }
+
+ rc = dsi_panel_parse_dms_info(panel, of_node);
+ if (rc)
+ pr_debug("failed to get dms info, rc=%d\n", rc);
+
panel->panel_of_node = of_node;
drm_panel_init(&panel->drm_panel);
mutex_init(&panel->panel_lock);
@@ -2456,14 +2513,6 @@
void dsi_panel_put(struct dsi_panel *panel)
{
- u32 i;
-
- for (i = 0; i < DSI_CMD_SET_MAX; i++)
- dsi_panel_destroy_cmd_packets(&panel->cmd_sets[i]);
-
- kfree(panel->mode.mode_info);
-
- /* TODO: more free */
kfree(panel);
}
@@ -2576,20 +2625,42 @@
return 0;
}
-int dsi_panel_get_mode_count(struct dsi_panel *panel, u32 *count)
+int dsi_panel_get_mode_count(struct dsi_panel *panel,
+ struct device_node *of_node)
{
- int rc = 0;
+ const u32 SINGLE_MODE_SUPPORT = 1;
+ struct device_node *timings_np;
+ int count, rc = 0;
- if (!panel || !count) {
+ if (!of_node || !panel) {
pr_err("invalid params\n");
return -EINVAL;
}
- mutex_lock(&panel->panel_lock);
- /* TODO: DT format has not been decided for multiple modes. */
- *count = 1;
+ panel->num_timing_nodes = 0;
- mutex_unlock(&panel->panel_lock);
+ timings_np = of_get_child_by_name(of_node,
+ "qcom,mdss-dsi-display-timings");
+ if (!timings_np) {
+ pr_err("no display timing nodes defined\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ count = of_get_child_count(timings_np);
+ if (!count || count > DSI_MODE_MAX) {
+ pr_err("invalid count of timing nodes: %d\n", count);
+ rc = -EINVAL;
+ goto error;
+ }
+
+ /* No multiresolution support is available for video mode panels */
+ if (panel->panel_mode != DSI_OP_CMD_MODE)
+ count = SINGLE_MODE_SUPPORT;
+
+ panel->num_timing_nodes = count;
+
+error:
return rc;
}
@@ -2629,11 +2700,27 @@
return rc;
}
-int dsi_panel_get_mode(struct dsi_panel *panel,
- u32 index,
- struct dsi_display_mode *mode)
+void dsi_panel_put_mode(struct dsi_display_mode *mode)
{
- int rc = 0;
+ int i;
+
+ if (!mode->priv_info)
+ return;
+
+ for (i = 0; i < DSI_CMD_SET_MAX; i++)
+ dsi_panel_destroy_cmd_packets(&mode->priv_info->cmd_sets[i]);
+
+ kfree(mode->priv_info);
+}
+
+int dsi_panel_get_mode(struct dsi_panel *panel,
+ u32 index, struct dsi_display_mode *mode,
+ int topology_override)
+{
+ struct device_node *timings_np, *child_np;
+ struct dsi_display_mode_priv_info *prv_info;
+ u32 child_idx = 0;
+ int rc = 0, num_timings;
if (!panel || !mode) {
pr_err("invalid params\n");
@@ -2641,11 +2728,77 @@
}
mutex_lock(&panel->panel_lock);
- if (index != 0)
- rc = -ENOTSUPP; /* TODO: Support more than one mode */
- else
- memcpy(mode, &panel->mode, sizeof(*mode));
+ mode->priv_info = kzalloc(sizeof(*mode->priv_info), GFP_KERNEL);
+ if (!mode->priv_info) {
+ rc = -ENOMEM;
+ goto done;
+ }
+
+ prv_info = mode->priv_info;
+
+ timings_np = of_get_child_by_name(panel->panel_of_node,
+ "qcom,mdss-dsi-display-timings");
+ if (!timings_np) {
+ pr_err("no display timing nodes defined\n");
+ rc = -EINVAL;
+ goto parse_fail;
+ }
+
+ num_timings = of_get_child_count(timings_np);
+ if (!num_timings || num_timings > DSI_MODE_MAX) {
+ pr_err("invalid count of timing nodes: %d\n", num_timings);
+ rc = -EINVAL;
+ goto parse_fail;
+ }
+
+ for_each_child_of_node(timings_np, child_np) {
+ if (index != child_idx++)
+ continue;
+
+ rc = dsi_panel_parse_timing(&mode->timing, child_np);
+ if (rc) {
+ pr_err("failed to parse panel timing, rc=%d\n", rc);
+ goto parse_fail;
+ }
+
+ rc = dsi_panel_parse_dsc_params(mode, child_np);
+ if (rc) {
+ pr_err("failed to parse dsc params, rc=%d\n", rc);
+ goto parse_fail;
+ }
+
+ rc = dsi_panel_parse_topology(prv_info, child_np,
+ topology_override);
+ if (rc) {
+ pr_err("failed to parse panel topology, rc=%d\n", rc);
+ goto parse_fail;
+ }
+
+ rc = dsi_panel_parse_cmd_sets(prv_info, child_np);
+ if (rc) {
+ pr_err("failed to parse command sets, rc=%d\n", rc);
+ goto parse_fail;
+ }
+
+ rc = dsi_panel_parse_jitter_config(mode, child_np);
+ if (rc)
+ pr_err(
+ "failed to parse panel jitter config, rc=%d\n", rc);
+
+ rc = dsi_panel_parse_phy_timing(mode, child_np);
+ if (rc) {
+ pr_err(
+ "failed to parse panel phy timings, rc=%d\n", rc);
+ goto parse_fail;
+ }
+ }
+ goto done;
+
+parse_fail:
+ kfree(mode->priv_info);
+ mode->priv_info = NULL;
+done:
mutex_unlock(&panel->panel_lock);
return rc;
}
@@ -2663,11 +2816,11 @@
mutex_lock(&panel->panel_lock);
- config->panel_mode = panel->mode.panel_mode;
+ config->panel_mode = panel->panel_mode;
memcpy(&config->common_config, &panel->host_config,
sizeof(config->common_config));
- if (mode->panel_mode == DSI_OP_VIDEO_MODE) {
+ if (panel->panel_mode == DSI_OP_VIDEO_MODE) {
memcpy(&config->u.video_engine, &panel->video_config,
sizeof(config->u.video_engine));
} else {
@@ -2677,8 +2830,8 @@
memcpy(&config->video_timing, &mode->timing,
sizeof(config->video_timing));
- config->video_timing.dsc_enabled = panel->dsc_enabled;
- config->video_timing.dsc = &panel->dsc;
+ config->video_timing.dsc_enabled = mode->priv_info->dsc_enabled;
+ config->video_timing.dsc = &mode->priv_info->dsc;
config->esc_clk_rate_hz = 19200000;
mutex_unlock(&panel->panel_lock);
@@ -2715,17 +2868,20 @@
{
int rc = 0;
struct dsi_panel_cmd_set *set = NULL;
+ struct dsi_display_mode_priv_info *priv_info = NULL;
- if (!panel) {
+ if (!panel || !panel->cur_mode) {
pr_err("invalid params\n");
return -EINVAL;
}
mutex_lock(&panel->panel_lock);
- set = &panel->cmd_sets[DSI_CMD_SET_PPS];
+ priv_info = panel->cur_mode->priv_info;
- dsi_dsc_create_pps_buf_cmd(&panel->dsc, panel->dsc_pps_cmd, 0);
+ set = &priv_info->cmd_sets[DSI_CMD_SET_PPS];
+
+ dsi_dsc_create_pps_buf_cmd(&priv_info->dsc, panel->dsc_pps_cmd, 0);
rc = dsi_panel_create_cmd_packets(panel->dsc_pps_cmd,
DSI_CMD_PPS_SIZE, 1, set->cmds);
if (rc) {
@@ -2745,6 +2901,60 @@
return rc;
}
+int dsi_panel_set_lp1(struct dsi_panel *panel)
+{
+ int rc = 0;
+
+ if (!panel) {
+ pr_err("invalid params\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&panel->panel_lock);
+ rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_LP1);
+ if (rc)
+ pr_err("[%s] failed to send DSI_CMD_SET_LP1 cmd, rc=%d\n",
+ panel->name, rc);
+ mutex_unlock(&panel->panel_lock);
+ return rc;
+}
+
+int dsi_panel_set_lp2(struct dsi_panel *panel)
+{
+ int rc = 0;
+
+ if (!panel) {
+ pr_err("invalid params\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&panel->panel_lock);
+ rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_LP2);
+ if (rc)
+ pr_err("[%s] failed to send DSI_CMD_SET_LP2 cmd, rc=%d\n",
+ panel->name, rc);
+ mutex_unlock(&panel->panel_lock);
+ return rc;
+}
+
+int dsi_panel_set_nolp(struct dsi_panel *panel)
+{
+ int rc = 0;
+
+ if (!panel) {
+ pr_err("invalid params\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&panel->panel_lock);
+ rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_NOLP);
+ if (rc)
+ pr_err("[%s] failed to send DSI_CMD_SET_NOLP cmd, rc=%d\n",
+ panel->name, rc);
+ mutex_unlock(&panel->panel_lock);
+ return rc;
+}
+
int dsi_panel_prepare(struct dsi_panel *panel)
{
int rc = 0;
@@ -2777,11 +2987,11 @@
return rc;
}
-static int dsi_panel_roi_prepare_dcs_cmds(struct dsi_panel *panel,
+static int dsi_panel_roi_prepare_dcs_cmds(struct dsi_panel_cmd_set *set,
struct dsi_rect *roi, int ctrl_idx, int unicast)
{
static const int ROI_CMD_LEN = 5;
- struct dsi_panel_cmd_set *set = &panel->cmd_sets[DSI_CMD_SET_ROI];
+
int rc = 0;
/* DTYPE_DCS_LWRITE */
@@ -2856,13 +3066,18 @@
struct dsi_rect *roi)
{
int rc = 0;
+ struct dsi_panel_cmd_set *set;
+ struct dsi_display_mode_priv_info *priv_info;
- if (!panel) {
+ if (!panel || !panel->cur_mode) {
pr_err("Invalid params\n");
return -EINVAL;
}
- rc = dsi_panel_roi_prepare_dcs_cmds(panel, roi, ctrl_idx, true);
+ priv_info = panel->cur_mode->priv_info;
+ set = &priv_info->cmd_sets[DSI_CMD_SET_ROI];
+
+ rc = dsi_panel_roi_prepare_dcs_cmds(set, roi, ctrl_idx, true);
if (rc) {
pr_err("[%s] failed to prepare DSI_CMD_SET_ROI cmds, rc=%d\n",
panel->name, rc);
@@ -2880,11 +3095,51 @@
mutex_unlock(&panel->panel_lock);
- dsi_panel_destroy_cmd_packets(&panel->cmd_sets[DSI_CMD_SET_ROI]);
+ dsi_panel_destroy_cmd_packets(set);
return rc;
}
+int dsi_panel_switch(struct dsi_panel *panel)
+{
+ int rc = 0;
+
+ if (!panel) {
+ pr_err("Invalid params\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&panel->panel_lock);
+
+ rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_TIMING_SWITCH);
+ if (rc)
+ pr_err("[%s] failed to send DSI_CMD_SET_TIMING_SWITCH cmds, rc=%d\n",
+ panel->name, rc);
+
+ mutex_unlock(&panel->panel_lock);
+ return rc;
+}
+
+int dsi_panel_post_switch(struct dsi_panel *panel)
+{
+ int rc = 0;
+
+ if (!panel) {
+ pr_err("Invalid params\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&panel->panel_lock);
+
+ rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_POST_TIMING_SWITCH);
+ if (rc)
+ pr_err("[%s] failed to send DSI_CMD_SET_POST_TIMING_SWITCH cmds, rc=%d\n",
+ panel->name, rc);
+
+ mutex_unlock(&panel->panel_lock);
+ return rc;
+}
+
int dsi_panel_enable(struct dsi_panel *panel)
{
int rc = 0;
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
index 5380049..0ee23f3 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
@@ -21,7 +21,6 @@
#include <linux/errno.h>
#include <linux/leds.h>
#include <drm/drm_panel.h>
-#include <drm/drm_mipi_dsi.h>
#include <drm/msm_drm.h>
#include "dsi_defs.h"
@@ -33,6 +32,8 @@
#define MAX_BL_LEVEL 4096
#define DSI_CMD_PPS_SIZE 135
+#define DSI_MODE_MAX 5
+
enum dsi_panel_rotation {
DSI_PANEL_ROTATE_NONE = 0,
DSI_PANEL_ROTATE_HV_FLIP,
@@ -40,32 +41,6 @@
DSI_PANEL_ROTATE_V_FLIP
};
-enum dsi_cmd_set_type {
- DSI_CMD_SET_PRE_ON = 0,
- DSI_CMD_SET_ON,
- DSI_CMD_SET_POST_ON,
- DSI_CMD_SET_PRE_OFF,
- DSI_CMD_SET_OFF,
- DSI_CMD_SET_POST_OFF,
- DSI_CMD_SET_PRE_RES_SWITCH,
- DSI_CMD_SET_RES_SWITCH,
- DSI_CMD_SET_POST_RES_SWITCH,
- DSI_CMD_SET_CMD_TO_VID_SWITCH,
- DSI_CMD_SET_POST_CMD_TO_VID_SWITCH,
- DSI_CMD_SET_VID_TO_CMD_SWITCH,
- DSI_CMD_SET_POST_VID_TO_CMD_SWITCH,
- DSI_CMD_SET_PANEL_STATUS,
- DSI_CMD_SET_PPS,
- DSI_CMD_SET_ROI,
- DSI_CMD_SET_MAX
-};
-
-enum dsi_cmd_set_state {
- DSI_CMD_SET_STATE_LP = 0,
- DSI_CMD_SET_STATE_HS,
- DSI_CMD_SET_STATE_MAX
-};
-
enum dsi_backlight_type {
DSI_BACKLIGHT_PWM = 0,
DSI_BACKLIGHT_WLED,
@@ -82,6 +57,11 @@
MODE_GPIO_LOW,
};
+enum dsi_dms_mode {
+ DSI_DMS_MODE_DISABLED = 0,
+ DSI_DMS_MODE_RES_SWITCH_IMMEDIATE,
+};
+
struct dsi_dfps_capabilities {
bool dfps_support;
enum dsi_dfps_type type;
@@ -101,20 +81,6 @@
enum dsi_panel_rotation rotation;
};
-struct dsi_cmd_desc {
- struct mipi_dsi_msg msg;
- bool last_command;
- u32 post_wait_ms;
-};
-
-struct dsi_panel_cmd_set {
- enum dsi_cmd_set_type type;
- enum dsi_cmd_set_state state;
- u32 count;
- int ctrl_idx;
- struct dsi_cmd_desc *cmds;
-};
-
struct dsi_backlight_config {
enum dsi_backlight_type type;
@@ -162,19 +128,17 @@
struct dsi_host_common_cfg host_config;
struct dsi_video_engine_cfg video_config;
struct dsi_cmd_engine_cfg cmd_config;
+ enum dsi_op_mode panel_mode;
struct dsi_dfps_capabilities dfps_caps;
struct msm_roi_caps roi_caps;
- struct dsi_panel_cmd_set cmd_sets[DSI_CMD_SET_MAX];
struct dsi_panel_phy_props phy_props;
- u32 *phy_timing_val;
- u32 phy_timing_len;
+ struct dsi_display_mode *cur_mode;
+ u32 num_timing_nodes;
struct dsi_regulator_info power_info;
- struct dsi_display_mode mode;
-
struct dsi_backlight_config bl_config;
struct dsi_panel_reset_config reset_config;
struct dsi_pinctrl_info pinctrl;
@@ -184,15 +148,11 @@
bool ulps_enabled;
bool allow_phy_power_off;
- u32 panel_jitter_numer;
- u32 panel_jitter_denom;
- u32 panel_prefill_lines;
bool panel_initialized;
bool te_using_watchdog_timer;
- bool dsc_enabled;
char dsc_pps_cmd[DSI_CMD_PPS_SIZE];
- struct msm_display_dsc_info dsc;
+ enum dsi_dms_mode dms_mode;
};
static inline bool dsi_panel_ulps_feature_enabled(struct dsi_panel *panel)
@@ -208,17 +168,26 @@
struct dsi_panel *dsi_panel_get(struct device *parent,
struct device_node *of_node,
int topology_override);
+
void dsi_panel_put(struct dsi_panel *panel);
int dsi_panel_drv_init(struct dsi_panel *panel, struct mipi_dsi_host *host);
+
int dsi_panel_drv_deinit(struct dsi_panel *panel);
-int dsi_panel_get_mode_count(struct dsi_panel *panel, u32 *count);
+int dsi_panel_get_mode_count(struct dsi_panel *panel,
+ struct device_node *of_node);
+
+void dsi_panel_put_mode(struct dsi_display_mode *mode);
+
int dsi_panel_get_mode(struct dsi_panel *panel,
u32 index,
- struct dsi_display_mode *mode);
+ struct dsi_display_mode *mode,
+ int topology_override);
+
int dsi_panel_validate_mode(struct dsi_panel *panel,
struct dsi_display_mode *mode);
+
int dsi_panel_get_host_cfg_for_mode(struct dsi_panel *panel,
struct dsi_display_mode *mode,
struct dsi_host_config *config);
@@ -230,6 +199,12 @@
int dsi_panel_pre_prepare(struct dsi_panel *panel);
+int dsi_panel_set_lp1(struct dsi_panel *panel);
+
+int dsi_panel_set_lp2(struct dsi_panel *panel);
+
+int dsi_panel_set_nolp(struct dsi_panel *panel);
+
int dsi_panel_prepare(struct dsi_panel *panel);
int dsi_panel_enable(struct dsi_panel *panel);
@@ -251,6 +226,10 @@
int dsi_panel_send_roi_dcs(struct dsi_panel *panel, int ctrl_idx,
struct dsi_rect *roi);
+int dsi_panel_switch(struct dsi_panel *panel);
+
+int dsi_panel_post_switch(struct dsi_panel *panel);
+
void dsi_dsc_pclk_param_calc(struct msm_display_dsc_info *dsc, int intf_width);
#endif /* _DSI_PANEL_H_ */
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
index d97e4ef..f05d760 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
@@ -617,7 +617,7 @@
goto fail;
}
- aspace = msm_gem_smmu_address_space_create(&pdev->dev,
+ aspace = msm_gem_smmu_address_space_create(dev,
mmu, "mdp5");
if (IS_ERR(aspace)) {
ret = PTR_ERR(aspace);
diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c
index efeea31..017dbfb 100644
--- a/drivers/gpu/drm/msm/msm_atomic.c
+++ b/drivers/gpu/drm/msm/msm_atomic.c
@@ -26,6 +26,7 @@
struct drm_device *dev;
struct drm_atomic_state *state;
uint32_t crtc_mask;
+ bool nonblock;
struct kthread_work commit_work;
};
@@ -62,7 +63,8 @@
static void commit_destroy(struct msm_commit *c)
{
end_atomic(c->dev->dev_private, c->crtc_mask);
- kfree(c);
+ if (c->nonblock)
+ kfree(c);
}
static void msm_atomic_wait_for_commit_done(
@@ -131,6 +133,10 @@
&connector->encoder->crtc->state->mode))
continue;
+ if (msm_is_mode_seamless_dms(
+ &connector->encoder->crtc->state->adjusted_mode))
+ continue;
+
funcs = encoder->helper_private;
DRM_DEBUG_ATOMIC("disabling [ENCODER:%d:%s]\n",
@@ -166,6 +172,9 @@
if (msm_is_mode_seamless(&crtc->state->mode))
continue;
+ if (msm_is_mode_seamless_dms(&crtc->state->adjusted_mode))
+ continue;
+
funcs = crtc->helper_private;
DRM_DEBUG_ATOMIC("disabling [CRTC:%d]\n",
@@ -442,7 +451,8 @@
SDE_ATRACE_END("complete_commit");
}
-static struct msm_commit *commit_init(struct drm_atomic_state *state)
+static struct msm_commit *commit_init(struct drm_atomic_state *state,
+ bool nonblock)
{
struct msm_commit *c = kzalloc(sizeof(*c), GFP_KERNEL);
@@ -451,6 +461,7 @@
c->dev = state->dev;
c->state = state;
+ c->nonblock = nonblock;
kthread_init_work(&c->commit_work, _msm_drm_commit_work_cb);
@@ -495,6 +506,11 @@
break;
}
+ if (!ret && !commit->nonblock) {
+ kthread_flush_work(&commit->commit_work);
+ kfree(commit);
+ }
+
return ret;
}
@@ -528,7 +544,7 @@
return ret;
}
- c = commit_init(state);
+ c = commit_init(state, nonblock);
if (!c) {
ret = -ENOMEM;
goto error;
@@ -596,20 +612,13 @@
* current layout.
*/
- if (nonblock) {
- ret = msm_atomic_commit_dispatch(dev, state, c);
- if (ret) {
- DRM_ERROR("%s: atomic commit failed\n", __func__);
- drm_atomic_state_free(state);
- commit_destroy(c);
- goto error;
- }
- SDE_ATRACE_END("atomic_commit");
- return 0;
+ ret = msm_atomic_commit_dispatch(dev, state, c);
+ if (ret) {
+ DRM_ERROR("%s: atomic commit failed\n", __func__);
+ drm_atomic_state_free(state);
+ commit_destroy(c);
+ goto error;
}
-
- complete_commit(c);
-
SDE_ATRACE_END("atomic_commit");
return 0;
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index d2ac684..5e47daf 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -121,13 +121,32 @@
msm_drm_helper_hotplug_event(dev);
}
+/**
+ * msm_atomic_helper_check - validate state object
+ * @dev: DRM device
+ * @state: the driver state object
+ *
+ * This is a wrapper for the drm_atomic_helper_check to check the modeset
+ * and state checking for planes. Additionally it checks if any secure
+ * transition(moving CRTC and planes between secure and non-secure states and
+ * vice versa) is allowed or not. When going to secure state, planes
+ * with fb_mode as dir translated only can be staged on the CRTC, and only one
+ * CRTC should be active.
+ * Also mixing of secure and non-secure is not allowed.
+ *
+ * RETURNS
+ * Zero for success or -errorno.
+ */
int msm_atomic_check(struct drm_device *dev,
struct drm_atomic_state *state)
{
- if (msm_is_suspend_blocked(dev)) {
- DRM_DEBUG("rejecting commit during suspend\n");
- return -EBUSY;
- }
+ struct msm_drm_private *priv;
+
+ priv = dev->dev_private;
+ if (priv && priv->kms && priv->kms->funcs &&
+ priv->kms->funcs->atomic_check)
+ return priv->kms->funcs->atomic_check(priv->kms, state);
+
return drm_atomic_helper_check(dev, state);
}
@@ -1644,12 +1663,8 @@
static int msm_pm_suspend(struct device *dev)
{
struct drm_device *ddev;
- struct drm_modeset_acquire_ctx ctx;
- struct drm_connector *conn;
- struct drm_atomic_state *state;
- struct drm_crtc_state *crtc_state;
struct msm_drm_private *priv;
- int ret = 0;
+ struct msm_kms *kms;
if (!dev)
return -EINVAL;
@@ -1659,68 +1674,10 @@
return -EINVAL;
priv = ddev->dev_private;
- SDE_EVT32(0);
+ kms = priv->kms;
- /* acquire modeset lock(s) */
- drm_modeset_acquire_init(&ctx, 0);
-
-retry:
- ret = drm_modeset_lock_all_ctx(ddev, &ctx);
- if (ret)
- goto unlock;
-
- /* save current state for resume */
- if (priv->suspend_state)
- drm_atomic_state_free(priv->suspend_state);
- priv->suspend_state = drm_atomic_helper_duplicate_state(ddev, &ctx);
- if (IS_ERR_OR_NULL(priv->suspend_state)) {
- DRM_ERROR("failed to back up suspend state\n");
- priv->suspend_state = NULL;
- goto unlock;
- }
-
- /* create atomic state to disable all CRTCs */
- state = drm_atomic_state_alloc(ddev);
- if (IS_ERR_OR_NULL(state)) {
- DRM_ERROR("failed to allocate crtc disable state\n");
- goto unlock;
- }
-
- state->acquire_ctx = &ctx;
- drm_for_each_connector(conn, ddev) {
-
- if (!conn->state || !conn->state->crtc ||
- conn->dpms != DRM_MODE_DPMS_ON)
- continue;
-
- /* force CRTC to be inactive */
- crtc_state = drm_atomic_get_crtc_state(state,
- conn->state->crtc);
- if (IS_ERR_OR_NULL(crtc_state)) {
- DRM_ERROR("failed to get crtc %d state\n",
- conn->state->crtc->base.id);
- drm_atomic_state_free(state);
- goto unlock;
- }
- crtc_state->active = false;
- }
-
- /* commit the "disable all" state */
- ret = drm_atomic_commit(state);
- if (ret < 0) {
- DRM_ERROR("failed to disable crtcs, %d\n", ret);
- drm_atomic_state_free(state);
- } else {
- priv->suspend_block = true;
- }
-
-unlock:
- if (ret == -EDEADLK) {
- drm_modeset_backoff(&ctx);
- goto retry;
- }
- drm_modeset_drop_locks(&ctx);
- drm_modeset_acquire_fini(&ctx);
+ if (kms && kms->funcs && kms->funcs->pm_suspend)
+ return kms->funcs->pm_suspend(dev);
/* disable hot-plug polling */
drm_kms_helper_poll_disable(ddev);
@@ -1732,7 +1689,7 @@
{
struct drm_device *ddev;
struct msm_drm_private *priv;
- int ret;
+ struct msm_kms *kms;
if (!dev)
return -EINVAL;
@@ -1742,26 +1699,10 @@
return -EINVAL;
priv = ddev->dev_private;
+ kms = priv->kms;
- SDE_EVT32(priv->suspend_state != NULL);
-
- drm_mode_config_reset(ddev);
-
- drm_modeset_lock_all(ddev);
-
- priv->suspend_block = false;
-
- if (priv->suspend_state) {
- priv->suspend_state->acquire_ctx =
- ddev->mode_config.acquire_ctx;
- ret = drm_atomic_commit(priv->suspend_state);
- if (ret < 0) {
- DRM_ERROR("failed to restore state, %d\n", ret);
- drm_atomic_state_free(priv->suspend_state);
- }
- priv->suspend_state = NULL;
- }
- drm_modeset_unlock_all(ddev);
+ if (kms && kms->funcs && kms->funcs->pm_resume)
+ return kms->funcs->pm_resume(dev);
/* enable hot-plug polling */
drm_kms_helper_poll_enable(ddev);
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 96ab883..fc4d243 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -216,10 +216,12 @@
* enum msm_event_wait - type of HW events to wait for
* @MSM_ENC_COMMIT_DONE - wait for the driver to flush the registers to HW
* @MSM_ENC_TX_COMPLETE - wait for the HW to transfer the frame to panel
+ * @MSM_ENC_VBLANK - wait for the HW VBLANK event (for driver-internal waiters)
*/
enum msm_event_wait {
MSM_ENC_COMMIT_DONE = 0,
MSM_ENC_TX_COMPLETE,
+ MSM_ENC_VBLANK,
};
/**
@@ -387,10 +389,22 @@
/**
* struct msm_mode_info - defines all msm custom mode info
- * @topology - supported topology for the mode
+ * @frame_rate: frame_rate of the mode
+ * @vtotal: vtotal calculated for the mode
+ * @prefill_lines: prefill lines based on porches.
+ * @jitter_numer: display panel jitter numerator configuration
+ * @jitter_denom: display panel jitter denominator configuration
+ * @topology: supported topology for the mode
+ * @comp_info: compression info supported
*/
struct msm_mode_info {
+ uint32_t frame_rate;
+ uint32_t vtotal;
+ uint32_t prefill_lines;
+ uint32_t jitter_numer;
+ uint32_t jitter_denom;
struct msm_display_topology topology;
+ struct msm_compression_info comp_info;
};
/**
@@ -410,12 +424,6 @@
* @is_primary: Set to true if display is primary display
* @is_te_using_watchdog_timer: Boolean to indicate watchdog TE is
* used instead of panel TE in cmd mode panels
- * @frame_rate: Display frame rate
- * @prefill_lines: prefill lines based on porches.
- * @vtotal: display vertical total
- * @jitter_numer: display panel jitter numerator configuration
- * @jitter_denom: display panel jitter denominator configuration
- * @comp_info: Compression supported by the display
* @roi_caps: Region of interest capability info
*/
struct msm_display_info {
@@ -435,13 +443,6 @@
bool is_primary;
bool is_te_using_watchdog_timer;
- uint32_t frame_rate;
- uint32_t prefill_lines;
- uint32_t vtotal;
- uint32_t jitter_numer;
- uint32_t jitter_denom;
-
- struct msm_compression_info comp_info;
struct msm_roi_caps roi_caps;
};
@@ -590,10 +591,6 @@
*/
struct task_struct *struct_mutex_task;
- /* saved atomic state during system suspend */
- struct drm_atomic_state *suspend_state;
- bool suspend_block;
-
/* list of clients waiting for events */
struct list_head client_event_list;
@@ -604,12 +601,14 @@
struct dentry *debug_root;
};
+/* get struct msm_kms * from drm_device * */
+#define ddev_to_msm_kms(D) ((D) && (D)->dev_private ? \
+ ((struct msm_drm_private *)((D)->dev_private))->kms : NULL)
+
struct msm_format {
uint32_t pixel_format;
};
-int msm_atomic_check(struct drm_device *dev,
- struct drm_atomic_state *state);
/* callback from wq once fence has passed: */
struct msm_fence_cb {
struct work_struct work;
@@ -624,25 +623,6 @@
(_cb)->func = _func; \
} while (0)
-static inline bool msm_is_suspend_state(struct drm_device *dev)
-{
- if (!dev || !dev->dev_private)
- return false;
-
- return ((struct msm_drm_private *)dev->dev_private)->suspend_state != 0;
-}
-
-static inline bool msm_is_suspend_blocked(struct drm_device *dev)
-{
- if (!dev || !dev->dev_private)
- return false;
-
- if (!msm_is_suspend_state(dev))
- return false;
-
- return ((struct msm_drm_private *)dev->dev_private)->suspend_block != 0;
-}
-
int msm_atomic_commit(struct drm_device *dev,
struct drm_atomic_state *state, bool nonblock);
@@ -662,13 +642,57 @@
/* For SDE display */
struct msm_gem_address_space *
-msm_gem_smmu_address_space_create(struct device *dev, struct msm_mmu *mmu,
+msm_gem_smmu_address_space_create(struct drm_device *dev, struct msm_mmu *mmu,
const char *name);
+/**
+ * msm_gem_add_obj_to_aspace_active_list: adds obj to active obj list in aspace
+ */
+void msm_gem_add_obj_to_aspace_active_list(
+ struct msm_gem_address_space *aspace,
+ struct drm_gem_object *obj);
+
+/**
+ * msm_gem_remove_obj_from_aspace_active_list: removes obj from active obj
+ * list in aspace
+ */
+void msm_gem_remove_obj_from_aspace_active_list(
+ struct msm_gem_address_space *aspace,
+ struct drm_gem_object *obj);
+
+/**
+ * msm_gem_smmu_address_space_get: returns the aspace pointer for the requested
+ * domain
+ */
struct msm_gem_address_space *
msm_gem_smmu_address_space_get(struct drm_device *dev,
unsigned int domain);
+/**
+ * msm_gem_aspace_domain_attach_detach: function to inform the attach/detach
+ * of the domain for this aspace
+ */
+void msm_gem_aspace_domain_attach_detach_update(
+ struct msm_gem_address_space *aspace,
+ bool is_detach);
+
+/**
+ * msm_gem_address_space_register_cb: function to register callback for attach
+ * and detach of the domain
+ */
+int msm_gem_address_space_register_cb(
+ struct msm_gem_address_space *aspace,
+ void (*cb)(void *, bool),
+ void *cb_data);
+
+/**
+ * msm_gem_address_space_register_cb: function to unregister callback
+ */
+int msm_gem_address_space_unregister_cb(
+ struct msm_gem_address_space *aspace,
+ void (*cb)(void *, bool),
+ void *cb_data);
+
int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
struct drm_file *file);
@@ -690,6 +714,7 @@
void msm_gem_put_pages(struct drm_gem_object *obj);
void msm_gem_put_iova(struct drm_gem_object *obj,
struct msm_gem_address_space *aspace);
+dma_addr_t msm_gem_get_dma_addr(struct drm_gem_object *obj);
int msm_gem_dumb_create(struct drm_file *file, struct drm_device *dev,
struct drm_mode_create_dumb *args);
int msm_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev,
@@ -732,6 +757,7 @@
struct msm_gem_address_space *aspace);
uint32_t msm_framebuffer_iova(struct drm_framebuffer *fb,
struct msm_gem_address_space *aspace, int plane);
+uint32_t msm_framebuffer_phys(struct drm_framebuffer *fb, int plane);
struct drm_gem_object *msm_framebuffer_bo(struct drm_framebuffer *fb, int plane);
const struct msm_format *msm_framebuffer_format(struct drm_framebuffer *fb);
struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev,
diff --git a/drivers/gpu/drm/msm/msm_fb.c b/drivers/gpu/drm/msm/msm_fb.c
index 0a9f12d..f5cdf64 100644
--- a/drivers/gpu/drm/msm/msm_fb.c
+++ b/drivers/gpu/drm/msm/msm_fb.c
@@ -190,6 +190,22 @@
return msm_gem_iova(msm_fb->planes[plane], aspace) + fb->offsets[plane];
}
+uint32_t msm_framebuffer_phys(struct drm_framebuffer *fb,
+ int plane)
+{
+ struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb);
+ dma_addr_t phys_addr;
+
+ if (!msm_fb->planes[plane])
+ return 0;
+
+ phys_addr = msm_gem_get_dma_addr(msm_fb->planes[plane]);
+ if (!phys_addr)
+ return 0;
+
+ return phys_addr + fb->offsets[plane];
+}
+
struct drm_gem_object *msm_framebuffer_bo(struct drm_framebuffer *fb, int plane)
{
struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb);
diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
index a7d06d1..b829460 100644
--- a/drivers/gpu/drm/msm/msm_gem.c
+++ b/drivers/gpu/drm/msm/msm_gem.c
@@ -290,6 +290,19 @@
return offset;
}
+dma_addr_t msm_gem_get_dma_addr(struct drm_gem_object *obj)
+{
+ struct msm_gem_object *msm_obj = to_msm_bo(obj);
+ struct drm_device *dev = obj->dev;
+
+ if (IS_ERR_OR_NULL(msm_obj->sgt)) {
+ dev_err(dev->dev, "invalid scatter/gather table\n");
+ return 0;
+ }
+
+ return sg_dma_address(msm_obj->sgt->sgl);
+}
+
static void obj_remove_domain(struct msm_gem_vma *domain)
{
if (domain) {
@@ -311,6 +324,10 @@
if (iommu_present(&platform_bus_type)) {
msm_gem_unmap_vma(domain->aspace, domain,
msm_obj->sgt, get_dmabuf_ptr(obj));
+
+ msm_gem_remove_obj_from_aspace_active_list(
+ domain->aspace,
+ obj);
}
obj_remove_domain(domain);
@@ -390,10 +407,12 @@
msm_obj->flags);
}
- if (!ret && domain)
+ if (!ret && domain) {
*iova = domain->iova;
- else
+ msm_gem_add_obj_to_aspace_active_list(aspace, obj);
+ } else {
obj_remove_domain(domain);
+ }
return ret;
}
@@ -441,6 +460,63 @@
// things that are no longer needed..
}
+void msm_gem_aspace_domain_attach_detach_update(
+ struct msm_gem_address_space *aspace,
+ bool is_detach)
+{
+ struct msm_gem_object *msm_obj;
+ struct drm_gem_object *obj;
+ struct aspace_client *aclient;
+ int ret;
+ uint32_t iova;
+
+ if (!aspace)
+ return;
+
+ mutex_lock(&aspace->dev->struct_mutex);
+ if (is_detach) {
+ /* Indicate to clients domain is getting detached */
+ list_for_each_entry(aclient, &aspace->clients, list) {
+ if (aclient->cb)
+ aclient->cb(aclient->cb_data,
+ is_detach);
+ }
+
+ /**
+ * Unmap active buffers,
+ * typically clients should do this when the callback is called,
+ * but this needs to be done for the framebuffers which are not
+ * attached to any planes. (background apps)
+ */
+ list_for_each_entry(msm_obj, &aspace->active_list, iova_list) {
+ obj = &msm_obj->base;
+ if (obj->import_attach) {
+ put_iova(obj);
+ put_pages(obj);
+ }
+ }
+ } else {
+ /* map active buffers */
+ list_for_each_entry(msm_obj, &aspace->active_list,
+ iova_list) {
+ obj = &msm_obj->base;
+ ret = msm_gem_get_iova_locked(obj, aspace, &iova);
+ if (ret) {
+ mutex_unlock(&obj->dev->struct_mutex);
+ return;
+ }
+ }
+
+ /* Indicate to clients domain is attached */
+ list_for_each_entry(aclient, &aspace->clients, list) {
+ if (aclient->cb)
+ aclient->cb(aclient->cb_data,
+ is_detach);
+ }
+ }
+ mutex_unlock(&aspace->dev->struct_mutex);
+}
+
int msm_gem_dumb_create(struct drm_file *file, struct drm_device *dev,
struct drm_mode_create_dumb *args)
{
@@ -869,6 +945,7 @@
INIT_LIST_HEAD(&msm_obj->submit_entry);
INIT_LIST_HEAD(&msm_obj->domains);
+ INIT_LIST_HEAD(&msm_obj->iova_list);
list_add_tail(&msm_obj->mm_list, &priv->inactive_list);
diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h
index 9d41a00..c50c453 100644
--- a/drivers/gpu/drm/msm/msm_gem.h
+++ b/drivers/gpu/drm/msm/msm_gem.h
@@ -25,6 +25,8 @@
#define MSM_BO_STOLEN 0x10000000 /* try to use stolen/splash memory */
#define MSM_BO_KEEPATTRS 0x20000000 /* keep h/w bus attributes */
+struct msm_gem_object;
+
struct msm_gem_aspace_ops {
int (*map)(struct msm_gem_address_space *, struct msm_gem_vma *,
struct sg_table *sgt, void *priv, unsigned int flags);
@@ -33,12 +35,35 @@
struct sg_table *sgt, void *priv);
void (*destroy)(struct msm_gem_address_space *);
+ void (*add_to_active)(struct msm_gem_address_space *,
+ struct msm_gem_object *);
+ void (*remove_from_active)(struct msm_gem_address_space *,
+ struct msm_gem_object *);
+ int (*register_cb)(struct msm_gem_address_space *,
+ void (*cb)(void *, bool),
+ void *);
+ int (*unregister_cb)(struct msm_gem_address_space *,
+ void (*cb)(void *, bool),
+ void *);
};
+struct aspace_client {
+ void (*cb)(void *, bool);
+ void *cb_data;
+ struct list_head list;
+};
+
+
struct msm_gem_address_space {
const char *name;
struct msm_mmu *mmu;
const struct msm_gem_aspace_ops *ops;
+ bool domain_attached;
+ struct drm_device *dev;
+ /* list of mapped objects */
+ struct list_head active_list;
+ /* list of clients */
+ struct list_head clients;
};
struct msm_gem_vma {
@@ -96,6 +121,7 @@
* an IOMMU. Also used for stolen/splashscreen buffer.
*/
struct drm_mm_node *vram_node;
+ struct list_head iova_list;
};
#define to_msm_bo(x) container_of(x, struct msm_gem_object, base)
diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c
index 8d727fe..c695dda 100644
--- a/drivers/gpu/drm/msm/msm_gem_submit.c
+++ b/drivers/gpu/drm/msm/msm_gem_submit.c
@@ -31,11 +31,14 @@
#define BO_PINNED 0x2000
static struct msm_gem_submit *submit_create(struct drm_device *dev,
- struct msm_gpu *gpu, int nr_bos, int nr_cmds)
+ struct msm_gpu *gpu, uint32_t nr_bos, uint32_t nr_cmds)
{
struct msm_gem_submit *submit;
- int sz = sizeof(*submit) + (nr_bos * sizeof(submit->bos[0])) +
- (nr_cmds * sizeof(*submit->cmd));
+ uint64_t sz = sizeof(*submit) + (nr_bos * sizeof(submit->bos[0])) +
+ (nr_cmds * sizeof(submit->cmd[0]));
+
+ if (sz > SIZE_MAX)
+ return NULL;
submit = kmalloc(sz, GFP_TEMPORARY | __GFP_NOWARN | __GFP_NORETRY);
if (!submit)
diff --git a/drivers/gpu/drm/msm/msm_gem_vma.c b/drivers/gpu/drm/msm/msm_gem_vma.c
index 8e56871..d02228a 100644
--- a/drivers/gpu/drm/msm/msm_gem_vma.c
+++ b/drivers/gpu/drm/msm/msm_gem_vma.c
@@ -44,6 +44,9 @@
struct dma_buf *buf = priv;
int ret;
+ if (!aspace || !aspace->domain_attached)
+ return -EINVAL;
+
if (buf)
ret = aspace->mmu->funcs->map_dma_buf(aspace->mmu, sgt, buf,
DMA_BIDIRECTIONAL, flags);
@@ -62,15 +65,109 @@
aspace->mmu->funcs->destroy(aspace->mmu);
}
+static void smmu_aspace_add_to_active(
+ struct msm_gem_address_space *aspace,
+ struct msm_gem_object *msm_obj)
+{
+ WARN_ON(!mutex_is_locked(&aspace->dev->struct_mutex));
+ list_move_tail(&msm_obj->iova_list, &aspace->active_list);
+}
+
+static void smmu_aspace_remove_from_active(
+ struct msm_gem_address_space *aspace,
+ struct msm_gem_object *obj)
+{
+ struct msm_gem_object *msm_obj, *next;
+
+ WARN_ON(!mutex_is_locked(&aspace->dev->struct_mutex));
+
+ list_for_each_entry_safe(msm_obj, next, &aspace->active_list,
+ iova_list) {
+ if (msm_obj == obj) {
+ list_del(&msm_obj->iova_list);
+ break;
+ }
+ }
+}
+
+static int smmu_aspace_register_cb(
+ struct msm_gem_address_space *aspace,
+ void (*cb)(void *, bool),
+ void *cb_data)
+{
+ struct aspace_client *aclient = NULL;
+ struct aspace_client *temp;
+
+ if (!aspace)
+ return -EINVAL;
+
+ if (!aspace->domain_attached)
+ return -EACCES;
+
+ aclient = kzalloc(sizeof(*aclient), GFP_KERNEL);
+ if (!aclient)
+ return -ENOMEM;
+
+ aclient->cb = cb;
+ aclient->cb_data = cb_data;
+ INIT_LIST_HEAD(&aclient->list);
+
+ /* check if callback is already registered */
+ mutex_lock(&aspace->dev->struct_mutex);
+ list_for_each_entry(temp, &aspace->clients, list) {
+ if ((temp->cb == aclient->cb) &&
+ (temp->cb_data == aclient->cb_data)) {
+ kfree(aclient);
+ mutex_unlock(&aspace->dev->struct_mutex);
+ return -EEXIST;
+ }
+ }
+
+ list_move_tail(&aclient->list, &aspace->clients);
+ mutex_unlock(&aspace->dev->struct_mutex);
+
+ return 0;
+}
+
+static int smmu_aspace_unregister_cb(
+ struct msm_gem_address_space *aspace,
+ void (*cb)(void *, bool),
+ void *cb_data)
+{
+ struct aspace_client *aclient = NULL;
+ int rc = -ENOENT;
+
+ if (!aspace || !cb)
+ return -EINVAL;
+
+ mutex_lock(&aspace->dev->struct_mutex);
+ list_for_each_entry(aclient, &aspace->clients, list) {
+ if ((aclient->cb == cb) &&
+ (aclient->cb_data == cb_data)) {
+ list_del(&aclient->list);
+ kfree(aclient);
+ rc = 0;
+ break;
+ }
+ }
+ mutex_unlock(&aspace->dev->struct_mutex);
+
+ return rc;
+}
+
static const struct msm_gem_aspace_ops smmu_aspace_ops = {
.map = smmu_aspace_map_vma,
.unmap = smmu_aspace_unmap_vma,
- .destroy = smmu_aspace_destroy
+ .destroy = smmu_aspace_destroy,
+ .add_to_active = smmu_aspace_add_to_active,
+ .remove_from_active = smmu_aspace_remove_from_active,
+ .register_cb = smmu_aspace_register_cb,
+ .unregister_cb = smmu_aspace_unregister_cb,
};
struct msm_gem_address_space *
-msm_gem_smmu_address_space_create(struct device *dev, struct msm_mmu *mmu,
+msm_gem_smmu_address_space_create(struct drm_device *dev, struct msm_mmu *mmu,
const char *name)
{
struct msm_gem_address_space *aspace;
@@ -82,9 +179,12 @@
if (!aspace)
return ERR_PTR(-ENOMEM);
+ aspace->dev = dev;
aspace->name = name;
aspace->mmu = mmu;
aspace->ops = &smmu_aspace_ops;
+ INIT_LIST_HEAD(&aspace->active_list);
+ INIT_LIST_HEAD(&aspace->clients);
return aspace;
}
@@ -218,3 +318,44 @@
kfree(aspace);
}
+
+void msm_gem_add_obj_to_aspace_active_list(
+ struct msm_gem_address_space *aspace,
+ struct drm_gem_object *obj)
+{
+ struct msm_gem_object *msm_obj = to_msm_bo(obj);
+
+ if (aspace && aspace->ops && aspace->ops->add_to_active)
+ aspace->ops->add_to_active(aspace, msm_obj);
+}
+
+void msm_gem_remove_obj_from_aspace_active_list(
+ struct msm_gem_address_space *aspace,
+ struct drm_gem_object *obj)
+{
+ struct msm_gem_object *msm_obj = to_msm_bo(obj);
+
+ if (aspace && aspace->ops && aspace->ops->remove_from_active)
+ aspace->ops->remove_from_active(aspace, msm_obj);
+}
+
+int msm_gem_address_space_register_cb(struct msm_gem_address_space *aspace,
+ void (*cb)(void *, bool),
+ void *cb_data)
+{
+ if (aspace && aspace->ops && aspace->ops->register_cb)
+ return aspace->ops->register_cb(aspace, cb, cb_data);
+
+ return -EINVAL;
+}
+
+int msm_gem_address_space_unregister_cb(struct msm_gem_address_space *aspace,
+ void (*cb)(void *, bool),
+ void *cb_data)
+{
+ if (aspace && aspace->ops && aspace->ops->unregister_cb)
+ return aspace->ops->unregister_cb(aspace, cb, cb_data);
+
+ return -EINVAL;
+}
+
diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h
index 7692bef..76523c7 100644
--- a/drivers/gpu/drm/msm/msm_kms.h
+++ b/drivers/gpu/drm/msm/msm_kms.h
@@ -34,6 +34,8 @@
#define MSM_MODE_FLAG_SEAMLESS_DYNAMIC_FPS (1<<0)
/* Transition to new mode requires a wait-for-vblank before the modeset */
#define MSM_MODE_FLAG_VBLANK_PRE_MODESET (1<<1)
+/* Request to switch the connector mode */
+#define MSM_MODE_FLAG_SEAMLESS_DMS (1<<2)
/* As there are different display controller blocks depending on the
* snapdragon version, the kms support is split out and the appropriate
@@ -75,6 +77,9 @@
const struct msm_format *msm_fmt,
const struct drm_mode_fb_cmd2 *cmd,
struct drm_gem_object **bos);
+ /* perform complete atomic check of given atomic state */
+ int (*atomic_check)(struct msm_kms *kms,
+ struct drm_atomic_state *state);
/* misc: */
long (*round_pixclk)(struct msm_kms *kms, unsigned long rate,
struct drm_encoder *encoder);
@@ -88,6 +93,9 @@
void (*lastclose)(struct msm_kms *kms);
int (*register_events)(struct msm_kms *kms,
struct drm_mode_object *obj, u32 event, bool en);
+ /* pm suspend/resume hooks */
+ int (*pm_suspend)(struct device *dev);
+ int (*pm_resume)(struct device *dev);
/* cleanup: */
void (*destroy)(struct msm_kms *kms);
/* get address space */
@@ -143,6 +151,12 @@
return (mode->flags & DRM_MODE_FLAG_SEAMLESS);
}
+static inline bool msm_is_mode_seamless_dms(const struct drm_display_mode *mode)
+{
+ return mode ? (mode->private_flags & MSM_MODE_FLAG_SEAMLESS_DMS)
+ : false;
+}
+
static inline bool msm_is_mode_dynamic_fps(const struct drm_display_mode *mode)
{
return ((mode->flags & DRM_MODE_FLAG_SEAMLESS) &&
diff --git a/drivers/gpu/drm/msm/msm_mmu.h b/drivers/gpu/drm/msm/msm_mmu.h
index 5af26e2..08e6f79 100644
--- a/drivers/gpu/drm/msm/msm_mmu.h
+++ b/drivers/gpu/drm/msm/msm_mmu.h
@@ -45,6 +45,7 @@
void (*unmap_dma_buf)(struct msm_mmu *mmu, struct sg_table *sgt,
struct dma_buf *dma_buf, int dir);
void (*destroy)(struct msm_mmu *mmu);
+ bool (*is_domain_secure)(struct msm_mmu *mmu);
};
struct msm_mmu {
diff --git a/drivers/gpu/drm/msm/msm_prop.c b/drivers/gpu/drm/msm/msm_prop.c
index f2996dd..d1991a4 100644
--- a/drivers/gpu/drm/msm/msm_prop.c
+++ b/drivers/gpu/drm/msm/msm_prop.c
@@ -21,8 +21,6 @@
uint32_t blob_count,
uint32_t state_size)
{
- int i;
-
/* prevent access if any of these are NULL */
if (!base || !dev || !property_array || !property_data) {
property_count = 0;
@@ -60,10 +58,6 @@
0,
sizeof(struct msm_property_data) *
property_count);
- INIT_LIST_HEAD(&info->dirty_list);
-
- for (i = 0; i < property_count; ++i)
- INIT_LIST_HEAD(&property_data[i].dirty_node);
}
}
@@ -72,9 +66,6 @@
if (!info)
return;
- /* reset dirty list */
- INIT_LIST_HEAD(&info->dirty_list);
-
/* free state cache */
while (info->state_cache_size > 0)
kfree(info->state_cache[--(info->state_cache_size)]);
@@ -82,24 +73,25 @@
mutex_destroy(&info->property_lock);
}
-int msm_property_pop_dirty(struct msm_property_info *info)
+int msm_property_pop_dirty(struct msm_property_info *info,
+ struct msm_property_state *property_state)
{
struct list_head *item;
int rc = 0;
- if (!info) {
- DRM_ERROR("invalid info\n");
+ if (!info || !property_state || !property_state->values) {
+ DRM_ERROR("invalid argument(s)\n");
return -EINVAL;
}
mutex_lock(&info->property_lock);
- if (list_empty(&info->dirty_list)) {
+ if (list_empty(&property_state->dirty_list)) {
rc = -EAGAIN;
} else {
- item = info->dirty_list.next;
+ item = property_state->dirty_list.next;
list_del_init(item);
- rc = container_of(item, struct msm_property_data, dirty_node)
- - info->property_data;
+ rc = container_of(item, struct msm_property_value, dirty_node)
+ - property_state->values;
DRM_DEBUG_KMS("property %d dirty\n", rc);
}
mutex_unlock(&info->property_lock);
@@ -112,26 +104,28 @@
* This function doesn't mutex protect the
* dirty linked list.
* @info: Pointer to property info container struct
+ * @property_state: Pointer to property state container struct
* @property_idx: Property index
*/
static void _msm_property_set_dirty_no_lock(
struct msm_property_info *info,
+ struct msm_property_state *property_state,
uint32_t property_idx)
{
- if (!info || property_idx >= info->property_count) {
- DRM_ERROR("invalid argument(s), info %pK, idx %u\n",
- info, property_idx);
+ if (!info || !property_state || !property_state->values ||
+ property_idx >= info->property_count) {
+ DRM_ERROR("invalid argument(s), idx %u\n", property_idx);
return;
}
/* avoid re-inserting if already dirty */
- if (!list_empty(&info->property_data[property_idx].dirty_node)) {
+ if (!list_empty(&property_state->values[property_idx].dirty_node)) {
DRM_DEBUG_KMS("property %u already dirty\n", property_idx);
return;
}
- list_add_tail(&info->property_data[property_idx].dirty_node,
- &info->dirty_list);
+ list_add_tail(&property_state->values[property_idx].dirty_node,
+ &property_state->dirty_list);
}
/**
@@ -371,35 +365,36 @@
return rc;
}
-int msm_property_set_dirty(struct msm_property_info *info, int property_idx)
+int msm_property_set_dirty(struct msm_property_info *info,
+ struct msm_property_state *property_state,
+ int property_idx)
{
- if (!info) {
- DRM_ERROR("invalid property info\n");
+ if (!info || !property_state || !property_state->values) {
+ DRM_ERROR("invalid argument(s)\n");
return -EINVAL;
}
mutex_lock(&info->property_lock);
- _msm_property_set_dirty_no_lock(info, property_idx);
+ _msm_property_set_dirty_no_lock(info, property_state, property_idx);
mutex_unlock(&info->property_lock);
return 0;
}
int msm_property_atomic_set(struct msm_property_info *info,
- uint64_t *property_values,
- struct drm_property_blob **property_blobs,
+ struct msm_property_state *property_state,
struct drm_property *property, uint64_t val)
{
struct drm_property_blob *blob;
int property_idx, rc = -EINVAL;
property_idx = msm_property_index(info, property);
- if (!info || (property_idx == -EINVAL) || !property_values) {
- DRM_DEBUG("Invalid argument(s)\n");
+ if (!info || !property_state ||
+ (property_idx == -EINVAL) || !property_state->values) {
+ DRM_DEBUG("invalid argument(s)\n");
} else {
/* extra handling for incoming properties */
mutex_lock(&info->property_lock);
if ((property->flags & DRM_MODE_PROP_BLOB) &&
- (property_idx < info->blob_count) &&
- property_blobs) {
+ (property_idx < info->blob_count)) {
/* DRM lookup also takes a reference */
blob = drm_property_lookup_blob(info->dev,
(uint32_t)val);
@@ -411,18 +406,21 @@
val = blob->base.id;
/* save blob - need to clear previous ref */
- if (property_blobs[property_idx])
+ if (property_state->values[property_idx].blob)
drm_property_unreference_blob(
- property_blobs[property_idx]);
- property_blobs[property_idx] = blob;
+ property_state->values[
+ property_idx].blob);
+ property_state->values[property_idx].blob =
+ blob;
}
}
/* update value and flag as dirty */
- if (property_values[property_idx] != val ||
+ if (property_state->values[property_idx].value != val ||
info->property_data[property_idx].force_dirty) {
- property_values[property_idx] = val;
- _msm_property_set_dirty_no_lock(info, property_idx);
+ property_state->values[property_idx].value = val;
+ _msm_property_set_dirty_no_lock(info, property_state,
+ property_idx);
DBG("%s - %lld", property->name, val);
}
@@ -434,18 +432,18 @@
}
int msm_property_atomic_get(struct msm_property_info *info,
- uint64_t *property_values,
- struct drm_property_blob **property_blobs,
+ struct msm_property_state *property_state,
struct drm_property *property, uint64_t *val)
{
int property_idx, rc = -EINVAL;
property_idx = msm_property_index(info, property);
- if (!info || (property_idx == -EINVAL) || !property_values || !val) {
+ if (!info || (property_idx == -EINVAL) ||
+ !property_state->values || !val) {
DRM_DEBUG("Invalid argument(s)\n");
} else {
mutex_lock(&info->property_lock);
- *val = property_values[property_idx];
+ *val = property_state->values[property_idx].value;
mutex_unlock(&info->property_lock);
rc = 0;
}
@@ -495,8 +493,8 @@
}
void msm_property_reset_state(struct msm_property_info *info, void *state,
- uint64_t *property_values,
- struct drm_property_blob **property_blobs)
+ struct msm_property_state *property_state,
+ struct msm_property_value *property_values)
{
uint32_t i;
@@ -508,24 +506,29 @@
if (state)
memset(state, 0, info->state_size);
+ if (property_state) {
+ property_state->property_count = info->property_count;
+ property_state->values = property_values;
+ INIT_LIST_HEAD(&property_state->dirty_list);
+ }
+
/*
* Assign default property values. This helper is mostly used
* to initialize newly created state objects.
*/
if (property_values)
- for (i = 0; i < info->property_count; ++i)
- property_values[i] =
+ for (i = 0; i < info->property_count; ++i) {
+ property_values[i].value =
info->property_data[i].default_value;
-
- if (property_blobs)
- for (i = 0; i < info->blob_count; ++i)
- property_blobs[i] = 0;
+ property_values[i].blob = NULL;
+ INIT_LIST_HEAD(&property_values[i].dirty_node);
+ }
}
void msm_property_duplicate_state(struct msm_property_info *info,
void *old_state, void *state,
- uint64_t *property_values,
- struct drm_property_blob **property_blobs)
+ struct msm_property_state *property_state,
+ struct msm_property_value *property_values)
{
uint32_t i;
@@ -536,17 +539,24 @@
memcpy(state, old_state, info->state_size);
- if (property_blobs) {
- /* add ref count for blobs */
- for (i = 0; i < info->blob_count; ++i)
- if (property_blobs[i])
- drm_property_reference_blob(property_blobs[i]);
- }
+ if (!property_state)
+ return;
+
+ INIT_LIST_HEAD(&property_state->dirty_list);
+ property_state->values = property_values;
+
+ if (property_state->values)
+ /* add ref count for blobs and initialize dirty nodes */
+ for (i = 0; i < info->property_count; ++i) {
+ if (property_state->values[i].blob)
+ drm_property_reference_blob(
+ property_state->values[i].blob);
+ INIT_LIST_HEAD(&property_state->values[i].dirty_node);
+ }
}
void msm_property_destroy_state(struct msm_property_info *info, void *state,
- uint64_t *property_values,
- struct drm_property_blob **property_blobs)
+ struct msm_property_state *property_state)
{
uint32_t i;
@@ -554,19 +564,21 @@
DRM_ERROR("invalid argument(s)\n");
return;
}
- if (property_blobs) {
+ if (property_state && property_state->values) {
/* remove ref count for blobs */
- for (i = 0; i < info->blob_count; ++i)
- if (property_blobs[i])
+ for (i = 0; i < info->property_count; ++i)
+ if (property_state->values[i].blob) {
drm_property_unreference_blob(
- property_blobs[i]);
+ property_state->values[i].blob);
+ property_state->values[i].blob = NULL;
+ }
}
_msm_property_free_state(info, state);
}
void *msm_property_get_blob(struct msm_property_info *info,
- struct drm_property_blob **property_blobs,
+ struct msm_property_state *property_state,
size_t *byte_len,
uint32_t property_idx)
{
@@ -574,10 +586,11 @@
size_t len = 0;
void *rc = 0;
- if (!info || !property_blobs || (property_idx >= info->blob_count)) {
+ if (!info || !property_state || !property_state->values ||
+ (property_idx >= info->blob_count)) {
DRM_ERROR("invalid argument(s)\n");
} else {
- blob = property_blobs[property_idx];
+ blob = property_state->values[property_idx].blob;
if (blob) {
len = blob->length;
rc = &blob->data;
@@ -636,14 +649,15 @@
}
int msm_property_set_property(struct msm_property_info *info,
- uint64_t *property_values,
+ struct msm_property_state *property_state,
uint32_t property_idx,
uint64_t val)
{
int rc = -EINVAL;
if (!info || (property_idx >= info->property_count) ||
- property_idx < info->blob_count || !property_values) {
+ property_idx < info->blob_count ||
+ !property_state || !property_state->values) {
DRM_ERROR("invalid argument(s)\n");
} else {
struct drm_property *drm_prop;
@@ -651,8 +665,7 @@
mutex_lock(&info->property_lock);
/* update cached value */
- if (property_values)
- property_values[property_idx] = val;
+ property_state->values[property_idx].value = val;
/* update the new default value for immutables */
drm_prop = info->property_array[property_idx];
diff --git a/drivers/gpu/drm/msm/msm_prop.h b/drivers/gpu/drm/msm/msm_prop.h
index e54c796..d257a8c 100644
--- a/drivers/gpu/drm/msm/msm_prop.h
+++ b/drivers/gpu/drm/msm/msm_prop.h
@@ -22,17 +22,28 @@
* struct msm_property_data - opaque structure for tracking per
* drm-object per property stuff
* @default_value: Default property value for this drm object
- * @dirty_node: Linked list node to track if property is dirty or not
* @force_dirty: Always dirty property on incoming sets, rather than checking
* for modified values
*/
struct msm_property_data {
uint64_t default_value;
- struct list_head dirty_node;
bool force_dirty;
};
/**
+ * struct msm_property_value - opaque structure for tracking per
+ * drm-object per property stuff
+ * @value: Current property value for this drm object
+ * @blob: Pointer to associated blob data, if available
+ * @dirty_node: Linked list node to track if property is dirty or not
+ */
+struct msm_property_value {
+ uint64_t value;
+ struct drm_property_blob *blob;
+ struct list_head dirty_node;
+};
+
+/**
* struct msm_property_info: Structure for property/state helper functions
* @base: Pointer to base drm object (plane/crtc/etc.)
* @dev: Pointer to drm device object
@@ -43,8 +54,6 @@
* @install_request: Total number of property 'install' requests
* @install_count: Total number of successful 'install' requests
* @recent_idx: Index of property most recently accessed by set/get
- * @dirty_list: List of all properties that have been 'atomic_set' but not
- * yet cleared with 'msm_property_pop_dirty'
* @is_active: Whether or not drm component properties are 'active'
* @state_cache: Cache of local states, to prevent alloc/free thrashing
* @state_size: Size of local state structures
@@ -64,7 +73,6 @@
int32_t recent_idx;
- struct list_head dirty_list;
bool is_active;
void *state_cache[MSM_PROP_STATE_CACHE_SIZE];
@@ -74,6 +82,35 @@
};
/**
+ * struct msm_property_state - Structure for local property state information
+ * @property_count: Total number of properties
+ * @values: Pointer to array of msm_property_value objects
+ * @dirty_list: List of all properties that have been 'atomic_set' but not
+ * yet cleared with 'msm_property_pop_dirty'
+ */
+struct msm_property_state {
+ uint32_t property_count;
+ struct msm_property_value *values;
+ struct list_head dirty_list;
+};
+
+/**
+ * msm_property_index_to_drm_property - get drm property struct from prop index
+ * @info: Pointer to property info container struct
+ * @property_idx: Property index
+ * Returns: drm_property pointer associated with property index
+ */
+static inline
+struct drm_property *msm_property_index_to_drm_property(
+ struct msm_property_info *info, uint32_t property_idx)
+{
+ if (!info || property_idx >= info->property_count)
+ return NULL;
+
+ return info->property_array[property_idx];
+}
+
+/**
* msm_property_get_default - query default value of a property
* @info: Pointer to property info container struct
* @property_idx: Property index
@@ -134,12 +171,14 @@
* msm_property_pop_dirty - determine next dirty property and clear
* its dirty flag
* @info: Pointer to property info container struct
+ * @property_state: Pointer to property state container struct
* Returns: Valid msm property index on success,
* -EAGAIN if no dirty properties are available
* Property indicies returned from this function are similar
* to those returned by the msm_property_index function.
*/
-int msm_property_pop_dirty(struct msm_property_info *info);
+int msm_property_pop_dirty(struct msm_property_info *info,
+ struct msm_property_state *property_state);
/**
* msm_property_init - initialize property info structure
@@ -268,38 +307,37 @@
/**
* msm_property_set_dirty - forcibly flag a property as dirty
* @info: Pointer to property info container struct
+ * @property_state: Pointer to property state container struct
* @property_idx: Property index
* Returns: Zero on success
*/
-int msm_property_set_dirty(struct msm_property_info *info, int property_idx);
+int msm_property_set_dirty(struct msm_property_info *info,
+ struct msm_property_state *property_state,
+ int property_idx);
/**
* msm_property_atomic_set - helper function for atomic property set callback
* @info: Pointer to property info container struct
- * @property_values: Pointer to property values cache array
- * @property_blobs: Pointer to property blobs cache array
+ * @property_state: Pointer to local state structure
* @property: Incoming property pointer
* @val: Incoming property value
* Returns: Zero on success
*/
int msm_property_atomic_set(struct msm_property_info *info,
- uint64_t *property_values,
- struct drm_property_blob **property_blobs,
+ struct msm_property_state *property_state,
struct drm_property *property,
uint64_t val);
/**
* msm_property_atomic_get - helper function for atomic property get callback
* @info: Pointer to property info container struct
- * @property_values: Pointer to property values cache array
- * @property_blobs: Pointer to property blobs cache array
+ * @property_state: Pointer to local state structure
* @property: Incoming property pointer
* @val: Pointer to variable for receiving property value
* Returns: Zero on success
*/
int msm_property_atomic_get(struct msm_property_info *info,
- uint64_t *property_values,
- struct drm_property_blob **property_blobs,
+ struct msm_property_state *property_state,
struct drm_property *property,
uint64_t *val);
@@ -313,50 +351,47 @@
* msm_property_reset_state - helper function for state reset callback
* @info: Pointer to property info container struct
* @state: Pointer to local state structure
+ * @property_state: Pointer to property state container struct
* @property_values: Pointer to property values cache array
- * @property_blobs: Pointer to property blobs cache array
*/
-void msm_property_reset_state(struct msm_property_info *info,
- void *state,
- uint64_t *property_values,
- struct drm_property_blob **property_blobs);
+void msm_property_reset_state(struct msm_property_info *info, void *state,
+ struct msm_property_state *property_state,
+ struct msm_property_value *property_values);
/**
* msm_property_duplicate_state - helper function for duplicate state cb
* @info: Pointer to property info container struct
* @old_state: Pointer to original state structure
* @state: Pointer to newly created state structure
+ * @property_state: Pointer to destination property state container struct
* @property_values: Pointer to property values cache array
- * @property_blobs: Pointer to property blobs cache array
*/
void msm_property_duplicate_state(struct msm_property_info *info,
void *old_state,
void *state,
- uint64_t *property_values,
- struct drm_property_blob **property_blobs);
+ struct msm_property_state *property_state,
+ struct msm_property_value *property_values);
/**
* msm_property_destroy_state - helper function for destroy state cb
* @info: Pointer to property info container struct
* @state: Pointer to local state structure
- * @property_values: Pointer to property values cache array
- * @property_blobs: Pointer to property blobs cache array
+ * @property_state: Pointer to property state container struct
*/
void msm_property_destroy_state(struct msm_property_info *info,
void *state,
- uint64_t *property_values,
- struct drm_property_blob **property_blobs);
+ struct msm_property_state *property_state);
/**
* msm_property_get_blob - obtain cached data pointer for drm blob property
* @info: Pointer to property info container struct
- * @property_blobs: Pointer to property blobs cache array
+ * @property_state: Pointer to property state container struct
* @byte_len: Optional pointer to variable for accepting blob size
* @property_idx: Property index
* Returns: Pointer to blob data
*/
void *msm_property_get_blob(struct msm_property_info *info,
- struct drm_property_blob **property_blobs,
+ struct msm_property_state *property_state,
size_t *byte_len,
uint32_t property_idx);
@@ -385,13 +420,13 @@
* DRM_MODE_PROP_IMMUTABLE flag set.
* Note: This function cannot be called on a blob.
* @info: Pointer to property info container struct
- * @property_values: Pointer to property values cache array
+ * @property_state: Pointer to property state container struct
* @property_idx: Property index
* @val: value of the property to set
* Returns: Zero on success
*/
int msm_property_set_property(struct msm_property_info *info,
- uint64_t *property_values,
+ struct msm_property_state *property_state,
uint32_t property_idx,
uint64_t val);
diff --git a/drivers/gpu/drm/msm/msm_smmu.c b/drivers/gpu/drm/msm/msm_smmu.c
index 7d7f74a..730fc06 100644
--- a/drivers/gpu/drm/msm/msm_smmu.c
+++ b/drivers/gpu/drm/msm/msm_smmu.c
@@ -37,6 +37,7 @@
struct device *dev;
struct dma_iommu_mapping *mmu_mapping;
bool domain_attached;
+ bool secure;
};
struct msm_smmu {
@@ -275,6 +276,14 @@
msm_dma_unmap_sg(client->dev, sgt->sgl, sgt->nents, dir, dma_buf);
}
+static bool msm_smmu_is_domain_secure(struct msm_mmu *mmu)
+{
+ struct msm_smmu *smmu = to_msm_smmu(mmu);
+ struct msm_smmu_client *client = msm_smmu_to_client(smmu);
+
+ return client->secure;
+}
+
static const struct msm_mmu_funcs funcs = {
.attach = msm_smmu_attach,
.detach = msm_smmu_detach,
@@ -285,6 +294,7 @@
.map_dma_buf = msm_smmu_map_dma_buf,
.unmap_dma_buf = msm_smmu_unmap_dma_buf,
.destroy = msm_smmu_destroy,
+ .is_domain_secure = msm_smmu_is_domain_secure,
};
static struct msm_smmu_domain msm_smmu_domains[MSM_SMMU_DOMAIN_MAX] = {
@@ -458,6 +468,7 @@
if (domain->secure) {
int secure_vmid = VMID_CP_PIXEL;
+ client->secure = true;
rc = iommu_domain_set_attr(client->mmu_mapping->domain,
DOMAIN_ATTR_SECURE_VMID, &secure_vmid);
if (rc) {
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c
index e87058e..f379eb1 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.c
+++ b/drivers/gpu/drm/msm/sde/sde_connector.c
@@ -233,8 +233,8 @@
}
if (!c_conn->ops.get_dst_format) {
- SDE_ERROR("get_dst_format is invalid\n");
- return -EINVAL;
+ SDE_DEBUG("get_dst_format is unavailable\n");
+ return 0;
}
dst_format = c_conn->ops.get_dst_format(c_conn->display);
@@ -331,7 +331,7 @@
/* try to get user config data first */
*cfg = msm_property_get_blob(&c_conn->property_info,
- c_state->property_blobs,
+ &c_state->property_state,
&dither_sz,
CONNECTOR_PROP_PP_DITHER);
/* if user config data doesn't exist, use default dither blob */
@@ -365,12 +365,60 @@
return c_conn->ops.get_info(info, c_conn->display);
}
+static int _sde_connector_update_power_locked(struct sde_connector *c_conn)
+{
+ struct drm_connector *connector;
+ void *display;
+ int (*set_power)(struct drm_connector *, int, void *);
+ int mode, rc = 0;
+
+ if (!c_conn)
+ return -EINVAL;
+ connector = &c_conn->base;
+
+ switch (c_conn->dpms_mode) {
+ case DRM_MODE_DPMS_ON:
+ mode = c_conn->lp_mode;
+ break;
+ case DRM_MODE_DPMS_STANDBY:
+ mode = SDE_MODE_DPMS_STANDBY;
+ break;
+ case DRM_MODE_DPMS_SUSPEND:
+ mode = SDE_MODE_DPMS_SUSPEND;
+ break;
+ case DRM_MODE_DPMS_OFF:
+ mode = SDE_MODE_DPMS_OFF;
+ break;
+ default:
+ mode = c_conn->lp_mode;
+ SDE_ERROR("conn %d dpms set to unrecognized mode %d\n",
+ connector->base.id, mode);
+ break;
+ }
+
+ SDE_EVT32(connector->base.id, c_conn->dpms_mode, c_conn->lp_mode, mode);
+ SDE_DEBUG("conn %d - dpms %d, lp %d, panel %d\n", connector->base.id,
+ c_conn->dpms_mode, c_conn->lp_mode, mode);
+
+ if (mode != c_conn->last_panel_power_mode && c_conn->ops.set_power) {
+ display = c_conn->display;
+ set_power = c_conn->ops.set_power;
+
+ mutex_unlock(&c_conn->lock);
+ rc = set_power(connector, mode, display);
+ mutex_lock(&c_conn->lock);
+ }
+ c_conn->last_panel_power_mode = mode;
+
+ return rc;
+}
+
int sde_connector_pre_kickoff(struct drm_connector *connector)
{
struct sde_connector *c_conn;
struct sde_connector_state *c_state;
struct msm_display_kickoff_params params;
- int rc;
+ int idx, rc;
if (!connector) {
SDE_ERROR("invalid argument\n");
@@ -385,6 +433,22 @@
return -EINVAL;
}
+ while ((idx = msm_property_pop_dirty(&c_conn->property_info,
+ &c_state->property_state)) >= 0) {
+ switch (idx) {
+ case CONNECTOR_PROP_LP:
+ mutex_lock(&c_conn->lock);
+ c_conn->lp_mode = sde_connector_get_property(
+ connector->state, CONNECTOR_PROP_LP);
+ _sde_connector_update_power_locked(c_conn);
+ mutex_unlock(&c_conn->lock);
+ break;
+ default:
+ /* nothing to do for most properties */
+ break;
+ }
+ }
+
if (!c_conn->ops.pre_kickoff)
return 0;
@@ -427,6 +491,9 @@
c_conn = to_sde_connector(connector);
+ if (c_conn->ops.put_modes)
+ c_conn->ops.put_modes(connector, c_conn->display);
+
if (c_conn->blob_caps)
drm_property_unreference_blob(c_conn->blob_caps);
if (c_conn->blob_hdr)
@@ -459,13 +526,12 @@
drm_framebuffer_unreference(c_state->out_fb);
c_state->out_fb = NULL;
- if (c_conn) {
- c_state->property_values[CONNECTOR_PROP_OUT_FB] =
+ if (c_conn)
+ c_state->property_values[CONNECTOR_PROP_OUT_FB].value =
msm_property_get_default(&c_conn->property_info,
CONNECTOR_PROP_OUT_FB);
- } else {
- c_state->property_values[CONNECTOR_PROP_OUT_FB] = ~0;
- }
+ else
+ c_state->property_values[CONNECTOR_PROP_OUT_FB].value = ~0;
}
static void sde_connector_atomic_destroy_state(struct drm_connector *connector,
@@ -496,8 +562,7 @@
} else {
/* destroy value helper */
msm_property_destroy_state(&c_conn->property_info, c_state,
- c_state->property_values,
- c_state->property_blobs);
+ &c_state->property_state);
}
}
@@ -526,7 +591,8 @@
/* reset value helper, zero out state structure and reset properties */
msm_property_reset_state(&c_conn->property_info, c_state,
- c_state->property_values, c_state->property_blobs);
+ &c_state->property_state,
+ c_state->property_values);
c_state->base.connector = connector;
connector->state = &c_state->base;
@@ -554,8 +620,8 @@
/* duplicate value helper */
msm_property_duplicate_state(&c_conn->property_info,
- c_oldstate, c_state, c_state->property_values,
- c_state->property_blobs);
+ c_oldstate, c_state,
+ &c_state->property_state, c_state->property_values);
/* additional handling for drm framebuffer objects */
if (c_state->out_fb) {
@@ -685,56 +751,6 @@
return 0;
}
-static int _sde_connector_update_power_locked(struct sde_connector *c_conn)
-{
- struct drm_connector *connector;
- void *display;
- int (*set_power)(struct drm_connector *, int, void *);
- int mode, rc = 0;
-
- if (!c_conn)
- return -EINVAL;
- connector = &c_conn->base;
-
- mode = c_conn->lp_mode;
- if (c_conn->dpms_mode != DRM_MODE_DPMS_ON)
- mode = SDE_MODE_DPMS_OFF;
- switch (c_conn->dpms_mode) {
- case DRM_MODE_DPMS_ON:
- mode = c_conn->lp_mode;
- break;
- case DRM_MODE_DPMS_STANDBY:
- mode = SDE_MODE_DPMS_STANDBY;
- break;
- case DRM_MODE_DPMS_SUSPEND:
- mode = SDE_MODE_DPMS_SUSPEND;
- break;
- case DRM_MODE_DPMS_OFF:
- mode = SDE_MODE_DPMS_OFF;
- break;
- default:
- mode = c_conn->lp_mode;
- SDE_ERROR("conn %d dpms set to unrecognized mode %d\n",
- connector->base.id, mode);
- break;
- }
-
- SDE_DEBUG("conn %d - dpms %d, lp %d, panel %d\n", connector->base.id,
- c_conn->dpms_mode, c_conn->lp_mode, mode);
-
- if (mode != c_conn->last_panel_power_mode && c_conn->ops.set_power) {
- display = c_conn->display;
- set_power = c_conn->ops.set_power;
-
- mutex_unlock(&c_conn->lock);
- rc = set_power(connector, mode, display);
- mutex_lock(&c_conn->lock);
- }
- c_conn->last_panel_power_mode = mode;
-
- return rc;
-}
-
static int sde_connector_atomic_set_property(struct drm_connector *connector,
struct drm_connector_state *state,
struct drm_property *property,
@@ -755,8 +771,7 @@
/* generic property handling */
rc = msm_property_atomic_set(&c_conn->property_info,
- c_state->property_values, c_state->property_blobs,
- property, val);
+ &c_state->property_state, property, val);
if (rc)
goto end;
@@ -794,12 +809,6 @@
SDE_ERROR("prep fb failed, %d\n", rc);
}
break;
- case CONNECTOR_PROP_LP:
- mutex_lock(&c_conn->lock);
- c_conn->lp_mode = val;
- _sde_connector_update_power_locked(c_conn);
- mutex_unlock(&c_conn->lock);
- break;
default:
break;
}
@@ -863,8 +872,7 @@
else
/* get cached property value */
rc = msm_property_atomic_get(&c_conn->property_info,
- c_state->property_values,
- c_state->property_blobs, property, val);
+ &c_state->property_state, property, val);
/* allow for custom override */
if (c_conn->ops.get_property)
@@ -972,6 +980,39 @@
return rc;
}
+int sde_connector_set_property_for_commit(struct drm_connector *connector,
+ struct drm_atomic_state *atomic_state,
+ uint32_t property_idx, uint64_t value)
+{
+ struct drm_connector_state *state;
+ struct drm_property *property;
+ struct sde_connector *c_conn;
+
+ if (!connector || !atomic_state) {
+ SDE_ERROR("invalid argument(s), conn %d, state %d\n",
+ connector != NULL, atomic_state != NULL);
+ return -EINVAL;
+ }
+
+ c_conn = to_sde_connector(connector);
+ property = msm_property_index_to_drm_property(
+ &c_conn->property_info, property_idx);
+ if (!property) {
+ SDE_ERROR("invalid property index %d\n", property_idx);
+ return -EINVAL;
+ }
+
+ state = drm_atomic_get_connector_state(atomic_state, connector);
+ if (IS_ERR_OR_NULL(state)) {
+ SDE_ERROR("failed to get conn %d state\n",
+ connector->base.id);
+ return -EINVAL;
+ }
+
+ return drm_atomic_connector_set_property(
+ connector, state, property, value);
+}
+
#ifdef CONFIG_DEBUG_FS
/**
* sde_connector_init_debugfs - initialize connector debugfs
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.h b/drivers/gpu/drm/msm/sde/sde_connector.h
index 8796c52..29a36aa 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.h
+++ b/drivers/gpu/drm/msm/sde/sde_connector.h
@@ -65,6 +65,14 @@
void *display);
/**
+ * put_modes - free up drm modes of the connector
+ * @connector: Pointer to drm connector structure
+ * @display: Pointer to private display handle
+ */
+ void (*put_modes)(struct drm_connector *connector,
+ void *display);
+
+ /**
* update_pps - update pps command for the display panel
* @pps_cmd: Pointer to pps command
* @display: Pointer to private display handle
@@ -122,14 +130,14 @@
int (*get_info)(struct msm_display_info *info, void *display);
/**
- * get_topology - retrieve current topology for the mode selected
+ * get_mode_info - retrieve mode information
* @drm_mode: Display mode set for the display
- * @topology: Out parameter. Topology for the mode.
+ * @mode_info: Out parameter. information of the display mode
* @max_mixer_width: max width supported by HW layer mixer
* Returns: Zero on success
*/
- int (*get_topology)(const struct drm_display_mode *drm_mode,
- struct msm_display_topology *topology,
+ int (*get_mode_info)(const struct drm_display_mode *drm_mode,
+ struct msm_mode_info *mode_info,
u32 max_mixer_width);
/**
@@ -315,6 +323,7 @@
* @base: Base drm connector structure
* @out_fb: Pointer to output frame buffer, if applicable
* @aspace: Address space for accessing frame buffer objects, if applicable
+ * @property_state: Local storage for msm_prop properties
* @property_values: Local cache of current connector property values
* @rois: Regions of interest structure for mapping CRTC to Connector output
* @property_blobs: blob properties
@@ -323,7 +332,8 @@
struct drm_connector_state base;
struct drm_framebuffer *out_fb;
struct msm_gem_address_space *aspace;
- uint64_t property_values[CONNECTOR_PROP_COUNT];
+ struct msm_property_state property_state;
+ struct msm_property_value property_values[CONNECTOR_PROP_COUNT];
struct msm_roi_list rois;
struct drm_property_blob *property_blobs[CONNECTOR_PROP_BLOBCOUNT];
@@ -346,15 +356,15 @@
*/
#define sde_connector_get_property(S, X) \
((S) && ((X) < CONNECTOR_PROP_COUNT) ? \
- (to_sde_connector_state((S))->property_values[(X)]) : 0)
+ (to_sde_connector_state((S))->property_values[(X)].value) : 0)
/**
- * sde_connector_get_property_values - retrieve property values cache
+ * sde_connector_get_property_state - retrieve property state cache
* @S: Pointer to drm connector state
- * Returns: Integer value of requested property
+ * Returns: Pointer to local property state structure
*/
-#define sde_connector_get_property_values(S) \
- ((S) ? (to_sde_connector_state((S))->property_values) : 0)
+#define sde_connector_get_property_state(S) \
+ ((S) ? (&to_sde_connector_state((S))->property_state) : NULL)
/**
* sde_connector_get_out_fb - query out_fb value from sde connector state
@@ -379,6 +389,34 @@
}
/**
+ * sde_connector_get_lp - helper accessor to retrieve LP state
+ * @connector: pointer to drm connector
+ * Returns: value of the CONNECTOR_PROP_LP property or 0
+ */
+static inline uint64_t sde_connector_get_lp(
+ struct drm_connector *connector)
+{
+ if (!connector || !connector->state)
+ return 0;
+ return sde_connector_get_property(connector->state,
+ CONNECTOR_PROP_LP);
+}
+
+/**
+ * sde_connector_set_property_for_commit - add property set to atomic state
+ * Add a connector state property update for the specified property index
+ * to the atomic state in preparation for a drm_atomic_commit.
+ * @connector: Pointer to drm connector
+ * @atomic_state: Pointer to DRM atomic state structure for commit
+ * @property_idx: Connector property index
+ * @value: Updated property value
+ * Returns: Zero on success
+ */
+int sde_connector_set_property_for_commit(struct drm_connector *connector,
+ struct drm_atomic_state *atomic_state,
+ uint32_t property_idx, uint64_t value);
+
+/**
* sde_connector_init - create drm connector object for a given display
* @dev: Pointer to drm device struct
* @encoder: Pointer to associated encoder
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index ff802e6..ee84841 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -34,9 +34,19 @@
#include "sde_color_processing.h"
#include "sde_encoder.h"
#include "sde_connector.h"
+#include "sde_vbif.h"
#include "sde_power_handle.h"
#include "sde_core_perf.h"
#include "sde_trace.h"
+#include <soc/qcom/scm.h>
+#include "soc/qcom/secure_buffer.h"
+
+/* defines for secure channel call */
+#define SEC_SID_CNT 2
+#define SEC_SID_MASK_0 0x80881
+#define SEC_SID_MASK_1 0x80C81
+#define MEM_PROTECT_SD_CTRL_SWITCH 0x18
+#define MDP_DEVICE_ID 0x1A
struct sde_crtc_irq_info {
struct sde_irq_callback irq;
@@ -65,7 +75,7 @@
};
/* default input fence timeout, in ms */
-#define SDE_CRTC_INPUT_FENCE_TIMEOUT 2000
+#define SDE_CRTC_INPUT_FENCE_TIMEOUT 10000
/*
* The default input fence timeout is 2 seconds while max allowed
@@ -180,7 +190,9 @@
*/
static void _sde_crtc_rp_free_unused(struct sde_crtc_respool *rp)
{
+ mutex_lock(rp->rp_lock);
_sde_crtc_rp_reclaim(rp, false);
+ mutex_unlock(rp->rp_lock);
}
/**
@@ -190,7 +202,10 @@
*/
static void _sde_crtc_rp_destroy(struct sde_crtc_respool *rp)
{
+ mutex_lock(rp->rp_lock);
+ list_del_init(&rp->rp_list);
_sde_crtc_rp_reclaim(rp, true);
+ mutex_unlock(rp->rp_lock);
}
/**
@@ -229,7 +244,7 @@
struct sde_crtc_res *res, *dup_res;
struct drm_crtc *crtc;
- if (!rp || !dup_rp) {
+ if (!rp || !dup_rp || !rp->rp_head) {
SDE_ERROR("invalid resource pool\n");
return;
}
@@ -242,13 +257,16 @@
SDE_DEBUG("crtc%d.%u duplicate\n", crtc->base.id, rp->sequence_id);
+ mutex_lock(rp->rp_lock);
dup_rp->sequence_id = rp->sequence_id + 1;
INIT_LIST_HEAD(&dup_rp->res_list);
dup_rp->ops = rp->ops;
list_for_each_entry(res, &rp->res_list, list) {
dup_res = kzalloc(sizeof(struct sde_crtc_res), GFP_KERNEL);
- if (!dup_res)
+ if (!dup_res) {
+ mutex_unlock(rp->rp_lock);
return;
+ }
INIT_LIST_HEAD(&dup_res->list);
atomic_set(&dup_res->refcount, 0);
dup_res->type = res->type;
@@ -264,28 +282,43 @@
if (dup_res->ops.get)
dup_res->ops.get(dup_res->val, 0, -1);
}
+
+ dup_rp->rp_lock = rp->rp_lock;
+ dup_rp->rp_head = rp->rp_head;
+ INIT_LIST_HEAD(&dup_rp->rp_list);
+ list_add_tail(&dup_rp->rp_list, rp->rp_head);
+ mutex_unlock(rp->rp_lock);
}
/**
* _sde_crtc_rp_reset - reset resource pool after allocation
* @rp: Pointer to original resource pool
+ * @rp_lock: Pointer to serialization resource pool lock
+ * @rp_head: Pointer to crtc resource pool head
* return: None
*/
-static void _sde_crtc_rp_reset(struct sde_crtc_respool *rp)
+static void _sde_crtc_rp_reset(struct sde_crtc_respool *rp,
+ struct mutex *rp_lock, struct list_head *rp_head)
{
- if (!rp) {
+ if (!rp || !rp_lock || !rp_head) {
SDE_ERROR("invalid resource pool\n");
return;
}
+ mutex_lock(rp_lock);
+ rp->rp_lock = rp_lock;
+ rp->rp_head = rp_head;
+ INIT_LIST_HEAD(&rp->rp_list);
rp->sequence_id = 0;
INIT_LIST_HEAD(&rp->res_list);
rp->ops.get = _sde_crtc_hw_blk_get;
rp->ops.put = _sde_crtc_hw_blk_put;
+ list_add_tail(&rp->rp_list, rp->rp_head);
+ mutex_unlock(rp_lock);
}
/**
- * _sde_crtc_rp_add - add given resource to resource pool
+ * _sde_crtc_rp_add_no_lock - add given resource to resource pool without lock
* @rp: Pointer to original resource pool
* @type: Resource type
* @tag: Search tag for given resource
@@ -293,8 +326,8 @@
* @ops: Resource callback operations
* return: 0 if success; error code otherwise
*/
-static int _sde_crtc_rp_add(struct sde_crtc_respool *rp, u32 type, u64 tag,
- void *val, struct sde_crtc_res_ops *ops)
+static int _sde_crtc_rp_add_no_lock(struct sde_crtc_respool *rp, u32 type,
+ u64 tag, void *val, struct sde_crtc_res_ops *ops)
{
struct sde_crtc_res *res;
struct drm_crtc *crtc;
@@ -335,6 +368,31 @@
}
/**
+ * _sde_crtc_rp_add - add given resource to resource pool
+ * @rp: Pointer to original resource pool
+ * @type: Resource type
+ * @tag: Search tag for given resource
+ * @val: Resource handle
+ * @ops: Resource callback operations
+ * return: 0 if success; error code otherwise
+ */
+static int _sde_crtc_rp_add(struct sde_crtc_respool *rp, u32 type, u64 tag,
+ void *val, struct sde_crtc_res_ops *ops)
+{
+ int rc;
+
+ if (!rp) {
+ SDE_ERROR("invalid resource pool\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(rp->rp_lock);
+ rc = _sde_crtc_rp_add_no_lock(rp, type, tag, val, ops);
+ mutex_unlock(rp->rp_lock);
+ return rc;
+}
+
+/**
* _sde_crtc_rp_get - lookup the resource from given resource pool and obtain
* if available; otherwise, obtain resource from global pool
* @rp: Pointer to original resource pool
@@ -344,6 +402,7 @@
*/
static void *_sde_crtc_rp_get(struct sde_crtc_respool *rp, u32 type, u64 tag)
{
+ struct sde_crtc_respool *old_rp;
struct sde_crtc_res *res;
void *val = NULL;
int rc;
@@ -360,6 +419,7 @@
return NULL;
}
+ mutex_lock(rp->rp_lock);
list_for_each_entry(res, &rp->res_list, list) {
if (res->type != type || res->tag != tag)
continue;
@@ -369,6 +429,7 @@
atomic_read(&res->refcount));
atomic_inc(&res->refcount);
res->flags &= ~SDE_CRTC_RES_FLAG_FREE;
+ mutex_unlock(rp->rp_lock);
return res->val;
}
list_for_each_entry(res, &rp->res_list, list) {
@@ -381,16 +442,63 @@
atomic_inc(&res->refcount);
res->tag = tag;
res->flags &= ~SDE_CRTC_RES_FLAG_FREE;
+ mutex_unlock(rp->rp_lock);
return res->val;
}
+ /* not in this rp, try to grab from global pool */
if (rp->ops.get)
val = rp->ops.get(NULL, type, -1);
+ if (!IS_ERR_OR_NULL(val))
+ goto add_res;
+ /*
+ * Search older resource pools for hw blk with matching type,
+ * necessary when resource is being used by this object,
+ * but in previous states not yet cleaned up.
+ *
+ * This enables searching of all resources currently owned
+ * by this crtc even though the resource might not be used
+ * in the current atomic state. This allows those resources
+ * to be re-acquired by the new atomic state immediately
+ * without waiting for the resources to be fully released.
+ */
+ else if (IS_ERR_OR_NULL(val) && (type < SDE_HW_BLK_MAX)) {
+ list_for_each_entry(old_rp, rp->rp_head, rp_list) {
+ if (old_rp == rp)
+ continue;
+
+ list_for_each_entry(res, &old_rp->res_list, list) {
+ if (res->type != type)
+ continue;
+ SDE_DEBUG(
+ "crtc%d.%u found res:0x%x//%pK/ in crtc%d.%d\n",
+ crtc->base.id,
+ rp->sequence_id,
+ res->type, res->val,
+ crtc->base.id,
+ old_rp->sequence_id);
+ SDE_EVT32_VERBOSE(crtc->base.id,
+ rp->sequence_id,
+ res->type, res->val,
+ crtc->base.id,
+ old_rp->sequence_id);
+ if (res->ops.get)
+ res->ops.get(res->val, 0, -1);
+ val = res->val;
+ break;
+ }
+
+ if (!IS_ERR_OR_NULL(val))
+ break;
+ }
+ }
if (IS_ERR_OR_NULL(val)) {
SDE_DEBUG("crtc%d.%u failed to get res:0x%x//\n",
crtc->base.id, rp->sequence_id, type);
+ mutex_unlock(rp->rp_lock);
return NULL;
}
- rc = _sde_crtc_rp_add(rp, type, tag, val, &rp->ops);
+add_res:
+ rc = _sde_crtc_rp_add_no_lock(rp, type, tag, val, &rp->ops);
if (rc) {
SDE_ERROR("crtc%d.%u failed to add res:0x%x/0x%llx\n",
crtc->base.id, rp->sequence_id, type, tag);
@@ -398,6 +506,7 @@
rp->ops.put(val);
val = NULL;
}
+ mutex_unlock(rp->rp_lock);
return val;
}
@@ -424,6 +533,7 @@
return;
}
+ mutex_lock(rp->rp_lock);
list_for_each_entry_safe(res, next, &rp->res_list, list) {
if (res->type != type || res->tag != tag)
continue;
@@ -440,10 +550,12 @@
else if (atomic_dec_return(&res->refcount) == 0)
res->flags |= SDE_CRTC_RES_FLAG_FREE;
+ mutex_unlock(rp->rp_lock);
return;
}
SDE_ERROR("crtc%d.%u not found res:0x%x/0x%llx\n",
crtc->base.id, rp->sequence_id, type, tag);
+ mutex_unlock(rp->rp_lock);
}
int sde_crtc_res_add(struct drm_crtc_state *state, u32 type, u64 tag,
@@ -1220,7 +1332,8 @@
state->src_w >> 16, state->src_h >> 16,
state->crtc_x, state->crtc_y,
state->crtc_w, state->crtc_h,
- cstate->sbuf_cfg.rot_op_mode);
+ flush_tmp ? cstate->sbuf_cfg.rot_op_mode :
+ SDE_CTL_ROT_OP_MODE_OFFLINE);
stage_idx = zpos_cnt[pstate->stage]++;
stage_cfg->stage[pstate->stage][stage_idx] =
@@ -1412,6 +1525,348 @@
_sde_crtc_program_lm_output_roi(crtc);
}
+static int _sde_crtc_find_plane_fb_modes(struct drm_crtc_state *state,
+ uint32_t *fb_ns,
+ uint32_t *fb_sec,
+ uint32_t *fb_ns_dir,
+ uint32_t *fb_sec_dir)
+{
+ struct drm_plane *plane;
+ const struct drm_plane_state *pstate;
+ struct sde_plane_state *sde_pstate;
+ uint32_t mode = 0;
+ int rc;
+
+ if (!state) {
+ SDE_ERROR("invalid state\n");
+ return -EINVAL;
+ }
+
+ *fb_ns = 0;
+ *fb_sec = 0;
+ *fb_ns_dir = 0;
+ *fb_sec_dir = 0;
+ drm_atomic_crtc_state_for_each_plane_state(plane, pstate, state) {
+ if (IS_ERR_OR_NULL(pstate)) {
+ rc = PTR_ERR(pstate);
+ SDE_ERROR("crtc%d failed to get plane%d state%d\n",
+ state->crtc->base.id,
+ plane->base.id, rc);
+ return rc;
+ }
+ sde_pstate = to_sde_plane_state(pstate);
+ mode = sde_plane_get_property(sde_pstate,
+ PLANE_PROP_FB_TRANSLATION_MODE);
+ switch (mode) {
+ case SDE_DRM_FB_NON_SEC:
+ (*fb_ns)++;
+ break;
+ case SDE_DRM_FB_SEC:
+ (*fb_sec)++;
+ break;
+ case SDE_DRM_FB_NON_SEC_DIR_TRANS:
+ (*fb_ns_dir)++;
+ break;
+ case SDE_DRM_FB_SEC_DIR_TRANS:
+ (*fb_sec_dir)++;
+ break;
+ default:
+ SDE_ERROR("Error: Plane[%d], fb_trans_mode:%d",
+ plane->base.id,
+ mode);
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+/**
+ * sde_crtc_get_secure_transition_ops - determines the operations that
+ * need to be performed before transitioning to secure state
+ * This function should be called after swapping the new state
+ * @crtc: Pointer to drm crtc structure
+ * Returns the bitmask of operations need to be performed, -Error in
+ * case of error cases
+ */
+int sde_crtc_get_secure_transition_ops(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_crtc_state,
+ bool old_valid_fb)
+{
+ struct drm_plane *plane;
+ struct drm_encoder *encoder;
+ struct sde_crtc *sde_crtc;
+ struct sde_crtc_state *cstate;
+ struct sde_crtc_smmu_state_data *smmu_state;
+ uint32_t translation_mode = 0;
+ int ops = 0;
+ bool post_commit = false;
+
+ if (!crtc || !crtc->state) {
+ SDE_ERROR("invalid crtc\n");
+ return -EINVAL;
+ }
+
+ sde_crtc = to_sde_crtc(crtc);
+ cstate = to_sde_crtc_state(crtc->state);
+ smmu_state = &sde_crtc->smmu_state;
+
+ SDE_DEBUG("crtc%d, secure_level%d\n",
+ crtc->base.id,
+ sde_crtc_get_secure_level(crtc, crtc->state));
+
+ /**
+ * SMMU operations need to be delayed in case of
+ * video mode panels when switching back to non_secure
+ * mode
+ */
+ drm_for_each_encoder(encoder, crtc->dev) {
+ if (encoder->crtc != crtc)
+ continue;
+
+ post_commit &= !sde_encoder_is_cmd_mode(encoder);
+ }
+
+ drm_atomic_crtc_for_each_plane(plane, crtc) {
+ if (!plane->state)
+ continue;
+
+ translation_mode = sde_plane_get_property(
+ to_sde_plane_state(plane->state),
+ PLANE_PROP_FB_TRANSLATION_MODE);
+ if (translation_mode > SDE_DRM_FB_SEC_DIR_TRANS) {
+ SDE_ERROR("crtc%d, invalid translation_mode%d\n",
+ crtc->base.id,
+ translation_mode);
+ return -EINVAL;
+ }
+
+ /**
+ * we can break if we find sec_fir or non_sec_dir
+ * plane
+ */
+ if ((translation_mode == SDE_DRM_FB_NON_SEC_DIR_TRANS) ||
+ (translation_mode == SDE_DRM_FB_SEC_DIR_TRANS))
+ break;
+ }
+
+ switch (translation_mode) {
+ case SDE_DRM_FB_NON_SEC_DIR_TRANS:
+ if (smmu_state->state == ATTACHED) {
+ smmu_state->state = DETACH_ALL_REQ;
+ smmu_state->transition_type = PRE_COMMIT;
+ ops |= SDE_KMS_OPS_CRTC_SECURE_STATE_CHANGE;
+ if (old_valid_fb) {
+ ops |= (SDE_KMS_OPS_WAIT_FOR_TX_DONE |
+ SDE_KMS_OPS_CLEANUP_PLANE_FB);
+ }
+ }
+ break;
+ case SDE_DRM_FB_SEC_DIR_TRANS:
+ if (smmu_state->state == ATTACHED) {
+ smmu_state->state = DETACH_SEC_REQ;
+ smmu_state->transition_type = PRE_COMMIT;
+ ops |= SDE_KMS_OPS_CRTC_SECURE_STATE_CHANGE;
+ }
+ break;
+ case SDE_DRM_FB_SEC:
+ case SDE_DRM_FB_NON_SEC:
+ if (smmu_state->state == DETACHED_SEC) {
+ smmu_state->state = ATTACH_SEC_REQ;
+ smmu_state->transition_type = post_commit ?
+ POST_COMMIT : PRE_COMMIT;
+ ops |= SDE_KMS_OPS_CRTC_SECURE_STATE_CHANGE;
+ if (translation_mode == SDE_DRM_FB_SEC)
+ ops |= SDE_KMS_OPS_PREPARE_PLANE_FB;
+ } else if (smmu_state->state == DETACHED) {
+ smmu_state->state = ATTACH_ALL_REQ;
+ smmu_state->transition_type = post_commit ?
+ POST_COMMIT : PRE_COMMIT;
+ ops |= SDE_KMS_OPS_CRTC_SECURE_STATE_CHANGE |
+ SDE_KMS_OPS_PREPARE_PLANE_FB;
+ if (old_valid_fb)
+ ops |= (SDE_KMS_OPS_WAIT_FOR_TX_DONE |
+ SDE_KMS_OPS_CLEANUP_PLANE_FB);
+ }
+ break;
+ default:
+ SDE_ERROR("invalid plane fb_mode:%d\n",
+ translation_mode);
+ ops = 0;
+ return -EINVAL;
+ }
+
+ SDE_DEBUG("SMMU State:%d, type:%d ops:%x\n", smmu_state->state,
+ smmu_state->transition_type,
+ ops);
+ return ops;
+}
+
+/**
+ * _sde_crtc_scm_call - makes secure channel call to switch the VMIDs
+ * @vimd: switch the stage 2 translation to this VMID.
+ */
+static int _sde_crtc_scm_call(int vmid)
+{
+ struct scm_desc desc = {0};
+ uint32_t num_sids;
+ uint32_t *sec_sid;
+ uint32_t mem_protect_sd_ctrl_id = MEM_PROTECT_SD_CTRL_SWITCH;
+ int ret = 0;
+
+ /* This info should be queried from catalog */
+ num_sids = SEC_SID_CNT;
+ sec_sid = kcalloc(num_sids, sizeof(uint32_t), GFP_KERNEL);
+ if (!sec_sid)
+ return -ENOMEM;
+
+ /**
+ * derive this info from device tree/catalog, this is combination of
+ * smr mask and SID for secure
+ */
+ sec_sid[0] = SEC_SID_MASK_0;
+ sec_sid[1] = SEC_SID_MASK_1;
+ dmac_flush_range(&sec_sid, &sec_sid + num_sids);
+
+ SDE_DEBUG("calling scm_call for vmid %d", vmid);
+
+ desc.arginfo = SCM_ARGS(4, SCM_VAL, SCM_RW, SCM_VAL, SCM_VAL);
+ desc.args[0] = MDP_DEVICE_ID;
+ desc.args[1] = SCM_BUFFER_PHYS(&sec_sid);
+ desc.args[2] = sizeof(uint32_t) * num_sids;
+ desc.args[3] = vmid;
+
+ ret = scm_call2(SCM_SIP_FNID(SCM_SVC_MP,
+ mem_protect_sd_ctrl_id), &desc);
+ if (ret) {
+ SDE_ERROR("Error:scm_call2, vmid (%lld): ret%d\n",
+ desc.args[3],
+ ret);
+ }
+
+ kfree(sec_sid);
+ return ret;
+}
+
+/**
+ * sde_crtc_secure_ctrl - Initiates the operations to swtich between secure
+ * and non-secure mode
+ * @crtc: Pointer to crtc
+ * @post_commit: if this operation is triggered after commit
+ */
+int sde_crtc_secure_ctrl(struct drm_crtc *crtc, bool post_commit)
+{
+ struct sde_crtc *sde_crtc;
+ struct sde_crtc_state *cstate;
+ struct sde_kms *sde_kms;
+ struct sde_crtc_smmu_state_data *smmu_state;
+ int ret = 0;
+ int old_smmu_state;
+
+ if (!crtc || !crtc->state) {
+ SDE_ERROR("invalid crtc\n");
+ return -EINVAL;
+ }
+
+ sde_kms = _sde_crtc_get_kms(crtc);
+ if (!sde_kms) {
+ SDE_ERROR("invalid kms\n");
+ return -EINVAL;
+ }
+
+ sde_crtc = to_sde_crtc(crtc);
+ cstate = to_sde_crtc_state(crtc->state);
+ smmu_state = &sde_crtc->smmu_state;
+ old_smmu_state = smmu_state->state;
+
+ if ((!smmu_state->transition_type) ||
+ ((smmu_state->transition_type == POST_COMMIT) && !post_commit))
+ /* Bail out */
+ return 0;
+
+
+ /* Secure UI use case enable */
+ switch (smmu_state->state) {
+ case DETACH_ALL_REQ:
+ /* detach_all_contexts */
+ ret = sde_kms_mmu_detach(sde_kms, false);
+ if (ret) {
+ SDE_ERROR("crtc: %d, failed to detach %d\n",
+ crtc->base.id, ret);
+ goto error;
+ }
+
+ ret = _sde_crtc_scm_call(VMID_CP_SEC_DISPLAY);
+ if (ret)
+ goto error;
+
+ smmu_state->state = DETACHED;
+ break;
+ /* Secure UI use case disable */
+ case ATTACH_ALL_REQ:
+ ret = _sde_crtc_scm_call(VMID_CP_PIXEL);
+ if (ret)
+ goto error;
+
+ /* attach_all_contexts */
+ ret = sde_kms_mmu_attach(sde_kms, false);
+ if (ret) {
+ SDE_ERROR("crtc: %d, failed to attach %d\n",
+ crtc->base.id,
+ ret);
+ goto error;
+ }
+
+ smmu_state->state = ATTACHED;
+
+ break;
+ /* Secure preview enable */
+ case DETACH_SEC_REQ:
+ /* detach secure_context */
+ ret = sde_kms_mmu_detach(sde_kms, true);
+ if (ret) {
+ SDE_ERROR("crtc: %d, failed to detach %d\n",
+ crtc->base.id,
+ ret);
+ goto error;
+ }
+
+ smmu_state->state = DETACHED_SEC;
+ ret = _sde_crtc_scm_call(VMID_CP_CAMERA_PREVIEW);
+ if (ret)
+ goto error;
+
+ break;
+
+ /* Secure preview disable */
+ case ATTACH_SEC_REQ:
+ ret = _sde_crtc_scm_call(VMID_CP_PIXEL);
+ if (ret)
+ goto error;
+
+ ret = sde_kms_mmu_attach(sde_kms, true);
+ if (ret) {
+ SDE_ERROR("crtc: %d, failed to attach %d\n",
+ crtc->base.id,
+ ret);
+ goto error;
+ }
+ smmu_state->state = ATTACHED;
+ break;
+ default:
+ break;
+ }
+
+ SDE_DEBUG("crtc: %d, old_state %d new_state %d\n", crtc->base.id,
+ old_smmu_state,
+ smmu_state->state);
+ smmu_state->transition_error = false;
+ smmu_state->transition_type = NONE;
+
+error:
+ smmu_state->transition_error = true;
+ return ret;
+}
+
void sde_crtc_prepare_commit(struct drm_crtc *crtc,
struct drm_crtc_state *old_state)
{
@@ -1472,7 +1927,7 @@
sde_crtc->event = NULL;
DRM_DEBUG_VBL("%s: send event: %pK\n",
sde_crtc->name, event);
- SDE_EVT32(DRMID(crtc));
+ SDE_EVT32_VERBOSE(DRMID(crtc));
drm_crtc_send_vblank_event(crtc, event);
}
}
@@ -1651,6 +2106,26 @@
kthread_queue_work(&priv->event_thread[crtc_id].worker, &fevent->work);
}
+void sde_crtc_complete_commit(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_state)
+{
+ struct sde_crtc *sde_crtc;
+ struct sde_crtc_smmu_state_data *smmu_state;
+
+ if (!crtc || !crtc->state) {
+ SDE_ERROR("invalid crtc\n");
+ return;
+ }
+
+ sde_crtc = to_sde_crtc(crtc);
+ SDE_EVT32_VERBOSE(DRMID(crtc));
+ smmu_state = &sde_crtc->smmu_state;
+
+ /* complete secure transitions if any */
+ if (smmu_state->transition_type == POST_COMMIT)
+ sde_crtc_secure_ctrl(crtc, true);
+}
+
/**
* _sde_crtc_set_input_fence_timeout - update ns version of in fence timeout
* @cstate: Pointer to sde crtc state
@@ -1899,7 +2374,7 @@
cstate->lm_bounds[i].h = adj_mode->vdisplay;
memcpy(&cstate->lm_roi[i], &cstate->lm_bounds[i],
sizeof(cstate->lm_roi[i]));
- SDE_EVT32(DRMID(crtc), i,
+ SDE_EVT32_VERBOSE(DRMID(crtc), i,
cstate->lm_bounds[i].x, cstate->lm_bounds[i].y,
cstate->lm_bounds[i].w, cstate->lm_bounds[i].h);
SDE_DEBUG("%s: lm%d bnd&roi (%d,%d,%d,%d)\n", sde_crtc->name, i,
@@ -1917,6 +2392,7 @@
struct drm_encoder *encoder;
struct drm_device *dev;
unsigned long flags;
+ struct sde_crtc_smmu_state_data *smmu_state;
if (!crtc) {
SDE_ERROR("invalid crtc\n");
@@ -1933,6 +2409,7 @@
sde_crtc = to_sde_crtc(crtc);
dev = crtc->dev;
+ smmu_state = &sde_crtc->smmu_state;
if (!sde_crtc->num_mixers) {
_sde_crtc_setup_mixers(crtc);
@@ -1965,7 +2442,17 @@
return;
_sde_crtc_blend_setup(crtc);
- sde_cp_crtc_apply_properties(crtc);
+
+ /*
+ * Since CP properties use AXI buffer to program the
+ * HW, check if context bank is in attached
+ * state,
+ * apply color processing properties only if
+ * smmu state is attached,
+ */
+ if ((smmu_state->state != DETACHED) ||
+ (smmu_state->state != DETACH_ALL_REQ))
+ sde_cp_crtc_apply_properties(crtc);
/*
* PP_DONE irq is only used by command mode for now.
@@ -2051,8 +2538,11 @@
* required writes/flushing before crtc's "flush
* everything" call below.
*/
- drm_atomic_crtc_for_each_plane(plane, crtc)
+ drm_atomic_crtc_for_each_plane(plane, crtc) {
+ if (sde_crtc->smmu_state.transition_error)
+ sde_plane_set_error(plane, true);
sde_plane_flush(plane);
+ }
/* Kickoff will be scheduled by outer layer */
}
@@ -2084,7 +2574,7 @@
/* destroy value helper */
msm_property_destroy_state(&sde_crtc->property_info, cstate,
- cstate->property_values, cstate->property_blobs);
+ &cstate->property_state);
}
static int _sde_crtc_wait_for_frame_done(struct drm_crtc *crtc)
@@ -2103,7 +2593,7 @@
return 0;
}
- SDE_EVT32(DRMID(crtc), SDE_EVTLOG_FUNC_ENTRY);
+ SDE_EVT32_VERBOSE(DRMID(crtc), SDE_EVTLOG_FUNC_ENTRY);
ret = wait_for_completion_timeout(&sde_crtc->frame_done_comp,
msecs_to_jiffies(SDE_FRAME_DONE_TIMEOUT));
if (!ret) {
@@ -2112,13 +2602,14 @@
SDE_EVT32(DRMID(crtc), SDE_EVTLOG_FATAL);
rc = -ETIMEDOUT;
}
- SDE_EVT32(DRMID(crtc), SDE_EVTLOG_FUNC_EXIT);
+ SDE_EVT32_VERBOSE(DRMID(crtc), SDE_EVTLOG_FUNC_EXIT);
return rc;
}
void sde_crtc_commit_kickoff(struct drm_crtc *crtc)
{
+ struct drm_plane *plane;
struct drm_encoder *encoder;
struct drm_device *dev;
struct sde_crtc *sde_crtc;
@@ -2189,6 +2680,12 @@
}
sde_crtc->play_count++;
+ if (cstate->sbuf_cfg.rot_op_mode != SDE_CTL_ROT_OP_MODE_OFFLINE)
+ drm_atomic_crtc_for_each_plane(plane, crtc)
+ sde_plane_kickoff(plane);
+
+ sde_vbif_clear_errors(sde_kms);
+
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
if (encoder->crtc != crtc)
continue;
@@ -2196,19 +2693,20 @@
sde_encoder_kickoff(encoder);
}
- reinit_completion(&sde_crtc->frame_done_comp);
-
end:
+ reinit_completion(&sde_crtc->frame_done_comp);
SDE_ATRACE_END("crtc_commit");
return;
}
/**
- * _sde_crtc_vblank_enable_nolock - update power resource and vblank request
+ * _sde_crtc_vblank_enable_no_lock - update power resource and vblank request
* @sde_crtc: Pointer to sde crtc structure
* @enable: Whether to enable/disable vblanks
+ *
+ * @Return: error code
*/
-static void _sde_crtc_vblank_enable_nolock(
+static int _sde_crtc_vblank_enable_no_lock(
struct sde_crtc *sde_crtc, bool enable)
{
struct drm_device *dev;
@@ -2217,7 +2715,7 @@
if (!sde_crtc) {
SDE_ERROR("invalid crtc\n");
- return;
+ return -EINVAL;
}
crtc = &sde_crtc->base;
@@ -2231,13 +2729,16 @@
ret = _sde_crtc_power_enable(sde_crtc, true);
mutex_lock(&sde_crtc->crtc_lock);
if (ret)
- return;
+ return ret;
list_for_each_entry(enc, &dev->mode_config.encoder_list, head) {
if (enc->crtc != crtc)
continue;
- SDE_EVT32(DRMID(crtc), DRMID(enc), enable);
+ SDE_EVT32(DRMID(&sde_crtc->base), DRMID(enc), enable,
+ sde_crtc->enabled,
+ sde_crtc->suspend,
+ sde_crtc->vblank_requested);
sde_encoder_register_vblank_callback(enc,
sde_crtc_vblank_cb, (void *)crtc);
@@ -2247,7 +2748,10 @@
if (enc->crtc != crtc)
continue;
- SDE_EVT32(DRMID(crtc), DRMID(enc), enable);
+ SDE_EVT32(DRMID(&sde_crtc->base), DRMID(enc), enable,
+ sde_crtc->enabled,
+ sde_crtc->suspend,
+ sde_crtc->vblank_requested);
sde_encoder_register_vblank_callback(enc, NULL, NULL);
}
@@ -2257,6 +2761,8 @@
_sde_crtc_power_enable(sde_crtc, false);
mutex_lock(&sde_crtc->crtc_lock);
}
+
+ return 0;
}
/**
@@ -2269,8 +2775,7 @@
struct sde_crtc *sde_crtc;
struct msm_drm_private *priv;
struct sde_kms *sde_kms;
- struct drm_event event;
- u32 power_on;
+ int ret = 0;
if (!crtc || !crtc->dev || !crtc->dev->dev_private) {
SDE_ERROR("invalid crtc\n");
@@ -2286,35 +2791,27 @@
sde_kms = to_sde_kms(priv->kms);
SDE_DEBUG("crtc%d suspend = %d\n", crtc->base.id, enable);
+ SDE_EVT32_VERBOSE(DRMID(crtc), enable);
mutex_lock(&sde_crtc->crtc_lock);
- event.type = DRM_EVENT_CRTC_POWER;
- event.length = sizeof(u32);
- /*
- * Update CP on suspend/resume transitions
- */
- if (enable && !sde_crtc->suspend) {
- sde_cp_crtc_suspend(crtc);
- power_on = 0;
- } else if (!enable && sde_crtc->suspend) {
- sde_cp_crtc_resume(crtc);
- power_on = 1;
- }
-
/*
* If the vblank is enabled, release a power reference on suspend
* and take it back during resume (if it is still enabled).
*/
+ SDE_EVT32(DRMID(&sde_crtc->base), enable, sde_crtc->enabled,
+ sde_crtc->suspend, sde_crtc->vblank_requested);
if (sde_crtc->suspend == enable)
SDE_DEBUG("crtc%d suspend already set to %d, ignoring update\n",
crtc->base.id, enable);
- else if (sde_crtc->vblank_enable)
- _sde_crtc_vblank_enable_nolock(sde_crtc, !enable);
+ else if (sde_crtc->enabled && sde_crtc->vblank_requested) {
+ ret = _sde_crtc_vblank_enable_no_lock(sde_crtc, !enable);
+ if (ret)
+ SDE_ERROR("%s vblank enable failed: %d\n",
+ sde_crtc->name, ret);
+ }
sde_crtc->suspend = enable;
- msm_mode_object_event_notify(&crtc->base, crtc->dev, &event,
- (u8 *)&power_on);
mutex_unlock(&sde_crtc->crtc_lock);
}
@@ -2344,7 +2841,7 @@
/* duplicate value helper */
msm_property_duplicate_state(&sde_crtc->property_info,
old_cstate, cstate,
- cstate->property_values, cstate->property_blobs);
+ &cstate->property_state, cstate->property_values);
/* duplicate base helper */
__drm_atomic_helper_crtc_duplicate_state(crtc, &cstate->base);
@@ -2371,7 +2868,7 @@
}
/* revert suspend actions, if necessary */
- if (msm_is_suspend_state(crtc->dev))
+ if (sde_kms_is_suspend_state(crtc->dev))
_sde_crtc_set_suspend(crtc, false);
/* remove previous state, if present */
@@ -2389,40 +2886,27 @@
/* reset value helper */
msm_property_reset_state(&sde_crtc->property_info, cstate,
- cstate->property_values, cstate->property_blobs);
+ &cstate->property_state,
+ cstate->property_values);
_sde_crtc_set_input_fence_timeout(cstate);
- _sde_crtc_rp_reset(&cstate->rp);
+ _sde_crtc_rp_reset(&cstate->rp, &sde_crtc->rp_lock,
+ &sde_crtc->rp_head);
cstate->base.crtc = crtc;
crtc->state = &cstate->base;
}
-static int _sde_crtc_vblank_no_lock(struct sde_crtc *sde_crtc, bool en)
-{
- if (!sde_crtc) {
- SDE_ERROR("invalid crtc\n");
- return -EINVAL;
- }
-
- if (!sde_crtc->base.enabled || sde_crtc->suspend)
- SDE_EVT32(DRMID(&sde_crtc->base), sde_crtc->base.enabled, en,
- sde_crtc->vblank_enable, sde_crtc->suspend);
- else if (sde_crtc->vblank_enable != en)
- _sde_crtc_vblank_enable_nolock(sde_crtc, en);
- sde_crtc->vblank_enable = en;
-
- return 0;
-}
-
static void sde_crtc_handle_power_event(u32 event_type, void *arg)
{
struct drm_crtc *crtc = arg;
struct sde_crtc *sde_crtc;
+ struct drm_plane *plane;
struct drm_encoder *encoder;
+ struct sde_crtc_mixer *m;
struct drm_event event;
- u32 power_on = 0;
+ u32 power_on = 0, i, misr_status;
if (!crtc) {
SDE_ERROR("invalid crtc\n");
@@ -2434,7 +2918,8 @@
SDE_EVT32(DRMID(crtc), event_type);
- if (event_type == SDE_POWER_EVENT_POST_ENABLE) {
+ switch (event_type) {
+ case SDE_POWER_EVENT_POST_ENABLE:
/* restore encoder; crtc will be programmed during commit */
drm_for_each_encoder(encoder, crtc->dev) {
if (encoder->crtc != crtc)
@@ -2449,9 +2934,31 @@
power_on = 1;
msm_mode_object_event_notify(&crtc->base, crtc->dev, &event,
(u8 *)&power_on);
- } else if (event_type == SDE_POWER_EVENT_POST_DISABLE) {
- struct drm_plane *plane;
+ for (i = 0; i < sde_crtc->num_mixers; ++i) {
+ m = &sde_crtc->mixers[i];
+ if (!m->hw_lm || !m->hw_lm->ops.setup_misr ||
+ !sde_crtc->misr_enable)
+ continue;
+
+ m->hw_lm->ops.setup_misr(m->hw_lm, true,
+ sde_crtc->misr_frame_count);
+ }
+ break;
+ case SDE_POWER_EVENT_PRE_DISABLE:
+ for (i = 0; i < sde_crtc->num_mixers; ++i) {
+ m = &sde_crtc->mixers[i];
+ if (!m->hw_lm || !m->hw_lm->ops.collect_misr ||
+ !sde_crtc->misr_enable)
+ continue;
+
+ misr_status = m->hw_lm->ops.collect_misr(m->hw_lm);
+ sde_crtc->misr_data[i] = misr_status ? misr_status :
+ sde_crtc->misr_data[i];
+ }
+ sde_cp_crtc_pre_ipc(crtc);
+ break;
+ case SDE_POWER_EVENT_POST_DISABLE:
/*
* set revalidate flag in planes, so it will be re-programmed
* in the next frame update
@@ -2466,8 +2973,10 @@
power_on = 0;
msm_mode_object_event_notify(&crtc->base, crtc->dev, &event,
(u8 *)&power_on);
- } else if (event_type == SDE_POWER_EVENT_PRE_DISABLE) {
- sde_cp_crtc_pre_ipc(crtc);
+ break;
+ default:
+ SDE_DEBUG("event:%d not handled\n", event_type);
+ break;
}
mutex_unlock(&sde_crtc->crtc_lock);
@@ -2481,6 +2990,8 @@
struct msm_drm_private *priv;
unsigned long flags;
struct sde_crtc_irq_info *node = NULL;
+ struct drm_event event;
+ u32 power_on;
int ret;
if (!crtc || !crtc->dev || !crtc->dev->dev_private || !crtc->state) {
@@ -2493,11 +3004,19 @@
SDE_DEBUG("crtc%d\n", crtc->base.id);
- if (msm_is_suspend_state(crtc->dev))
+ if (sde_kms_is_suspend_state(crtc->dev))
_sde_crtc_set_suspend(crtc, true);
mutex_lock(&sde_crtc->crtc_lock);
- SDE_EVT32(DRMID(crtc));
+ SDE_EVT32_VERBOSE(DRMID(crtc));
+
+ /* update color processing on suspend */
+ event.type = DRM_EVENT_CRTC_POWER;
+ event.length = sizeof(u32);
+ sde_cp_crtc_suspend(crtc);
+ power_on = 0;
+ msm_mode_object_event_notify(&crtc->base, crtc->dev, &event,
+ (u8 *)&power_on);
/* wait for frame_event_done completion */
if (_sde_crtc_wait_for_frame_done(crtc))
@@ -2505,13 +3024,16 @@
crtc->base.id,
atomic_read(&sde_crtc->frame_pending));
- if (sde_crtc->vblank_enable && !sde_crtc->suspend) {
- SDE_DEBUG("crtc%d vblank left enabled at disable time\n",
- crtc->base.id);
- SDE_EVT32(DRMID(crtc), sde_crtc->vblank_enable,
- SDE_EVTLOG_FUNC_CASE1);
- _sde_crtc_vblank_enable_nolock(sde_crtc, false);
+ SDE_EVT32(DRMID(crtc), sde_crtc->enabled, sde_crtc->suspend,
+ sde_crtc->vblank_requested);
+ if (sde_crtc->enabled && !sde_crtc->suspend &&
+ sde_crtc->vblank_requested) {
+ ret = _sde_crtc_vblank_enable_no_lock(sde_crtc, false);
+ if (ret)
+ SDE_ERROR("%s vblank enable failed: %d\n",
+ sde_crtc->name, ret);
}
+ sde_crtc->enabled = false;
if (atomic_read(&sde_crtc->frame_pending)) {
SDE_EVT32(DRMID(crtc), atomic_read(&sde_crtc->frame_pending),
@@ -2562,6 +3084,8 @@
struct msm_drm_private *priv;
unsigned long flags;
struct sde_crtc_irq_info *node = NULL;
+ struct drm_event event;
+ u32 power_on;
int ret;
if (!crtc || !crtc->dev || !crtc->dev->dev_private) {
@@ -2571,7 +3095,7 @@
priv = crtc->dev->dev_private;
SDE_DEBUG("crtc%d\n", crtc->base.id);
- SDE_EVT32(DRMID(crtc));
+ SDE_EVT32_VERBOSE(DRMID(crtc));
sde_crtc = to_sde_crtc(crtc);
drm_for_each_encoder(encoder, crtc->dev) {
@@ -2582,13 +3106,25 @@
}
mutex_lock(&sde_crtc->crtc_lock);
- if (sde_crtc->vblank_enable) {
- /* honor user vblank request on crtc while it was disabled */
- SDE_DEBUG("%s vblank found enabled at crtc enable time\n",
- sde_crtc->name);
- SDE_EVT32(DRMID(crtc), sde_crtc->vblank_enable);
- _sde_crtc_vblank_enable_nolock(sde_crtc, true);
+ SDE_EVT32(DRMID(crtc), sde_crtc->enabled, sde_crtc->suspend,
+ sde_crtc->vblank_requested);
+ if (!sde_crtc->enabled && !sde_crtc->suspend &&
+ sde_crtc->vblank_requested) {
+ ret = _sde_crtc_vblank_enable_no_lock(sde_crtc, true);
+ if (ret)
+ SDE_ERROR("%s vblank enable failed: %d\n",
+ sde_crtc->name, ret);
}
+ sde_crtc->enabled = true;
+
+ /* update color processing on resume */
+ event.type = DRM_EVENT_CRTC_POWER;
+ event.length = sizeof(u32);
+ sde_cp_crtc_resume(crtc);
+ power_on = 1;
+ msm_mode_object_event_notify(&crtc->base, crtc->dev, &event,
+ (u8 *)&power_on);
+
mutex_unlock(&sde_crtc->crtc_lock);
spin_lock_irqsave(&sde_crtc->spin_lock, flags);
@@ -2710,6 +3246,75 @@
return rc;
}
+static int _sde_crtc_check_secure_state(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+{
+ struct drm_encoder *encoder;
+ struct sde_crtc_state *cstate;
+ uint32_t secure;
+ uint32_t fb_ns = 0, fb_sec = 0, fb_ns_dir = 0, fb_sec_dir = 0;
+ int encoder_cnt = 0;
+ int rc;
+
+ if (!crtc || !state) {
+ SDE_ERROR("invalid arguments\n");
+ return -EINVAL;
+ }
+
+ cstate = to_sde_crtc_state(state);
+
+ secure = sde_crtc_get_property(cstate,
+ CRTC_PROP_SECURITY_LEVEL);
+
+ rc = _sde_crtc_find_plane_fb_modes(state,
+ &fb_ns,
+ &fb_sec,
+ &fb_ns_dir,
+ &fb_sec_dir);
+ if (rc)
+ return rc;
+
+ /**
+ * validate planes
+ * fb_ns_dir is for secure display use case,
+ * fb_sec_dir is for secure camera preview use case,
+ * fb_sec is for secure video playback,
+ * fb_ns is for normal non secure use cases.
+ */
+ if (((secure == SDE_DRM_SEC_ONLY) &&
+ (fb_ns || fb_sec || fb_sec_dir)) ||
+ (fb_sec && fb_sec_dir)) {
+ SDE_ERROR(
+ "crtc%d: invalid planes fb_modes Sec:%d, NS:%d, Sec_Dir:%d, NS_Dir%d\n",
+ crtc->base.id,
+ fb_sec, fb_ns, fb_sec_dir,
+ fb_ns_dir);
+ return -EINVAL;
+ }
+
+ /**
+ * secure_crtc is not allowed in a shared toppolgy
+ * across different encoders.
+ */
+ if (fb_ns_dir || fb_sec_dir) {
+ drm_for_each_encoder(encoder, crtc->dev)
+ if (encoder->crtc == crtc)
+ encoder_cnt++;
+
+ if (encoder_cnt >
+ MAX_ALLOWED_ENCODER_CNT_PER_SECURE_CRTC) {
+ SDE_ERROR(
+ "crtc%d, invalid virtual encoder crtc%d\n",
+ crtc->base.id,
+ encoder_cnt);
+ return -EINVAL;
+
+ }
+ }
+ SDE_DEBUG("crtc:%d Secure validation successful\n", crtc->base.id);
+ return 0;
+}
+
static int sde_crtc_atomic_check(struct drm_crtc *crtc,
struct drm_crtc_state *state)
{
@@ -2756,6 +3361,10 @@
_sde_crtc_setup_is_ppsplit(state);
_sde_crtc_setup_lm_bounds(crtc, state);
+ rc = _sde_crtc_check_secure_state(crtc, state);
+ if (rc)
+ return rc;
+
/* get plane state for all drm planes associated with crtc state */
drm_atomic_crtc_state_for_each_plane_state(plane, pstate, state) {
if (IS_ERR_OR_NULL(pstate)) {
@@ -2981,7 +3590,7 @@
int sde_crtc_vblank(struct drm_crtc *crtc, bool en)
{
struct sde_crtc *sde_crtc;
- int rc;
+ int ret;
if (!crtc) {
SDE_ERROR("invalid crtc\n");
@@ -2990,10 +3599,18 @@
sde_crtc = to_sde_crtc(crtc);
mutex_lock(&sde_crtc->crtc_lock);
- rc = _sde_crtc_vblank_no_lock(sde_crtc, en);
+ SDE_EVT32(DRMID(&sde_crtc->base), en, sde_crtc->enabled,
+ sde_crtc->suspend, sde_crtc->vblank_requested);
+ if (sde_crtc->enabled && !sde_crtc->suspend) {
+ ret = _sde_crtc_vblank_enable_no_lock(sde_crtc, en);
+ if (ret)
+ SDE_ERROR("%s vblank enable failed: %d\n",
+ sde_crtc->name, ret);
+ }
+ sde_crtc->vblank_requested = en;
mutex_unlock(&sde_crtc->crtc_lock);
- return rc;
+ return 0;
}
void sde_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file)
@@ -3196,8 +3813,7 @@
sde_crtc = to_sde_crtc(crtc);
cstate = to_sde_crtc_state(state);
ret = msm_property_atomic_set(&sde_crtc->property_info,
- cstate->property_values, cstate->property_blobs,
- property, val);
+ &cstate->property_state, property, val);
if (!ret) {
idx = msm_property_index(&sde_crtc->property_info,
property);
@@ -3317,8 +3933,8 @@
SDE_ERROR("fence create failed\n");
} else {
ret = msm_property_atomic_get(&sde_crtc->property_info,
- cstate->property_values,
- cstate->property_blobs, property, val);
+ &cstate->property_state,
+ property, val);
if (ret)
ret = sde_cp_crtc_get_property(crtc,
property, val);
@@ -3460,7 +4076,7 @@
sde_crtc->vblank_cb_time = ktime_set(0, 0);
}
- seq_printf(s, "vblank_enable:%d\n", sde_crtc->vblank_enable);
+ seq_printf(s, "vblank_enable:%d\n", sde_crtc->vblank_requested);
mutex_unlock(&sde_crtc->crtc_lock);
@@ -3503,9 +4119,11 @@
mutex_lock(&sde_crtc->crtc_lock);
sde_crtc->misr_enable = enable;
+ sde_crtc->misr_frame_count = frame_count;
for (i = 0; i < sde_crtc->num_mixers; ++i) {
+ sde_crtc->misr_data[i] = 0;
m = &sde_crtc->mixers[i];
- if (!m->hw_lm)
+ if (!m->hw_lm || !m->hw_lm->ops.setup_misr)
continue;
m->hw_lm->ops.setup_misr(m->hw_lm, enable, frame_count);
@@ -3522,6 +4140,7 @@
struct sde_crtc *sde_crtc;
struct sde_crtc_mixer *m;
int i = 0, rc;
+ u32 misr_status;
ssize_t len = 0;
char buf[MISR_BUFF_SIZE + 1] = {'\0'};
@@ -3545,13 +4164,16 @@
for (i = 0; i < sde_crtc->num_mixers; ++i) {
m = &sde_crtc->mixers[i];
- if (!m->hw_lm)
+ if (!m->hw_lm || !m->hw_lm->ops.collect_misr)
continue;
+ misr_status = m->hw_lm->ops.collect_misr(m->hw_lm);
+ sde_crtc->misr_data[i] = misr_status ? misr_status :
+ sde_crtc->misr_data[i];
len += snprintf(buf + len, MISR_BUFF_SIZE - len, "lm idx:%d\n",
m->hw_lm->idx - LM_0);
len += snprintf(buf + len, MISR_BUFF_SIZE - len, "0x%x\n",
- m->hw_lm->ops.collect_misr(m->hw_lm));
+ sde_crtc->misr_data[i]);
}
buff_check:
@@ -3592,6 +4214,7 @@
struct sde_crtc *sde_crtc = to_sde_crtc(crtc);
struct sde_crtc_state *cstate = to_sde_crtc_state(crtc->state);
struct sde_crtc_res *res;
+ struct sde_crtc_respool *rp;
int i;
seq_printf(s, "num_connectors: %d\n", cstate->num_connectors);
@@ -3609,12 +4232,16 @@
sde_crtc->cur_perf.max_per_pipe_ib[i]);
}
- seq_printf(s, "rp.%d: ", cstate->rp.sequence_id);
- list_for_each_entry(res, &cstate->rp.res_list, list)
- seq_printf(s, "0x%x/0x%llx/%pK/%d ",
- res->type, res->tag, res->val,
- atomic_read(&res->refcount));
- seq_puts(s, "\n");
+ mutex_lock(&sde_crtc->rp_lock);
+ list_for_each_entry(rp, &sde_crtc->rp_head, rp_list) {
+ seq_printf(s, "rp.%d: ", rp->sequence_id);
+ list_for_each_entry(res, &rp->res_list, list)
+ seq_printf(s, "0x%x/0x%llx/%pK/%d ",
+ res->type, res->tag, res->val,
+ atomic_read(&res->refcount));
+ seq_puts(s, "\n");
+ }
+ mutex_unlock(&sde_crtc->rp_lock);
return 0;
}
@@ -3831,6 +4458,9 @@
spin_lock_init(&sde_crtc->spin_lock);
atomic_set(&sde_crtc->frame_pending, 0);
+ mutex_init(&sde_crtc->rp_lock);
+ INIT_LIST_HEAD(&sde_crtc->rp_head);
+
init_completion(&sde_crtc->frame_done_comp);
INIT_LIST_HEAD(&sde_crtc->frame_event_list);
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h
index 86b7855..43b3045 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.h
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.h
@@ -47,6 +47,50 @@
};
/**
+ * enum sde_crtc_smmu_state: smmu state
+ * @ATTACHED: all the context banks are attached.
+ * @DETACHED: all the context banks are detached.
+ * @DETACHED_SEC: secure context bank is detached.
+ * @ATTACH_ALL_REQ: transient state of attaching context banks.
+ * @DETACH_ALL_REQ: transient state of detaching context banks.
+ * @DETACH_SEC_REQ: tranisent state of secure context bank is detached
+ * @ATTACH_SEC_REQ: transient state of attaching secure context bank.
+ */
+enum sde_crtc_smmu_state {
+ ATTACHED = 0,
+ DETACHED,
+ DETACHED_SEC,
+ ATTACH_ALL_REQ,
+ DETACH_ALL_REQ,
+ DETACH_SEC_REQ,
+ ATTACH_SEC_REQ,
+};
+
+/**
+ * enum sde_crtc_smmu_state_transition_type: state transition type
+ * @NONE: no pending state transitions
+ * @PRE_COMMIT: state transitions should be done before processing the commit
+ * @POST_COMMIT: state transitions to be done after processing the commit.
+ */
+enum sde_crtc_smmu_state_transition_type {
+ NONE,
+ PRE_COMMIT,
+ POST_COMMIT
+};
+
+/**
+ * struct sde_crtc_smmu_state_data: stores the smmu state and transition type
+ * @state: current state of smmu context banks
+ * @transition_type: transition request type
+ * @transition_error: whether there is error while transitioning the state
+ */
+struct sde_crtc_smmu_state_data {
+ uint32_t state;
+ uint32_t transition_type;
+ uint32_t transition_error;
+};
+
+/**
* struct sde_crtc_mixer: stores the map for each virtual pipeline in the CRTC
* @hw_lm: LM HW Driver context
* @hw_ctl: CTL Path HW driver context
@@ -123,8 +167,11 @@
* @vblank_cb_count : count of vblank callback since last reset
* @play_count : frame count between crtc enable and disable
* @vblank_cb_time : ktime at vblank count reset
- * @vblank_enable : whether the user has requested vblank events
+ * @vblank_requested : whether the user has requested vblank events
* @suspend : whether or not a suspend operation is in progress
+ * @enabled : whether the SDE CRTC is currently enabled. updated in the
+ * commit-thread, not state-swap time which is earlier, so
+ * safe to make decisions on during VBLANK on/off work
* @feature_list : list of color processing features supported on a crtc
* @active_list : list of color processing features are active
* @dirty_list : list of color processing features are dirty
@@ -142,8 +189,12 @@
* @event_free_list : List of available event structures
* @event_lock : Spinlock around event handling code
* @misr_enable : boolean entry indicates misr enable/disable status.
+ * @misr_frame_count : misr frame count provided by client
+ * @misr_data : store misr data before turning off the clocks.
* @power_event : registered power event handle
* @cur_perf : current performance committed to clock/bandwidth driver
+ * @rp_lock : serialization lock for resource pool
+ * @rp_head : list of active resource pool
*/
struct sde_crtc {
struct drm_crtc base;
@@ -171,8 +222,9 @@
u32 vblank_cb_count;
u64 play_count;
ktime_t vblank_cb_time;
- bool vblank_enable;
+ bool vblank_requested;
bool suspend;
+ bool enabled;
struct list_head feature_list;
struct list_head active_list;
@@ -194,10 +246,17 @@
struct list_head event_free_list;
spinlock_t event_lock;
bool misr_enable;
+ u32 misr_frame_count;
+ u32 misr_data[CRTC_DUAL_MIXERS];
struct sde_power_event *power_event;
struct sde_core_perf_params cur_perf;
+
+ struct mutex rp_lock;
+ struct list_head rp_head;
+
+ struct sde_crtc_smmu_state_data smmu_state;
};
#define to_sde_crtc(x) container_of(x, struct sde_crtc, base)
@@ -242,11 +301,17 @@
/**
* sde_crtc_respool - crtc resource pool
+ * @rp_lock: pointer to serialization lock
+ * @rp_head: pointer to head of active resource pools of this crtc
+ * @rp_list: list of crtc resource pool
* @sequence_id: sequence identifier, incremented per state duplication
* @res_list: list of resource managed by this resource pool
* @ops: resource operations for parent resource pool
*/
struct sde_crtc_respool {
+ struct mutex *rp_lock;
+ struct list_head *rp_head;
+ struct list_head rp_list;
u32 sequence_id;
struct list_head res_list;
struct sde_crtc_res_ops ops;
@@ -269,9 +334,9 @@
* @lm_roi : Current LM ROI, possibly sub-rectangle of mode.
* Origin top left of CRTC.
* @user_roi_list : List of user's requested ROIs as from set property
+ * @property_state: Local storage for msm_prop properties
* @property_values: Current crtc property values
* @input_fence_timeout_ns : Cached input fence timeout, in ns
- * @property_blobs: Reference pointers for blob properties
* @num_dim_layers: Number of dim layers
* @dim_layer: Dim layer configs
* @new_perf: new performance state being requested
@@ -296,9 +361,9 @@
struct sde_rect lm_roi[CRTC_DUAL_MIXERS];
struct msm_roi_list user_roi_list;
- uint64_t property_values[CRTC_PROP_COUNT];
+ struct msm_property_state property_state;
+ struct msm_property_value property_values[CRTC_PROP_COUNT];
uint64_t input_fence_timeout_ns;
- struct drm_property_blob *property_blobs[CRTC_PROP_COUNT];
uint32_t num_dim_layers;
struct sde_hw_dim_layer dim_layer[SDE_MAX_DIM_LAYERS];
@@ -320,7 +385,7 @@
* Returns: Integer value of requested property
*/
#define sde_crtc_get_property(S, X) \
- ((S) && ((X) < CRTC_PROP_COUNT) ? ((S)->property_values[(X)]) : 0)
+ ((S) && ((X) < CRTC_PROP_COUNT) ? ((S)->property_values[(X)].value) : 0)
static inline int sde_crtc_mixer_width(struct sde_crtc *sde_crtc,
struct drm_display_mode *mode)
@@ -369,6 +434,14 @@
struct drm_crtc_state *old_state);
/**
+ * sde_crtc_complete_commit - callback signalling completion of current commit
+ * @crtc: Pointer to drm crtc object
+ * @old_state: Pointer to drm crtc old state object
+ */
+void sde_crtc_complete_commit(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_state);
+
+/**
* sde_crtc_init - create a new crtc object
* @dev: sde device
* @plane: base plane
@@ -492,4 +565,41 @@
void sde_crtc_get_crtc_roi(struct drm_crtc_state *state,
const struct sde_rect **crtc_roi);
+/** sde_crt_get_secure_level - retrieve the secure level from the give state
+ * object, this is used to determine the secure state of the crtc
+ * @crtc : Pointer to drm crtc structure
+ * @usr: Pointer to drm crtc state
+ * return: secure_level
+ */
+static inline int sde_crtc_get_secure_level(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+{
+ if (!crtc || !state)
+ return -EINVAL;
+
+ return sde_crtc_get_property(to_sde_crtc_state(state),
+ CRTC_PROP_SECURITY_LEVEL);
+}
+
+/**
+ * sde_crtc_get_secure_transition - determines the operations to be
+ * performed before transitioning to secure state
+ * This function should be called after swapping the new state
+ * @crtc: Pointer to drm crtc structure
+ * @old_crtc_state: Poniter to previous CRTC state
+ * Returns the bitmask of operations need to be performed, -Error in
+ * case of error cases
+ */
+int sde_crtc_get_secure_transition_ops(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_crtc_state,
+ bool old_valid_fb);
+
+/**
+ * sde_crtc_secure_ctrl - Initiates the transition between secure and
+ * non-secure world
+ * @crtc: Pointer to crtc
+ * @post_commit: if this operation is triggered after commit
+ */
+int sde_crtc_secure_ctrl(struct drm_crtc *crtc, bool post_commit);
+
#endif /* _SDE_CRTC_H_ */
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index 0e94085..edfef24 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -71,7 +71,11 @@
#define MISR_BUFF_SIZE 256
-#define IDLE_TIMEOUT 64
+#define IDLE_TIMEOUT (66 - 16/2)
+#define IDLE_SHORT_TIMEOUT 1
+
+/* Maximum number of VSYNC wait attempts for RSC state transition */
+#define MAX_RSC_WAIT 5
/**
* enum sde_enc_rc_events - events for resource control state machine
@@ -86,15 +90,29 @@
* Event signals the end of the data transfer after the PP FRAME_DONE
* event. At the end of this event, a delayed work is scheduled to go to
* IDLE_PC state after IDLE_TIMEOUT time.
+ * @SDE_ENC_RC_EVENT_PRE_STOP:
+ * This event happens at NORMAL priority.
+ * This event, when received during the ON state, set RSC to IDLE, and
+ * and leave the RC STATE in the PRE_OFF state.
+ * It should be followed by the STOP event as part of encoder disable.
+ * If received during IDLE or OFF states, it will do nothing.
* @SDE_ENC_RC_EVENT_STOP:
* This event happens at NORMAL priority.
- * When this event is received, disable all the MDP/DSI core clocks
- * and request RSC with IDLE state. Resource state should be in OFF
- * at the end of the event.
- * @SDE_ENC_RC_EARLY_WAKEUP
+ * When this event is received, disable all the MDP/DSI core clocks, and
+ * disable IRQs. It should be called from the PRE_OFF or IDLE states.
+ * IDLE is expected when IDLE_PC has run, and PRE_OFF did nothing.
+ * PRE_OFF is expected when PRE_STOP was executed during the ON state.
+ * Resource state should be in OFF at the end of the event.
+ * @SDE_ENC_RC_EVENT_PRE_MODESET:
* This event happens at NORMAL priority from a work item.
- * Event signals that there will be frame update soon and the driver should
- * wake up early to update the frame with minimum latency.
+ * Event signals that there is a seamless mode switch is in prgoress. A
+ * client needs to turn of only irq - leave clocks ON to reduce the mode
+ * switch latency.
+ * @SDE_ENC_RC_EVENT_POST_MODESET:
+ * This event happens at NORMAL priority from a work item.
+ * Event signals that seamless mode switch is complete and resources are
+ * acquired. Clients wants to turn on the irq again and update the rsc
+ * with new vtotal.
* @SDE_ENC_RC_EVENT_ENTER_IDLE:
* This event happens at NORMAL priority from a work item.
* Event signals that there were no frame updates for IDLE_TIMEOUT time.
@@ -104,20 +122,26 @@
enum sde_enc_rc_events {
SDE_ENC_RC_EVENT_KICKOFF = 1,
SDE_ENC_RC_EVENT_FRAME_DONE,
+ SDE_ENC_RC_EVENT_PRE_STOP,
SDE_ENC_RC_EVENT_STOP,
- SDE_ENC_RC_EVENT_EARLY_WAKE_UP,
+ SDE_ENC_RC_EVENT_PRE_MODESET,
+ SDE_ENC_RC_EVENT_POST_MODESET,
SDE_ENC_RC_EVENT_ENTER_IDLE
};
/*
* enum sde_enc_rc_states - states that the resource control maintains
* @SDE_ENC_RC_STATE_OFF: Resource is in OFF state
+ * @SDE_ENC_RC_STATE_PRE_OFF: Resource is transitioning to OFF state
* @SDE_ENC_RC_STATE_ON: Resource is in ON state
+ * @SDE_ENC_RC_STATE_MODESET: Resource is in modeset state
* @SDE_ENC_RC_STATE_IDLE: Resource is in IDLE state
*/
enum sde_enc_rc_states {
SDE_ENC_RC_STATE_OFF,
+ SDE_ENC_RC_STATE_PRE_OFF,
SDE_ENC_RC_STATE_ON,
+ SDE_ENC_RC_STATE_MODESET,
SDE_ENC_RC_STATE_IDLE
};
@@ -159,7 +183,9 @@
* @rsc_client: rsc client pointer
* @rsc_state_init: boolean to indicate rsc config init
* @disp_info: local copy of msm_display_info struct
+ * @mode_info: local copy of msm_mode_info struct
* @misr_enable: misr enable/disable status
+ * @misr_frame_count: misr frame count before start capturing the data
* @idle_pc_supported: indicate if idle power collaps is supported
* @rc_lock: resource control mutex lock to protect
* virt encoder over various state changes
@@ -168,7 +194,7 @@
* clks and resources after IDLE_TIMEOUT time.
* @topology: topology of the display
* @mode_set_complete: flag to indicate modeset completion
- * @rsc_cfg: rsc configuration
+ * @rsc_config: rsc configuration for display vtotal, fps, etc.
* @cur_conn_roi: current connector roi
* @prv_conn_roi: previous connector roi to optimize if unchanged
*/
@@ -202,7 +228,9 @@
struct sde_rsc_client *rsc_client;
bool rsc_state_init;
struct msm_display_info disp_info;
+ struct msm_mode_info mode_info;
bool misr_enable;
+ u32 misr_frame_count;
bool idle_pc_supported;
struct mutex rc_lock;
@@ -211,7 +239,7 @@
struct msm_display_topology topology;
bool mode_set_complete;
- struct sde_encoder_rsc_config rsc_cfg;
+ struct sde_rsc_cmd_config rsc_config;
struct sde_rect cur_conn_roi;
struct sde_rect prv_conn_roi;
};
@@ -228,7 +256,7 @@
return false;
sde_enc = to_sde_encoder_virt(drm_enc);
- comp_info = &sde_enc->disp_info.comp_info;
+ comp_info = &sde_enc->mode_info.comp_info;
return (comp_info->comp_type == MSM_DISPLAY_COMPRESSION_DSC);
}
@@ -321,6 +349,8 @@
/* return EWOULDBLOCK since we know the wait isn't necessary */
if (phys_enc->enable_state == SDE_ENC_DISABLED) {
SDE_ERROR_PHYS(phys_enc, "encoder is disabled\n");
+ SDE_EVT32(DRMID(phys_enc->parent), intr_idx, irq->hw_idx,
+ irq->irq_idx, intr_idx, SDE_EVTLOG_ERROR);
return -EWOULDBLOCK;
}
@@ -334,9 +364,9 @@
SDE_DEBUG_PHYS(phys_enc, "pending_cnt %d\n",
atomic_read(wait_info->atomic_cnt));
- SDE_EVT32(DRMID(phys_enc->parent), irq->hw_idx,
- atomic_read(wait_info->atomic_cnt),
- SDE_EVTLOG_FUNC_ENTRY);
+ SDE_EVT32_VERBOSE(DRMID(phys_enc->parent), intr_idx, irq->hw_idx,
+ irq->irq_idx, phys_enc->hw_pp->idx - PINGPONG_0,
+ atomic_read(wait_info->atomic_cnt), SDE_EVTLOG_FUNC_ENTRY);
ret = sde_encoder_helper_wait_event_timeout(
DRMID(phys_enc->parent),
@@ -349,9 +379,10 @@
if (irq_status) {
unsigned long flags;
- SDE_EVT32(DRMID(phys_enc->parent),
- irq->hw_idx,
- atomic_read(wait_info->atomic_cnt));
+ SDE_EVT32(DRMID(phys_enc->parent), intr_idx,
+ irq->hw_idx, irq->irq_idx,
+ phys_enc->hw_pp->idx - PINGPONG_0,
+ atomic_read(wait_info->atomic_cnt));
SDE_DEBUG_PHYS(phys_enc,
"done but irq %d not triggered\n",
irq->irq_idx);
@@ -361,13 +392,22 @@
ret = 0;
} else {
ret = -ETIMEDOUT;
+ SDE_EVT32(DRMID(phys_enc->parent), intr_idx,
+ irq->hw_idx, irq->irq_idx,
+ phys_enc->hw_pp->idx - PINGPONG_0,
+ atomic_read(wait_info->atomic_cnt), irq_status,
+ SDE_EVTLOG_ERROR);
}
} else {
ret = 0;
+ SDE_EVT32(DRMID(phys_enc->parent), intr_idx, irq->hw_idx,
+ irq->irq_idx, phys_enc->hw_pp->idx - PINGPONG_0,
+ atomic_read(wait_info->atomic_cnt));
}
- SDE_EVT32(DRMID(phys_enc->parent), irq->hw_idx, ret,
- SDE_EVTLOG_FUNC_EXIT);
+ SDE_EVT32_VERBOSE(DRMID(phys_enc->parent), intr_idx, irq->hw_idx,
+ irq->irq_idx, ret, phys_enc->hw_pp->idx - PINGPONG_0,
+ atomic_read(wait_info->atomic_cnt), SDE_EVTLOG_FUNC_EXIT);
return ret;
}
@@ -501,7 +541,7 @@
phys->ops.get_hw_resources(phys, hw_res, conn_state);
}
- hw_res->topology = sde_enc->topology;
+ hw_res->topology = sde_enc->mode_info.topology;
}
void sde_encoder_destroy(struct drm_encoder *drm_enc)
@@ -597,7 +637,7 @@
if (hw_mdptop->ops.setup_split_pipe)
hw_mdptop->ops.setup_split_pipe(hw_mdptop, &cfg);
- } else {
+ } else if (sde_enc->hw_pp[0]) {
/*
* slave encoder
* - determine split index from master index,
@@ -625,7 +665,7 @@
cur_mode->hdisplay == adj_mode->hdisplay &&
cur_mode->vrefresh == adj_mode->vrefresh) {
adj_mode->private = cur_mode->private;
- adj_mode->private_flags = cur_mode->private_flags;
+ adj_mode->private_flags |= cur_mode->private_flags;
}
}
}
@@ -863,7 +903,7 @@
struct sde_encoder_phys *enc_master = sde_enc->cur_master;
const struct sde_rect *roi = &sde_enc->cur_conn_roi;
struct msm_display_dsc_info *dsc =
- &sde_enc->disp_info.comp_info.dsc_info;
+ &sde_enc->mode_info.comp_info.dsc_info;
if (dsc == NULL || hw_dsc == NULL || hw_pp == NULL || !enc_master) {
SDE_ERROR_ENC(sde_enc, "invalid params for DSC\n");
@@ -928,8 +968,8 @@
if (enc_master->intf_mode == INTF_MODE_VIDEO)
dsc_common_mode |= DSC_MODE_VIDEO;
- memcpy(&dsc[0], &sde_enc->disp_info.comp_info.dsc_info, sizeof(dsc[0]));
- memcpy(&dsc[1], &sde_enc->disp_info.comp_info.dsc_info, sizeof(dsc[1]));
+ memcpy(&dsc[0], &sde_enc->mode_info.comp_info.dsc_info, sizeof(dsc[0]));
+ memcpy(&dsc[1], &sde_enc->mode_info.comp_info.dsc_info, sizeof(dsc[1]));
/*
* Since both DSC use same pic dimension, set same pic dimension
@@ -993,7 +1033,7 @@
struct sde_hw_dsc *hw_dsc[MAX_CHANNELS_PER_ENC];
struct sde_hw_pingpong *hw_pp[MAX_CHANNELS_PER_ENC];
struct msm_display_dsc_info *dsc =
- &sde_enc->disp_info.comp_info.dsc_info;
+ &sde_enc->mode_info.comp_info.dsc_info;
bool half_panel_partial_update;
int i;
@@ -1129,6 +1169,7 @@
struct sde_kms *sde_kms;
struct sde_hw_mdp *hw_mdptop;
struct drm_encoder *drm_enc;
+ struct msm_mode_info *mode_info;
int i;
if (!sde_enc || !disp_info) {
@@ -1158,13 +1199,19 @@
return;
}
+ mode_info = &sde_enc->mode_info;
+ if (!mode_info) {
+ SDE_ERROR("invalid mode info\n");
+ return;
+ }
+
if (hw_mdptop->ops.setup_vsync_source &&
disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) {
for (i = 0; i < sde_enc->num_phys_encs; i++)
vsync_cfg.ppnumber[i] = sde_enc->hw_pp[i]->idx;
vsync_cfg.pp_count = sde_enc->num_phys_encs;
- vsync_cfg.frame_rate = sde_enc->disp_info.frame_rate;
+ vsync_cfg.frame_rate = mode_info->frame_rate;
if (is_dummy)
vsync_cfg.vsync_source = SDE_VSYNC_SOURCE_WD_TIMER_1;
else if (disp_info->is_te_using_watchdog_timer)
@@ -1177,26 +1224,35 @@
}
}
-static int sde_encoder_update_rsc_client(
+static int _sde_encoder_update_rsc_client(
struct drm_encoder *drm_enc,
struct sde_encoder_rsc_config *config, bool enable)
{
struct sde_encoder_virt *sde_enc;
+ struct drm_crtc *crtc;
enum sde_rsc_state rsc_state;
- struct sde_rsc_cmd_config rsc_config;
- int ret;
+ struct sde_rsc_cmd_config *rsc_config;
+ int ret, prefill_lines;
struct msm_display_info *disp_info;
+ struct msm_mode_info *mode_info;
+ int wait_vblank_crtc_id = SDE_RSC_INVALID_CRTC_ID;
+ int wait_count = 0;
+ struct drm_crtc *primary_crtc;
+ int pipe = -1;
- if (!drm_enc) {
- SDE_ERROR("invalid encoder\n");
+ if (!drm_enc || !drm_enc->crtc || !drm_enc->dev) {
+ SDE_ERROR("invalid arguments\n");
return -EINVAL;
}
sde_enc = to_sde_encoder_virt(drm_enc);
+ crtc = drm_enc->crtc;
disp_info = &sde_enc->disp_info;
+ mode_info = &sde_enc->mode_info;
+ rsc_config = &sde_enc->rsc_config;
if (!sde_enc->rsc_client) {
- SDE_DEBUG("rsc client not created\n");
+ SDE_DEBUG_ENC(sde_enc, "rsc client not created\n");
return 0;
}
@@ -1209,40 +1265,119 @@
(((disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) &&
disp_info->is_primary) ? SDE_RSC_CMD_STATE :
SDE_RSC_VID_STATE) : SDE_RSC_IDLE_STATE;
+ prefill_lines = config ? mode_info->prefill_lines +
+ config->inline_rotate_prefill : mode_info->prefill_lines;
- if (config && memcmp(&sde_enc->rsc_cfg, config,
- sizeof(sde_enc->rsc_cfg)))
+ /* compare specific items and reconfigure the rsc */
+ if ((rsc_config->fps != mode_info->frame_rate) ||
+ (rsc_config->vtotal != mode_info->vtotal) ||
+ (rsc_config->prefill_lines != prefill_lines) ||
+ (rsc_config->jitter_numer != mode_info->jitter_numer) ||
+ (rsc_config->jitter_denom != mode_info->jitter_denom)) {
+ rsc_config->fps = mode_info->frame_rate;
+ rsc_config->vtotal = mode_info->vtotal;
+ rsc_config->prefill_lines = prefill_lines;
+ rsc_config->jitter_numer = mode_info->jitter_numer;
+ rsc_config->jitter_denom = mode_info->jitter_denom;
sde_enc->rsc_state_init = false;
+ }
if (rsc_state != SDE_RSC_IDLE_STATE && !sde_enc->rsc_state_init
&& disp_info->is_primary) {
- rsc_config.fps = disp_info->frame_rate;
- rsc_config.vtotal = disp_info->vtotal;
- rsc_config.prefill_lines = disp_info->prefill_lines;
- rsc_config.jitter_numer = disp_info->jitter_numer;
- rsc_config.jitter_denom = disp_info->jitter_denom;
- rsc_config.prefill_lines += config ?
- config->inline_rotate_prefill : 0;
/* update it only once */
sde_enc->rsc_state_init = true;
- if (config)
- sde_enc->rsc_cfg = *config;
ret = sde_rsc_client_state_update(sde_enc->rsc_client,
- rsc_state, &rsc_config,
- drm_enc->crtc ? drm_enc->crtc->index : -1);
+ rsc_state, rsc_config, crtc->base.id,
+ &wait_vblank_crtc_id);
} else {
ret = sde_rsc_client_state_update(sde_enc->rsc_client,
- rsc_state, NULL,
- drm_enc->crtc ? drm_enc->crtc->index : -1);
+ rsc_state, NULL, crtc->base.id,
+ &wait_vblank_crtc_id);
}
- if (ret)
- SDE_ERROR("sde rsc client update failed ret:%d\n", ret);
+ /**
+ * if RSC performed a state change that requires a VBLANK wait, it will
+ * set wait_vblank_crtc_id to the CRTC whose VBLANK we must wait on.
+ *
+ * if we are the primary display, we will need to enable and wait
+ * locally since we hold the commit thread
+ *
+ * if we are an external display, we must send a signal to the primary
+ * to enable its VBLANK and wait one, since the RSC hardware is driven
+ * by the primary panel's VBLANK signals
+ */
+ SDE_EVT32_VERBOSE(DRMID(drm_enc), wait_vblank_crtc_id);
+ if (ret) {
+ SDE_ERROR_ENC(sde_enc,
+ "sde rsc client update failed ret:%d\n", ret);
+ return ret;
+ } else if (wait_vblank_crtc_id == SDE_RSC_INVALID_CRTC_ID) {
+ return ret;
+ }
+
+ if (crtc->base.id != wait_vblank_crtc_id) {
+ primary_crtc = drm_crtc_find(drm_enc->dev, wait_vblank_crtc_id);
+ if (!primary_crtc) {
+ SDE_ERROR_ENC(sde_enc,
+ "failed to find primary crtc id %d\n",
+ wait_vblank_crtc_id);
+ return -EINVAL;
+ }
+ pipe = drm_crtc_index(primary_crtc);
+ }
+
+ /**
+ * note: VBLANK is expected to be enabled at this point in
+ * resource control state machine if on primary CRTC
+ */
+ for (wait_count = 0; wait_count < MAX_RSC_WAIT; wait_count++) {
+ if (sde_rsc_client_is_state_update_complete(
+ sde_enc->rsc_client))
+ break;
+
+ if (crtc->base.id == wait_vblank_crtc_id)
+ ret = sde_encoder_wait_for_event(drm_enc,
+ MSM_ENC_VBLANK);
+ else
+ drm_wait_one_vblank(drm_enc->dev, pipe);
+
+ if (ret) {
+ SDE_ERROR_ENC(sde_enc,
+ "wait for vblank failed ret:%d\n", ret);
+ break;
+ }
+ }
+
+ if (wait_count >= MAX_RSC_WAIT)
+ SDE_EVT32(DRMID(drm_enc), wait_vblank_crtc_id, wait_count,
+ SDE_EVTLOG_ERROR);
return ret;
}
+static void _sde_encoder_irq_control(struct drm_encoder *drm_enc, bool enable)
+{
+ struct sde_encoder_virt *sde_enc;
+ int i;
+
+ if (!drm_enc) {
+ SDE_ERROR("invalid encoder\n");
+ return;
+ }
+
+ sde_enc = to_sde_encoder_virt(drm_enc);
+
+ SDE_DEBUG_ENC(sde_enc, "enable:%d\n", enable);
+ for (i = 0; i < sde_enc->num_phys_encs; i++) {
+ struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
+
+ if (phys && phys->ops.irq_control)
+ phys->ops.irq_control(phys, enable);
+ }
+
+}
+
struct sde_rsc_client *sde_encoder_get_rsc_client(struct drm_encoder *drm_enc)
{
struct sde_encoder_virt *sde_enc;
@@ -1253,14 +1388,43 @@
return sde_enc->rsc_client;
}
+static void _sde_encoder_resource_control_rsc_update(
+ struct drm_encoder *drm_enc, bool enable)
+{
+ struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
+ struct sde_encoder_rsc_config rsc_cfg = { 0 };
+
+ if (enable) {
+ rsc_cfg.inline_rotate_prefill =
+ sde_crtc_get_inline_prefill(drm_enc->crtc);
+
+ /* connect the TE source to actual TE GPIO to drive RSC */
+ _sde_encoder_update_vsync_source(sde_enc, &sde_enc->disp_info,
+ false);
+
+ _sde_encoder_update_rsc_client(drm_enc, &rsc_cfg, true);
+ } else {
+ _sde_encoder_update_rsc_client(drm_enc, NULL, false);
+
+ /**
+ * disconnect the TE source from the actual TE GPIO for RSC
+ *
+ * this call is for hardware workaround on sdm845 and should
+ * not be removed without considering the design changes for
+ * sde rsc + command mode concurrency. It may lead to pp
+ * timeout due to vsync from panel for command mode panel.
+ */
+ _sde_encoder_update_vsync_source(sde_enc, &sde_enc->disp_info,
+ true);
+ }
+}
+
static void _sde_encoder_resource_control_helper(struct drm_encoder *drm_enc,
bool enable)
{
struct msm_drm_private *priv;
struct sde_kms *sde_kms;
struct sde_encoder_virt *sde_enc;
- struct sde_encoder_rsc_config rsc_cfg = { 0 };
- int i;
sde_enc = to_sde_encoder_virt(drm_enc);
priv = drm_enc->dev->dev_private;
@@ -1283,43 +1447,11 @@
sde_connector_clk_ctrl(sde_enc->cur_master->connector, true);
/* enable all the irq */
- for (i = 0; i < sde_enc->num_phys_encs; i++) {
- struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
-
- if (phys && phys->ops.irq_control)
- phys->ops.irq_control(phys, true);
- }
-
- rsc_cfg.inline_rotate_prefill =
- sde_crtc_get_inline_prefill(drm_enc->crtc);
-
- _sde_encoder_update_vsync_source(sde_enc, &sde_enc->disp_info,
- false);
-
- /* enable RSC */
- sde_encoder_update_rsc_client(drm_enc, &rsc_cfg, true);
+ _sde_encoder_irq_control(drm_enc, true);
} else {
-
- /* disable RSC */
- sde_encoder_update_rsc_client(drm_enc, NULL, false);
-
- /**
- * this call is for hardware workaround on sdm845 and should
- * not be removed without considering the design changes for
- * sde rsc + command mode concurrency. It may lead to pp
- * timeout due to vsync from panel for command mode panel.
- */
- _sde_encoder_update_vsync_source(sde_enc, &sde_enc->disp_info,
- true);
/* disable all the irq */
- for (i = 0; i < sde_enc->num_phys_encs; i++) {
- struct sde_encoder_phys *phys =
- sde_enc->phys_encs[i];
-
- if (phys && phys->ops.irq_control)
- phys->ops.irq_control(phys, false);
- }
+ _sde_encoder_irq_control(drm_enc, false);
/* disable DSI clks */
sde_connector_clk_ctrl(sde_enc->cur_master->connector, false);
@@ -1334,10 +1466,12 @@
static int sde_encoder_resource_control(struct drm_encoder *drm_enc,
u32 sw_event)
{
- bool schedule_off = false;
+ bool autorefresh_enabled = false;
+ unsigned int lp, idle_timeout;
struct sde_encoder_virt *sde_enc;
struct msm_drm_private *priv;
struct msm_drm_thread *disp_thread;
+ int ret;
if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private ||
!drm_enc->crtc) {
@@ -1354,17 +1488,20 @@
disp_thread = &priv->disp_thread[drm_enc->crtc->index];
/*
- * when idle_pc is not supported, process only KICKOFF and STOP
- * event and return early for other events (ie video mode).
+ * when idle_pc is not supported, process only KICKOFF, STOP and MODESET
+ * events and return early for other events (ie video mode).
*/
if (!sde_enc->idle_pc_supported &&
(sw_event != SDE_ENC_RC_EVENT_KICKOFF &&
- sw_event != SDE_ENC_RC_EVENT_STOP))
+ sw_event != SDE_ENC_RC_EVENT_PRE_MODESET &&
+ sw_event != SDE_ENC_RC_EVENT_POST_MODESET &&
+ sw_event != SDE_ENC_RC_EVENT_STOP &&
+ sw_event != SDE_ENC_RC_EVENT_PRE_STOP))
return 0;
SDE_DEBUG_ENC(sde_enc, "sw_event:%d, idle_pc_supported:%d\n", sw_event,
sde_enc->idle_pc_supported);
- SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->idle_pc_supported,
+ SDE_EVT32_VERBOSE(DRMID(drm_enc), sw_event, sde_enc->idle_pc_supported,
sde_enc->rc_state, SDE_EVTLOG_FUNC_ENTRY);
switch (sw_event) {
@@ -1383,10 +1520,19 @@
sw_event);
mutex_unlock(&sde_enc->rc_lock);
return 0;
+ } else if (sde_enc->rc_state != SDE_ENC_RC_STATE_OFF &&
+ sde_enc->rc_state != SDE_ENC_RC_STATE_IDLE) {
+ SDE_ERROR_ENC(sde_enc, "sw_event:%d, rc in state %d\n",
+ sw_event, sde_enc->rc_state);
+ SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
+ SDE_EVTLOG_ERROR);
+ mutex_unlock(&sde_enc->rc_lock);
+ return -EINVAL;
}
/* enable all the clks and resources */
_sde_encoder_resource_control_helper(drm_enc, true);
+ _sde_encoder_resource_control_rsc_update(drm_enc, true);
SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
SDE_ENC_RC_STATE_ON, SDE_EVTLOG_FUNC_CASE1);
@@ -1405,6 +1551,8 @@
if (sde_enc->rc_state != SDE_ENC_RC_STATE_ON) {
SDE_ERROR_ENC(sde_enc, "sw_event:%d,rc:%d-unexpected\n",
sw_event, sde_enc->rc_state);
+ SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
+ SDE_EVTLOG_ERROR);
return -EINVAL;
}
@@ -1417,18 +1565,38 @@
return 0;
}
- /* schedule delayed off work */
- kthread_queue_delayed_work(
+ /* schedule delayed off work if autorefresh is disabled */
+ if (sde_enc->cur_master &&
+ sde_enc->cur_master->ops.is_autorefresh_enabled)
+ autorefresh_enabled =
+ sde_enc->cur_master->ops.is_autorefresh_enabled(
+ sde_enc->cur_master);
+
+ /* set idle timeout based on master connector's lp value */
+ if (sde_enc->cur_master)
+ lp = sde_connector_get_lp(
+ sde_enc->cur_master->connector);
+ else
+ lp = SDE_MODE_DPMS_ON;
+
+ if (lp == SDE_MODE_DPMS_LP2)
+ idle_timeout = IDLE_SHORT_TIMEOUT;
+ else
+ idle_timeout = IDLE_TIMEOUT;
+
+ if (!autorefresh_enabled)
+ kthread_queue_delayed_work(
&disp_thread->worker,
&sde_enc->delayed_off_work,
- msecs_to_jiffies(IDLE_TIMEOUT));
+ msecs_to_jiffies(idle_timeout));
SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
- SDE_EVTLOG_FUNC_CASE2);
+ autorefresh_enabled,
+ idle_timeout, SDE_EVTLOG_FUNC_CASE2);
SDE_DEBUG_ENC(sde_enc, "sw_event:%d, work scheduled\n",
sw_event);
break;
- case SDE_ENC_RC_EVENT_STOP:
+ case SDE_ENC_RC_EVENT_PRE_STOP:
/* cancel delayed off work, if any */
if (kthread_cancel_delayed_work_sync(
&sde_enc->delayed_off_work))
@@ -1437,79 +1605,128 @@
mutex_lock(&sde_enc->rc_lock);
+ /* skip if is already OFF or IDLE, resources are off already */
+ if (sde_enc->rc_state == SDE_ENC_RC_STATE_OFF ||
+ sde_enc->rc_state == SDE_ENC_RC_STATE_IDLE) {
+ SDE_DEBUG_ENC(sde_enc, "sw_event:%d, rc in %d state\n",
+ sw_event, sde_enc->rc_state);
+ mutex_unlock(&sde_enc->rc_lock);
+ return 0;
+ }
+
+ /**
+ * IRQs are still enabled currently, which allows wait for
+ * VBLANK which RSC may require to correctly transition to OFF
+ */
+ _sde_encoder_resource_control_rsc_update(drm_enc, false);
+
+ SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
+ SDE_ENC_RC_STATE_PRE_OFF,
+ SDE_EVTLOG_FUNC_CASE3);
+
+ sde_enc->rc_state = SDE_ENC_RC_STATE_PRE_OFF;
+
+ mutex_unlock(&sde_enc->rc_lock);
+ break;
+
+ case SDE_ENC_RC_EVENT_STOP:
+ mutex_lock(&sde_enc->rc_lock);
+
/* return if the resource control is already in OFF state */
if (sde_enc->rc_state == SDE_ENC_RC_STATE_OFF) {
SDE_DEBUG_ENC(sde_enc, "sw_event:%d, rc in OFF state\n",
sw_event);
mutex_unlock(&sde_enc->rc_lock);
return 0;
+ } else if (sde_enc->rc_state == SDE_ENC_RC_STATE_ON ||
+ sde_enc->rc_state == SDE_ENC_RC_STATE_MODESET) {
+ SDE_ERROR_ENC(sde_enc, "sw_event:%d, rc in state %d\n",
+ sw_event, sde_enc->rc_state);
+ SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
+ SDE_EVTLOG_ERROR);
+ mutex_unlock(&sde_enc->rc_lock);
+ return -EINVAL;
}
- /*
- * disable the clks and resources only if the resource control
- * is in ON state, otherwise the clks and resources would have
- * been disabled while going into IDLE state
+ /**
+ * expect to arrive here only if in either idle state or pre-off
+ * and in IDLE state the resources are already disabled
*/
- if (sde_enc->rc_state == SDE_ENC_RC_STATE_ON)
+ if (sde_enc->rc_state == SDE_ENC_RC_STATE_PRE_OFF)
_sde_encoder_resource_control_helper(drm_enc, false);
SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
- SDE_ENC_RC_STATE_OFF, SDE_EVTLOG_FUNC_CASE3);
+ SDE_ENC_RC_STATE_OFF, SDE_EVTLOG_FUNC_CASE4);
sde_enc->rc_state = SDE_ENC_RC_STATE_OFF;
mutex_unlock(&sde_enc->rc_lock);
break;
- case SDE_ENC_RC_EVENT_EARLY_WAKE_UP:
+ case SDE_ENC_RC_EVENT_PRE_MODESET:
/* cancel delayed off work, if any */
if (kthread_cancel_delayed_work_sync(
- &sde_enc->delayed_off_work)) {
+ &sde_enc->delayed_off_work))
SDE_DEBUG_ENC(sde_enc, "sw_event:%d, work cancelled\n",
sw_event);
- schedule_off = true;
- }
mutex_lock(&sde_enc->rc_lock);
- SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
- schedule_off, SDE_EVTLOG_FUNC_CASE4);
-
- /* return if the resource control is in OFF state */
- if (sde_enc->rc_state == SDE_ENC_RC_STATE_OFF) {
- SDE_DEBUG_ENC(sde_enc, "sw_event:%d, rc in OFF state\n",
- sw_event);
- mutex_unlock(&sde_enc->rc_lock);
- return 0;
- }
-
- /*
- * enable all the clks and resources if resource control is
- * coming out of IDLE state
- */
- if (sde_enc->rc_state == SDE_ENC_RC_STATE_IDLE) {
+ /* return if the resource control is already in ON state */
+ if (sde_enc->rc_state != SDE_ENC_RC_STATE_ON) {
+ /* enable all the clks and resources */
_sde_encoder_resource_control_helper(drm_enc, true);
+
+ _sde_encoder_resource_control_rsc_update(drm_enc, true);
+
+ SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
+ SDE_ENC_RC_STATE_ON, SDE_EVTLOG_FUNC_CASE5);
sde_enc->rc_state = SDE_ENC_RC_STATE_ON;
- schedule_off = true;
}
- /*
- * schedule off work when there are no frames pending and
- * 1. early wakeup cancelled off work
- * 2. early wakeup changed the rc_state to ON - this is to
- * handle cases where early wakeup is called but no
- * frame updates
- */
- if (schedule_off && !sde_crtc_frame_pending(drm_enc->crtc)) {
- /* schedule delayed off work */
- kthread_queue_delayed_work(
- &disp_thread->worker,
- &sde_enc->delayed_off_work,
- msecs_to_jiffies(IDLE_TIMEOUT));
- SDE_DEBUG_ENC(sde_enc, "sw_event:%d, work scheduled\n",
- sw_event);
+ ret = sde_encoder_wait_for_event(drm_enc, MSM_ENC_TX_COMPLETE);
+ if (ret && ret != -EWOULDBLOCK) {
+ SDE_ERROR_ENC(sde_enc,
+ "wait for commit done returned %d\n",
+ ret);
+ SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
+ ret, SDE_EVTLOG_ERROR);
+ mutex_unlock(&sde_enc->rc_lock);
+ return -EINVAL;
}
+ _sde_encoder_irq_control(drm_enc, false);
+
+ SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
+ SDE_ENC_RC_STATE_MODESET, SDE_EVTLOG_FUNC_CASE5);
+
+ sde_enc->rc_state = SDE_ENC_RC_STATE_MODESET;
+ mutex_unlock(&sde_enc->rc_lock);
+ break;
+
+ case SDE_ENC_RC_EVENT_POST_MODESET:
+ mutex_lock(&sde_enc->rc_lock);
+
+ /* return if the resource control is already in ON state */
+ if (sde_enc->rc_state != SDE_ENC_RC_STATE_MODESET) {
+ SDE_ERROR_ENC(sde_enc,
+ "sw_event:%d, rc:%d !MODESET state\n",
+ sw_event, sde_enc->rc_state);
+ SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
+ SDE_EVTLOG_ERROR);
+ mutex_unlock(&sde_enc->rc_lock);
+ return -EINVAL;
+ }
+
+ _sde_encoder_irq_control(drm_enc, true);
+
+ _sde_encoder_update_rsc_client(drm_enc, NULL, true);
+
+ SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
+ SDE_ENC_RC_STATE_ON, SDE_EVTLOG_FUNC_CASE6);
+
+ sde_enc->rc_state = SDE_ENC_RC_STATE_ON;
+
mutex_unlock(&sde_enc->rc_lock);
break;
@@ -1517,10 +1734,10 @@
mutex_lock(&sde_enc->rc_lock);
if (sde_enc->rc_state != SDE_ENC_RC_STATE_ON) {
- SDE_DEBUG_ENC(sde_enc, "sw_event:%d, rc:%d !ON state\n",
+ SDE_ERROR_ENC(sde_enc, "sw_event:%d, rc:%d !ON state\n",
sw_event, sde_enc->rc_state);
- SDE_EVT32_VERBOSE(DRMID(drm_enc), sw_event,
- sde_enc->rc_state);
+ SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
+ SDE_EVTLOG_ERROR);
mutex_unlock(&sde_enc->rc_lock);
return 0;
}
@@ -1530,30 +1747,32 @@
* ignore the IDLE event, it's probably a stale timer event
*/
if (sde_enc->frame_busy_mask[0]) {
- SDE_DEBUG_ENC(sde_enc,
+ SDE_ERROR_ENC(sde_enc,
"sw_event:%d, rc:%d frame pending\n",
sw_event, sde_enc->rc_state);
- SDE_EVT32_VERBOSE(DRMID(drm_enc), sw_event,
- sde_enc->rc_state);
+ SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
+ SDE_EVTLOG_ERROR);
mutex_unlock(&sde_enc->rc_lock);
return 0;
}
/* disable all the clks and resources */
+ _sde_encoder_resource_control_rsc_update(drm_enc, false);
_sde_encoder_resource_control_helper(drm_enc, false);
SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
- SDE_ENC_RC_STATE_IDLE, SDE_EVTLOG_FUNC_CASE5);
+ SDE_ENC_RC_STATE_IDLE, SDE_EVTLOG_FUNC_CASE7);
sde_enc->rc_state = SDE_ENC_RC_STATE_IDLE;
mutex_unlock(&sde_enc->rc_lock);
break;
default:
+ SDE_EVT32(DRMID(drm_enc), sw_event, SDE_EVTLOG_ERROR);
SDE_ERROR("unexpected sw_event: %d\n", sw_event);
break;
}
- SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->idle_pc_supported,
+ SDE_EVT32_VERBOSE(DRMID(drm_enc), sw_event, sde_enc->idle_pc_supported,
sde_enc->rc_state, SDE_EVTLOG_FUNC_EXIT);
return 0;
}
@@ -1613,7 +1832,7 @@
sde_conn = to_sde_connector(conn);
if (sde_conn) {
- ret = sde_conn->ops.get_topology(adj_mode, &sde_enc->topology,
+ ret = sde_conn->ops.get_mode_info(adj_mode, &sde_enc->mode_info,
sde_kms->catalog->max_mixer_width);
if (ret) {
SDE_ERROR_ENC(sde_enc,
@@ -1622,6 +1841,19 @@
}
}
+ /* release resources before seamless mode change */
+ if (msm_is_mode_seamless_dms(adj_mode)) {
+ /* restore resource state before releasing them */
+ ret = sde_encoder_resource_control(drm_enc,
+ SDE_ENC_RC_EVENT_PRE_MODESET);
+ if (ret) {
+ SDE_ERROR_ENC(sde_enc,
+ "sde resource control failed: %d\n",
+ ret);
+ return;
+ }
+ }
+
/* Reserve dynamic resources now. Indicating non-AtomicTest phase */
ret = sde_rm_reserve(&sde_kms->rm, drm_enc, drm_enc->crtc->state,
conn->state, false);
@@ -1663,6 +1895,11 @@
}
}
+ /* update resources after seamless mode change */
+ if (msm_is_mode_seamless_dms(adj_mode))
+ sde_encoder_resource_control(&sde_enc->base,
+ SDE_ENC_RC_EVENT_POST_MODESET);
+
sde_enc->mode_set_complete = true;
}
@@ -1690,6 +1927,12 @@
return;
}
+ if (sde_enc->disp_info.intf_type == DRM_MODE_CONNECTOR_DisplayPort &&
+ sde_enc->cur_master->hw_mdptop &&
+ sde_enc->cur_master->hw_mdptop->ops.intf_audio_select)
+ sde_enc->cur_master->hw_mdptop->ops.intf_audio_select(
+ sde_enc->cur_master->hw_mdptop);
+
if (sde_enc->cur_master->hw_mdptop &&
sde_enc->cur_master->hw_mdptop->ops.reset_ubwc)
sde_enc->cur_master->hw_mdptop->ops.reset_ubwc(
@@ -1730,15 +1973,19 @@
{
struct sde_encoder_virt *sde_enc = NULL;
int i, ret = 0;
+ struct msm_compression_info *comp_info = NULL;
+ struct drm_display_mode *cur_mode = NULL;
if (!drm_enc) {
SDE_ERROR("invalid encoder\n");
return;
}
sde_enc = to_sde_encoder_virt(drm_enc);
+ comp_info = &sde_enc->mode_info.comp_info;
+ cur_mode = &sde_enc->base.crtc->state->adjusted_mode;
SDE_DEBUG_ENC(sde_enc, "\n");
- SDE_EVT32(DRMID(drm_enc));
+ SDE_EVT32(DRMID(drm_enc), cur_mode->hdisplay, cur_mode->vdisplay);
sde_enc->cur_master = NULL;
for (i = 0; i < sde_enc->num_phys_encs; i++) {
@@ -1766,11 +2013,33 @@
for (i = 0; i < sde_enc->num_phys_encs; i++) {
struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
- if (phys && (phys != sde_enc->cur_master) && phys->ops.enable)
- phys->ops.enable(phys);
+ if (!phys)
+ continue;
+
+ phys->comp_type = comp_info->comp_type;
+ if (phys != sde_enc->cur_master) {
+ /**
+ * on DMS request, the encoder will be enabled
+ * already. Invoke restore to reconfigure the
+ * new mode.
+ */
+ if (msm_is_mode_seamless_dms(cur_mode) &&
+ phys->ops.restore)
+ phys->ops.restore(phys);
+ else if (phys->ops.enable)
+ phys->ops.enable(phys);
+ }
+
+ if (sde_enc->misr_enable && (sde_enc->disp_info.capabilities &
+ MSM_DISPLAY_CAP_VID_MODE) && phys->ops.setup_misr)
+ phys->ops.setup_misr(phys, true,
+ sde_enc->misr_frame_count);
}
- if (sde_enc->cur_master->ops.enable)
+ if (msm_is_mode_seamless_dms(cur_mode) &&
+ sde_enc->cur_master->ops.restore)
+ sde_enc->cur_master->ops.restore(sde_enc->cur_master);
+ else if (sde_enc->cur_master->ops.enable)
sde_enc->cur_master->ops.enable(sde_enc->cur_master);
_sde_encoder_virt_enable_helper(drm_enc);
@@ -1802,18 +2071,18 @@
SDE_EVT32(DRMID(drm_enc));
+ /* wait for idle */
+ sde_encoder_wait_for_event(drm_enc, MSM_ENC_TX_COMPLETE);
+
+ sde_encoder_resource_control(drm_enc, SDE_ENC_RC_EVENT_PRE_STOP);
+
for (i = 0; i < sde_enc->num_phys_encs; i++) {
struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
- if (phys && phys->ops.disable && !phys->ops.is_master(phys)) {
+ if (phys && phys->ops.disable)
phys->ops.disable(phys);
- phys->connector = NULL;
- }
}
- if (sde_enc->cur_master && sde_enc->cur_master->ops.disable)
- sde_enc->cur_master->ops.disable(sde_enc->cur_master);
-
/* after phys waits for frame-done, should be no more frames pending */
if (atomic_xchg(&sde_enc->frame_done_timeout, 0)) {
SDE_ERROR("enc%d timeout pending\n", drm_enc->base.id);
@@ -2008,6 +2277,11 @@
return;
}
+ if (!phys->hw_pp) {
+ SDE_ERROR("invalid pingpong hw\n");
+ return;
+ }
+
ctl = phys->hw_ctl;
if (!ctl || !ctl->ops.trigger_flush) {
SDE_ERROR("missing trigger cb\n");
@@ -2049,7 +2323,12 @@
struct sde_hw_ctl *ctl;
if (!phys) {
- SDE_ERROR("invalid encoder\n");
+ SDE_ERROR("invalid argument(s)\n");
+ return;
+ }
+
+ if (!phys->hw_pp) {
+ SDE_ERROR("invalid pingpong hw\n");
return;
}
@@ -2096,7 +2375,7 @@
atomic_read(info->atomic_cnt) == 0, jiffies);
time = ktime_to_ms(ktime_get());
- SDE_EVT32(drm_id, hw_id, rc, time, expected_time,
+ SDE_EVT32_VERBOSE(drm_id, hw_id, rc, time, expected_time,
atomic_read(info->atomic_cnt));
/* If we timed out, counter is valid and time is less, wait again */
} while (atomic_read(info->atomic_cnt) && (rc == 0) &&
@@ -2311,7 +2590,7 @@
bool active;
phys = sde_enc->phys_encs[i];
- if (!phys || !phys->ops.update_split_role)
+ if (!phys || !phys->ops.update_split_role || !phys->hw_pp)
continue;
active = test_bit(i, ¶ms->affected_displays);
@@ -2670,6 +2949,7 @@
mutex_lock(&sde_enc->enc_lock);
sde_enc->misr_enable = enable;
+ sde_enc->misr_frame_count = frame_count;
for (i = 0; i < sde_enc->num_phys_encs; i++) {
struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
@@ -2966,8 +3246,6 @@
SDE_DEBUG("dsi_info->num_of_h_tiles %d\n", disp_info->num_of_h_tiles);
- phys_params.comp_type = disp_info->comp_info.comp_type;
-
if (disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE)
sde_enc->idle_pc_supported = sde_kms->catalog->has_idle_pc;
@@ -3172,6 +3450,13 @@
case MSM_ENC_TX_COMPLETE:
fn_wait = phys->ops.wait_for_tx_complete;
break;
+ case MSM_ENC_VBLANK:
+ fn_wait = phys->ops.wait_for_vblank;
+ break;
+ default:
+ SDE_ERROR_ENC(sde_enc, "unknown wait event %d\n",
+ event);
+ return -EINVAL;
};
if (phys && fn_wait) {
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
index c1a40f5..2098b9f 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
@@ -113,6 +113,7 @@
* current pending frames to hardware
* @wait_for_tx_complete: Wait for hardware to transfer the pixels
* to the panel
+ * @wait_for_vblank: Wait for VBLANK, for sub-driver internal use
* @prepare_for_kickoff: Do any work necessary prior to a kickoff
* For CMD encoder, may wait for previous tx done
* @handle_post_kickoff: Do any work necessary post-kickoff work
@@ -125,6 +126,8 @@
* @irq_control: Handler to enable/disable all the encoder IRQs
* @update_split_role: Update the split role of the phys enc
* @restore: Restore all the encoder configs.
+ * @is_autorefresh_enabled: provides the autorefresh current
+ * enable/disable state.
*/
struct sde_encoder_phys_ops {
@@ -150,6 +153,7 @@
int (*control_vblank_irq)(struct sde_encoder_phys *enc, bool enable);
int (*wait_for_commit_done)(struct sde_encoder_phys *phys_enc);
int (*wait_for_tx_complete)(struct sde_encoder_phys *phys_enc);
+ int (*wait_for_vblank)(struct sde_encoder_phys *phys_enc);
void (*prepare_for_kickoff)(struct sde_encoder_phys *phys_enc,
struct sde_encoder_kickoff_params *params);
void (*handle_post_kickoff)(struct sde_encoder_phys *phys_enc);
@@ -164,6 +168,7 @@
void (*update_split_role)(struct sde_encoder_phys *phys_enc,
enum sde_enc_split_role role);
void (*restore)(struct sde_encoder_phys *phys);
+ bool (*is_autorefresh_enabled)(struct sde_encoder_phys *phys);
};
/**
@@ -310,9 +315,12 @@
* @serialize_wait4pp: serialize wait4pp feature waits for pp_done interrupt
* after ctl_start instead of before next frame kickoff
* @pp_timeout_report_cnt: number of pingpong done irq timeout errors
+ * @autorefresh: autorefresh feature state
* @pending_rd_ptr_cnt: atomic counter to indicate if retire fence can be
* signaled at the next rd_ptr_irq
- * @autorefresh: autorefresh feature state
+ * @rd_ptr_timestamp: last rd_ptr_irq timestamp
+ * @pending_vblank_cnt: Atomic counter tracking pending wait for VBLANK
+ * @pending_vblank_wq: Wait queue for blocking until VBLANK received
*/
struct sde_encoder_phys_cmd {
struct sde_encoder_phys base;
@@ -321,6 +329,9 @@
int pp_timeout_report_cnt;
struct sde_encoder_phys_cmd_autorefresh autorefresh;
atomic_t pending_rd_ptr_cnt;
+ ktime_t rd_ptr_timestamp;
+ atomic_t pending_vblank_cnt;
+ wait_queue_head_t pending_vblank_wq;
};
/**
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
index 2a46636..70a25dd 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
@@ -47,6 +47,12 @@
#define SDE_ENC_WR_PTR_START_TIMEOUT_US 20000
+/*
+ * Threshold for signalling retire fences in cases where
+ * CTL_START_IRQ is received just after RD_PTR_IRQ
+ */
+#define SDE_ENC_CTL_START_THRESHOLD_US 500
+
static inline int _sde_encoder_phys_cmd_get_idle_timeout(
struct sde_encoder_phys_cmd *cmd_enc)
{
@@ -125,6 +131,9 @@
struct sde_hw_ctl *ctl;
u32 flush_mask = 0;
+ if (!phys_enc)
+ return;
+
ctl = phys_enc->hw_ctl;
if (!ctl || !ctl->ops.get_bitmask_intf ||
!ctl->ops.update_pending_flush)
@@ -145,6 +154,9 @@
struct sde_hw_ctl *ctl;
struct sde_hw_intf_cfg intf_cfg = { 0 };
+ if (!phys_enc)
+ return;
+
ctl = phys_enc->hw_ctl;
if (!ctl || !ctl->ops.setup_intf_cfg)
return;
@@ -212,7 +224,7 @@
{
struct sde_encoder_phys *phys_enc = arg;
struct sde_encoder_phys_cmd *cmd_enc;
- bool signal_fence = false;
+ u32 event = 0;
if (!phys_enc || !phys_enc->hw_pp)
return;
@@ -221,48 +233,31 @@
cmd_enc = to_sde_encoder_phys_cmd(phys_enc);
/**
- * signal only for master,
- * - when the ctl_start irq is done and incremented
- * the pending_rd_ptr_cnt.
- * - when ctl_start irq status bit is set. This handles the case
- * where ctl_start status bit is set in hardware, but the interrupt
- * is delayed due to some reason.
+ * signal only for master, when the ctl_start irq is
+ * done and incremented the pending_rd_ptr_cnt.
*/
- if (sde_encoder_phys_cmd_is_master(phys_enc) &&
- atomic_read(&phys_enc->pending_retire_fence_cnt)) {
+ if (sde_encoder_phys_cmd_is_master(phys_enc)
+ && atomic_add_unless(&cmd_enc->pending_rd_ptr_cnt, -1, 0)
+ && atomic_add_unless(
+ &phys_enc->pending_retire_fence_cnt, -1, 0)) {
- if (atomic_add_unless(
- &cmd_enc->pending_rd_ptr_cnt, -1, 0)) {
- signal_fence = true;
- } else {
- signal_fence =
- sde_core_irq_read_nolock(phys_enc->sde_kms,
- phys_enc->irq[INTR_IDX_CTL_START].irq_idx,
- false);
- if (signal_fence)
- SDE_EVT32_IRQ(DRMID(phys_enc->parent),
- phys_enc->hw_pp->idx - PINGPONG_0,
- atomic_read(
- &phys_enc->pending_retire_fence_cnt),
- SDE_EVTLOG_FUNC_CASE1);
- }
-
- if (signal_fence && phys_enc->parent_ops.handle_frame_done) {
- atomic_add_unless(
- &phys_enc->pending_retire_fence_cnt, -1, 0);
+ event = SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE;
+ if (phys_enc->parent_ops.handle_frame_done)
phys_enc->parent_ops.handle_frame_done(
- phys_enc->parent, phys_enc,
- SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE);
- }
+ phys_enc->parent, phys_enc, event);
}
SDE_EVT32_IRQ(DRMID(phys_enc->parent),
- phys_enc->hw_pp->idx - PINGPONG_0, signal_fence, 0xfff);
+ phys_enc->hw_pp->idx - PINGPONG_0, event, 0xfff);
if (phys_enc->parent_ops.handle_vblank_virt)
phys_enc->parent_ops.handle_vblank_virt(phys_enc->parent,
phys_enc);
+ cmd_enc->rd_ptr_timestamp = ktime_get();
+
+ atomic_add_unless(&cmd_enc->pending_vblank_cnt, -1, 0);
+ wake_up_all(&cmd_enc->pending_vblank_wq);
SDE_ATRACE_END("rd_ptr_irq");
}
@@ -271,6 +266,8 @@
struct sde_encoder_phys *phys_enc = arg;
struct sde_encoder_phys_cmd *cmd_enc;
struct sde_hw_ctl *ctl;
+ u32 event = 0;
+ s64 time_diff_us;
if (!phys_enc || !phys_enc->hw_ctl)
return;
@@ -279,16 +276,41 @@
cmd_enc = to_sde_encoder_phys_cmd(phys_enc);
ctl = phys_enc->hw_ctl;
- SDE_EVT32_IRQ(DRMID(phys_enc->parent), ctl->idx - CTL_0, 0xfff);
atomic_add_unless(&phys_enc->pending_ctlstart_cnt, -1, 0);
- /*
- * this is required for the fence signalling to be done in rd_ptr_irq
- * after ctrl_start_irq
- */
+ time_diff_us = ktime_us_delta(ktime_get(), cmd_enc->rd_ptr_timestamp);
+
+ /* handle retire fence based on only master */
if (sde_encoder_phys_cmd_is_master(phys_enc)
- && atomic_read(&phys_enc->pending_retire_fence_cnt))
- atomic_inc(&cmd_enc->pending_rd_ptr_cnt);
+ && atomic_read(&phys_enc->pending_retire_fence_cnt)) {
+ /**
+ * Handle rare cases where the ctl_start_irq is received
+ * after rd_ptr_irq. If it falls within a threshold, it is
+ * guaranteed the frame would be picked up in the current TE.
+ * Signal retire fence immediately in such case.
+ */
+ if ((time_diff_us <= SDE_ENC_CTL_START_THRESHOLD_US)
+ && atomic_add_unless(
+ &phys_enc->pending_retire_fence_cnt, -1, 0)) {
+
+ event = SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE;
+
+ if (phys_enc->parent_ops.handle_frame_done)
+ phys_enc->parent_ops.handle_frame_done(
+ phys_enc->parent, phys_enc, event);
+
+ /**
+ * In ideal cases, ctl_start_irq is received before the
+ * rd_ptr_irq, so set the atomic flag to indicate the event
+ * and rd_ptr_irq will handle signalling the retire fence
+ */
+ } else {
+ atomic_inc(&cmd_enc->pending_rd_ptr_cnt);
+ }
+ }
+
+ SDE_EVT32_IRQ(DRMID(phys_enc->parent), ctl->idx - CTL_0,
+ time_diff_us, event, 0xfff);
/* Signal any waiting ctl start interrupt */
wake_up_all(&phys_enc->pending_kickoff_wq);
@@ -394,6 +416,9 @@
| SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE;
bool do_log = false;
+ if (!phys_enc || !phys_enc->hw_pp || !phys_enc->hw_ctl)
+ return -EINVAL;
+
cmd_enc->pp_timeout_report_cnt++;
if (cmd_enc->pp_timeout_report_cnt == PP_TIMEOUT_MAX_TRIALS) {
frame_event |= SDE_ENCODER_FRAME_EVENT_PANEL_DEAD;
@@ -467,7 +492,8 @@
phys_enc->hw_pp->idx - PINGPONG_0,
info.rd_ptr_line_count,
info.wr_ptr_line_count);
- SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0,
+ SDE_EVT32_VERBOSE(DRMID(phys_enc->parent),
+ phys_enc->hw_pp->idx - PINGPONG_0,
info.wr_ptr_line_count);
ret = hw_pp->ops.poll_timeout_wr_ptr(hw_pp, timeout_us);
@@ -584,22 +610,29 @@
struct sde_encoder_phys_cmd *cmd_enc =
to_sde_encoder_phys_cmd(phys_enc);
int ret = 0;
+ int refcount;
- if (!phys_enc) {
+ if (!phys_enc || !phys_enc->hw_pp) {
SDE_ERROR("invalid encoder\n");
return -EINVAL;
}
+ refcount = atomic_read(&phys_enc->vblank_refcount);
+
/* Slave encoders don't report vblank */
if (!sde_encoder_phys_cmd_is_master(phys_enc))
goto end;
- SDE_DEBUG_CMDENC(cmd_enc, "[%pS] enable=%d/%d\n",
- __builtin_return_address(0),
- enable, atomic_read(&phys_enc->vblank_refcount));
+ /* protect against negative */
+ if (!enable && refcount == 0) {
+ ret = -EINVAL;
+ goto end;
+ }
+ SDE_DEBUG_CMDENC(cmd_enc, "[%pS] enable=%d/%d\n",
+ __builtin_return_address(0), enable, refcount);
SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0,
- enable, atomic_read(&phys_enc->vblank_refcount));
+ enable, refcount);
if (enable && atomic_inc_return(&phys_enc->vblank_refcount) == 1)
ret = sde_encoder_helper_register_irq(phys_enc, INTR_IDX_RDPTR);
@@ -608,10 +641,14 @@
INTR_IDX_RDPTR);
end:
- if (ret)
+ if (ret) {
SDE_ERROR_CMDENC(cmd_enc,
- "control vblank irq error %d, enable %d\n",
- ret, enable);
+ "control vblank irq error %d, enable %d, refcount %d\n",
+ ret, enable, refcount);
+ SDE_EVT32(DRMID(phys_enc->parent),
+ phys_enc->hw_pp->idx - PINGPONG_0,
+ enable, refcount, SDE_EVTLOG_ERROR);
+ }
return ret;
}
@@ -667,7 +704,7 @@
struct msm_drm_private *priv;
struct sde_kms *sde_kms;
- if (!phys_enc) {
+ if (!phys_enc || !phys_enc->hw_pp) {
SDE_ERROR("invalid encoder\n");
return;
}
@@ -825,7 +862,7 @@
phys_enc->enable_state = SDE_ENC_ENABLED;
}
-static bool _sde_encoder_phys_cmd_is_autorefresh_enabled(
+static bool sde_encoder_phys_cmd_is_autorefresh_enabled(
struct sde_encoder_phys *phys_enc)
{
struct sde_hw_pingpong *hw_pp;
@@ -864,33 +901,22 @@
{
struct sde_encoder_phys_cmd *cmd_enc =
to_sde_encoder_phys_cmd(phys_enc);
- int ret;
if (!phys_enc || !phys_enc->hw_pp) {
SDE_ERROR("invalid encoder\n");
return;
}
- SDE_DEBUG_CMDENC(cmd_enc, "pp %d\n", phys_enc->hw_pp->idx - PINGPONG_0);
+ SDE_DEBUG_CMDENC(cmd_enc, "pp %d state %d\n",
+ phys_enc->hw_pp->idx - PINGPONG_0,
+ phys_enc->enable_state);
+ SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0,
+ phys_enc->enable_state);
if (phys_enc->enable_state == SDE_ENC_DISABLED) {
SDE_ERROR_CMDENC(cmd_enc, "already disabled\n");
return;
}
- SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0);
-
- if (!_sde_encoder_phys_is_ppsplit_slave(phys_enc)) {
- ret = _sde_encoder_phys_cmd_wait_for_idle(phys_enc);
- if (ret) {
- atomic_set(&phys_enc->pending_kickoff_cnt, 0);
- SDE_ERROR_CMDENC(cmd_enc,
- "pp %d failed wait for idle, %d\n",
- phys_enc->hw_pp->idx - PINGPONG_0, ret);
- SDE_EVT32(DRMID(phys_enc->parent),
- phys_enc->hw_pp->idx - PINGPONG_0, ret);
- }
- }
-
if (phys_enc->hw_pp->ops.enable_tearcheck)
phys_enc->hw_pp->ops.enable_tearcheck(phys_enc->hw_pp, false);
phys_enc->enable_state = SDE_ENC_DISABLED;
@@ -974,8 +1000,8 @@
struct sde_encoder_wait_info wait_info;
int ret;
- if (!phys_enc) {
- SDE_ERROR("invalid encoder\n");
+ if (!phys_enc || !phys_enc->hw_ctl) {
+ SDE_ERROR("invalid argument(s)\n");
return -EINVAL;
}
@@ -1045,6 +1071,34 @@
return rc;
}
+static int sde_encoder_phys_cmd_wait_for_vblank(
+ struct sde_encoder_phys *phys_enc)
+{
+ int rc = 0;
+ struct sde_encoder_phys_cmd *cmd_enc;
+ struct sde_encoder_wait_info wait_info;
+
+ if (!phys_enc)
+ return -EINVAL;
+
+ cmd_enc = to_sde_encoder_phys_cmd(phys_enc);
+
+ /* only required for master controller */
+ if (!sde_encoder_phys_cmd_is_master(phys_enc))
+ return rc;
+
+ wait_info.wq = &cmd_enc->pending_vblank_wq;
+ wait_info.atomic_cnt = &cmd_enc->pending_vblank_cnt;
+ wait_info.timeout_ms = _sde_encoder_phys_cmd_get_idle_timeout(cmd_enc);
+
+ atomic_inc(&cmd_enc->pending_vblank_cnt);
+
+ rc = sde_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_RDPTR,
+ &wait_info);
+
+ return rc;
+}
+
static void sde_encoder_phys_cmd_update_split_role(
struct sde_encoder_phys *phys_enc,
enum sde_enc_split_role role)
@@ -1083,73 +1137,51 @@
{
struct sde_encoder_phys_cmd *cmd_enc =
to_sde_encoder_phys_cmd(phys_enc);
+ unsigned long lock_flags;
if (!phys_enc)
return;
- if (sde_encoder_phys_cmd_is_master(phys_enc)) {
- unsigned long lock_flags;
+ if (!sde_encoder_phys_cmd_is_master(phys_enc))
+ return;
+ SDE_EVT32(DRMID(phys_enc->parent), phys_enc->intf_idx - INTF_0,
+ cmd_enc->autorefresh.cfg.enable);
- SDE_EVT32(DRMID(phys_enc->parent), phys_enc->intf_idx - INTF_0,
- cmd_enc->autorefresh.cfg.enable);
+ if (!sde_encoder_phys_cmd_is_autorefresh_enabled(phys_enc))
+ return;
- if (!_sde_encoder_phys_cmd_is_autorefresh_enabled(phys_enc))
- return;
+ /**
+ * Autorefresh must be disabled carefully:
+ * - Autorefresh must be disabled between pp_done and te
+ * signal prior to sdm845 targets. All targets after sdm845
+ * supports autorefresh disable without turning off the
+ * hardware TE and pp_done wait.
+ *
+ * - Wait for TX to Complete
+ * Wait for PPDone confirms the last frame transfer is complete.
+ *
+ * - Leave Autorefresh Disabled
+ * - Assume disable of Autorefresh since it is now safe
+ * - Can now safely Disable Encoder, do debug printing, etc.
+ * without worrying that Autorefresh will kickoff
+ */
- /**
- * Autorefresh must be disabled carefully:
- * - Must disable while there is no ongoing transmission
- * - Receiving a TE will trigger the next Autorefresh TX
- * - Only safe to disable Autorefresh between PPDone and TE
- * - However, that is a small time window
- * - Disabling External TE gives large safe window, assuming
- * internally generated TE is set to a large counter value
- *
- * If Autorefresh is active:
- * 1. Disable external TE
- * - TE will run on an SDE counter set to large value (~200ms)
- *
- * 2. Check for ongoing TX
- * - If ongoing TX, set pending_kickoff_cnt if not set already
- * - We don't want to wait for a ppdone that will never
- * arrive, so verify ongoing TX
- *
- * 3. Wait for TX to Complete
- * - Wait for PPDone pending count to reach 0
- *
- * 4. Leave Autorefresh Disabled
- * - Assume disable of Autorefresh since it is now safe
- * - Can now safely Disable Encoder, do debug printing, etc.
- * without worrying that Autorefresh will kickoff
- */
+ spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
- spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
+ _sde_encoder_phys_cmd_config_autorefresh(phys_enc, 0);
- /* disable external TE to prevent next autorefresh */
- _sde_encoder_phys_cmd_connect_te(phys_enc, false);
+ /* check for outstanding TX */
+ if (_sde_encoder_phys_cmd_is_ongoing_pptx(phys_enc))
+ atomic_add_unless(&phys_enc->pending_kickoff_cnt, 1, 1);
+ spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags);
- /* verify that we disabled TE during outstanding TX */
- if (_sde_encoder_phys_cmd_is_ongoing_pptx(phys_enc))
- atomic_add_unless(&phys_enc->pending_kickoff_cnt, 1, 1);
+ /* wait for ppdone if necessary due to catching ongoing TX */
+ if (_sde_encoder_phys_cmd_wait_for_idle(phys_enc))
+ SDE_ERROR_CMDENC(cmd_enc, "pp:%d kickoff timed out\n",
+ phys_enc->hw_pp->idx - PINGPONG_0);
- spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags);
-
- /* wait for ppdone if necessary due to catching ongoing TX */
- if (_sde_encoder_phys_cmd_wait_for_idle(phys_enc))
- SDE_ERROR_CMDENC(cmd_enc,
- "pp:%d kickoff timed out\n",
- phys_enc->hw_pp->idx - PINGPONG_0);
-
- /*
- * not strictly necessary for kickoff, but simplifies disable
- * callflow since our disable is split across multiple phys_encs
- */
- _sde_encoder_phys_cmd_config_autorefresh(phys_enc, 0);
-
- SDE_DEBUG_CMDENC(cmd_enc, "disabled autorefresh & ext TE\n");
-
- }
+ SDE_DEBUG_CMDENC(cmd_enc, "disabled autorefresh\n");
}
static void sde_encoder_phys_cmd_handle_post_kickoff(
@@ -1200,13 +1232,16 @@
ops->wait_for_commit_done = sde_encoder_phys_cmd_wait_for_commit_done;
ops->prepare_for_kickoff = sde_encoder_phys_cmd_prepare_for_kickoff;
ops->wait_for_tx_complete = sde_encoder_phys_cmd_wait_for_tx_complete;
- ops->handle_post_kickoff = sde_encoder_phys_cmd_handle_post_kickoff;
+ ops->wait_for_vblank = sde_encoder_phys_cmd_wait_for_vblank;
ops->trigger_start = sde_encoder_phys_cmd_trigger_start;
ops->needs_single_flush = sde_encoder_phys_cmd_needs_single_flush;
ops->hw_reset = sde_encoder_helper_hw_reset;
ops->irq_control = sde_encoder_phys_cmd_irq_control;
ops->update_split_role = sde_encoder_phys_cmd_update_split_role;
ops->restore = sde_encoder_phys_cmd_enable_helper;
+ ops->is_autorefresh_enabled =
+ sde_encoder_phys_cmd_is_autorefresh_enabled;
+ ops->handle_post_kickoff = sde_encoder_phys_cmd_handle_post_kickoff;
}
struct sde_encoder_phys *sde_encoder_phys_cmd_init(
@@ -1290,7 +1325,9 @@
atomic_set(&phys_enc->pending_ctlstart_cnt, 0);
atomic_set(&phys_enc->pending_retire_fence_cnt, 0);
atomic_set(&cmd_enc->pending_rd_ptr_cnt, 0);
+ atomic_set(&cmd_enc->pending_vblank_cnt, 0);
init_waitqueue_head(&phys_enc->pending_kickoff_wq);
+ init_waitqueue_head(&cmd_enc->pending_vblank_wq);
atomic_set(&cmd_enc->autorefresh.kickoff_cnt, 0);
init_waitqueue_head(&cmd_enc->autorefresh.kickoff_wq);
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
index 933e4812..b7d6284 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
@@ -385,6 +385,9 @@
return;
hw_ctl = phys_enc->hw_ctl;
+ if (!hw_ctl)
+ return;
+
SDE_ATRACE_BEGIN("vblank_irq");
/* signal only for master, where there is a pending kickoff */
@@ -657,7 +660,7 @@
hw_res->intfs[vid_enc->hw_intf->idx - INTF_0] = INTF_MODE_VIDEO;
}
-static int sde_encoder_phys_vid_wait_for_vblank(
+static int _sde_encoder_phys_vid_wait_for_vblank(
struct sde_encoder_phys *phys_enc, bool notify)
{
struct sde_encoder_wait_info wait_info;
@@ -696,10 +699,10 @@
return ret;
}
-static int sde_encoder_phys_vid_wait_for_commit_done(
+static int sde_encoder_phys_vid_wait_for_vblank(
struct sde_encoder_phys *phys_enc)
{
- return sde_encoder_phys_vid_wait_for_vblank(phys_enc, true);
+ return _sde_encoder_phys_vid_wait_for_vblank(phys_enc, true);
}
static void sde_encoder_phys_vid_prepare_for_kickoff(
@@ -781,7 +784,7 @@
* scanout buffer) don't latch properly..
*/
if (sde_encoder_phys_vid_is_master(phys_enc)) {
- ret = sde_encoder_phys_vid_wait_for_vblank(phys_enc, false);
+ ret = _sde_encoder_phys_vid_wait_for_vblank(phys_enc, false);
if (ret) {
atomic_set(&phys_enc->pending_kickoff_cnt, 0);
SDE_ERROR_VIDENC(vid_enc,
@@ -866,7 +869,9 @@
ops->destroy = sde_encoder_phys_vid_destroy;
ops->get_hw_resources = sde_encoder_phys_vid_get_hw_resources;
ops->control_vblank_irq = sde_encoder_phys_vid_control_vblank_irq;
- ops->wait_for_commit_done = sde_encoder_phys_vid_wait_for_commit_done;
+ ops->wait_for_commit_done = sde_encoder_phys_vid_wait_for_vblank;
+ ops->wait_for_vblank = sde_encoder_phys_vid_wait_for_vblank;
+ ops->wait_for_tx_complete = sde_encoder_phys_vid_wait_for_vblank;
ops->prepare_for_kickoff = sde_encoder_phys_vid_prepare_for_kickoff;
ops->handle_post_kickoff = sde_encoder_phys_vid_handle_post_kickoff;
ops->needs_single_flush = sde_encoder_phys_vid_needs_single_flush;
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
index c95fb47..afef192 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
@@ -156,10 +156,18 @@
struct drm_framebuffer *fb, const struct sde_format *format,
struct sde_rect *wb_roi)
{
- struct sde_hw_cdm *hw_cdm = phys_enc->hw_cdm;
- struct sde_hw_cdm_cfg *cdm_cfg = &phys_enc->cdm_cfg;
+ struct sde_hw_cdm *hw_cdm;
+ struct sde_hw_cdm_cfg *cdm_cfg;
int ret;
+ if (!phys_enc || !format)
+ return;
+
+ cdm_cfg = &phys_enc->cdm_cfg;
+ hw_cdm = phys_enc->hw_cdm;
+ if (!hw_cdm)
+ return;
+
if (!SDE_FORMAT_IS_YUV(format)) {
SDE_DEBUG("[cdm_disable fmt:%x]\n",
format->base.pixel_format);
@@ -172,6 +180,9 @@
memset(cdm_cfg, 0, sizeof(struct sde_hw_cdm_cfg));
+ if (!wb_roi)
+ return;
+
cdm_cfg->output_width = wb_roi->w;
cdm_cfg->output_height = wb_roi->h;
cdm_cfg->output_fmt = format;
@@ -512,11 +523,18 @@
static void _sde_encoder_phys_wb_update_flush(struct sde_encoder_phys *phys_enc)
{
struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
- struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
- struct sde_hw_ctl *hw_ctl = phys_enc->hw_ctl;
- struct sde_hw_cdm *hw_cdm = phys_enc->hw_cdm;
+ struct sde_hw_wb *hw_wb;
+ struct sde_hw_ctl *hw_ctl;
+ struct sde_hw_cdm *hw_cdm;
u32 flush_mask = 0;
+ if (!phys_enc)
+ return;
+
+ hw_wb = wb_enc->hw_wb;
+ hw_ctl = phys_enc->hw_ctl;
+ hw_cdm = phys_enc->hw_cdm;
+
SDE_DEBUG("[wb:%d]\n", hw_wb->idx - WB_0);
if (!hw_ctl) {
@@ -918,10 +936,12 @@
* @pixel_format: DRM pixel format
* @width: Desired fb width
* @height: Desired fb height
+ * @pitch: Desired fb pitch
*/
static int _sde_encoder_phys_wb_init_internal_fb(
struct sde_encoder_phys_wb *wb_enc,
- uint32_t pixel_format, uint32_t width, uint32_t height)
+ uint32_t pixel_format, uint32_t width,
+ uint32_t height, uint32_t pitch)
{
struct drm_device *dev;
struct drm_framebuffer *fb;
@@ -951,9 +971,11 @@
mode_cmd.pixel_format = pixel_format;
mode_cmd.width = width;
mode_cmd.height = height;
+ mode_cmd.pitches[0] = pitch;
size = sde_format_get_framebuffer_size(pixel_format,
- mode_cmd.width, mode_cmd.height, 0, 0);
+ mode_cmd.width, mode_cmd.height,
+ mode_cmd.pitches, NULL, 0);
if (!size) {
SDE_DEBUG("not creating zero size buffer\n");
return -EINVAL;
@@ -1314,7 +1336,7 @@
/* create internal buffer for disable logic */
if (_sde_encoder_phys_wb_init_internal_fb(wb_enc,
- DRM_FORMAT_RGB888, 2, 1)) {
+ DRM_FORMAT_RGB888, 2, 1, 6)) {
SDE_ERROR("failed to init internal fb\n");
goto fail_wb_init;
}
diff --git a/drivers/gpu/drm/msm/sde/sde_formats.c b/drivers/gpu/drm/msm/sde/sde_formats.c
index 04c9e79..6880f7b 100644
--- a/drivers/gpu/drm/msm/sde/sde_formats.c
+++ b/drivers/gpu/drm/msm/sde/sde_formats.c
@@ -22,6 +22,11 @@
#define SDE_UBWC_META_BLOCK_SIZE 256
#define SDE_UBWC_PLANE_SIZE_ALIGNMENT 4096
+#define SDE_TILE_HEIGHT_DEFAULT 1
+#define SDE_TILE_HEIGHT_TILED 4
+#define SDE_TILE_HEIGHT_UBWC 4
+#define SDE_TILE_HEIGHT_NV12 8
+
#define SDE_MAX_IMG_WIDTH 0x3FFF
#define SDE_MAX_IMG_HEIGHT 0x3FFF
@@ -48,9 +53,30 @@
.bpp = bp, \
.fetch_mode = fm, \
.flag = {(flg)}, \
- .num_planes = np \
+ .num_planes = np, \
+ .tile_height = SDE_TILE_HEIGHT_DEFAULT \
}
+#define INTERLEAVED_RGB_FMT_TILED(fmt, a, r, g, b, e0, e1, e2, e3, uc, \
+alpha, bp, flg, fm, np, th) \
+{ \
+ .base.pixel_format = DRM_FORMAT_ ## fmt, \
+ .fetch_planes = SDE_PLANE_INTERLEAVED, \
+ .alpha_enable = alpha, \
+ .element = { (e0), (e1), (e2), (e3) }, \
+ .bits = { g, b, r, a }, \
+ .chroma_sample = SDE_CHROMA_RGB, \
+ .unpack_align_msb = 0, \
+ .unpack_tight = 1, \
+ .unpack_count = uc, \
+ .bpp = bp, \
+ .fetch_mode = fm, \
+ .flag = {(flg)}, \
+ .num_planes = np, \
+ .tile_height = th \
+}
+
+
#define INTERLEAVED_YUV_FMT(fmt, a, r, g, b, e0, e1, e2, e3, \
alpha, chroma, count, bp, flg, fm, np) \
{ \
@@ -66,7 +92,8 @@
.bpp = bp, \
.fetch_mode = fm, \
.flag = {(flg)}, \
- .num_planes = np \
+ .num_planes = np, \
+ .tile_height = SDE_TILE_HEIGHT_DEFAULT \
}
#define PSEUDO_YUV_FMT(fmt, a, r, g, b, e0, e1, chroma, flg, fm, np) \
@@ -83,7 +110,27 @@
.bpp = 2, \
.fetch_mode = fm, \
.flag = {(flg)}, \
- .num_planes = np \
+ .num_planes = np, \
+ .tile_height = SDE_TILE_HEIGHT_DEFAULT \
+}
+
+#define PSEUDO_YUV_FMT_TILED(fmt, a, r, g, b, e0, e1, chroma, \
+flg, fm, np, th) \
+{ \
+ .base.pixel_format = DRM_FORMAT_ ## fmt, \
+ .fetch_planes = SDE_PLANE_PSEUDO_PLANAR, \
+ .alpha_enable = false, \
+ .element = { (e0), (e1), 0, 0 }, \
+ .bits = { g, b, r, a }, \
+ .chroma_sample = chroma, \
+ .unpack_align_msb = 0, \
+ .unpack_tight = 1, \
+ .unpack_count = 2, \
+ .bpp = 2, \
+ .fetch_mode = fm, \
+ .flag = {(flg)}, \
+ .num_planes = np, \
+ .tile_height = th \
}
#define PSEUDO_YUV_FMT_LOOSE(fmt, a, r, g, b, e0, e1, chroma, flg, fm, np)\
@@ -100,9 +147,30 @@
.bpp = 2, \
.fetch_mode = fm, \
.flag = {(flg)}, \
- .num_planes = np \
+ .num_planes = np, \
+ .tile_height = SDE_TILE_HEIGHT_DEFAULT \
}
+#define PSEUDO_YUV_FMT_LOOSE_TILED(fmt, a, r, g, b, e0, e1, chroma, \
+flg, fm, np, th) \
+{ \
+ .base.pixel_format = DRM_FORMAT_ ## fmt, \
+ .fetch_planes = SDE_PLANE_PSEUDO_PLANAR, \
+ .alpha_enable = false, \
+ .element = { (e0), (e1), 0, 0 }, \
+ .bits = { g, b, r, a }, \
+ .chroma_sample = chroma, \
+ .unpack_align_msb = 1, \
+ .unpack_tight = 0, \
+ .unpack_count = 2, \
+ .bpp = 2, \
+ .fetch_mode = fm, \
+ .flag = {(flg)}, \
+ .num_planes = np, \
+ .tile_height = th \
+}
+
+
#define PLANAR_YUV_FMT(fmt, a, r, g, b, e0, e1, e2, alpha, chroma, bp, \
flg, fm, np) \
{ \
@@ -118,7 +186,8 @@
.bpp = bp, \
.fetch_mode = fm, \
.flag = {(flg)}, \
- .num_planes = np \
+ .num_planes = np, \
+ .tile_height = SDE_TILE_HEIGHT_DEFAULT \
}
/*
@@ -414,75 +483,99 @@
* These tables hold the A5x tile formats supported.
*/
static const struct sde_format sde_format_map_tile[] = {
- INTERLEAVED_RGB_FMT(ARGB8888,
+ INTERLEAVED_RGB_FMT_TILED(BGR565,
+ 0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT,
+ C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3,
+ false, 2, 0,
+ SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED),
+
+ INTERLEAVED_RGB_FMT_TILED(ARGB8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
true, 4, 0,
- SDE_FETCH_UBWC, 1),
+ SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED),
- INTERLEAVED_RGB_FMT(ABGR8888,
+ INTERLEAVED_RGB_FMT_TILED(ABGR8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
true, 4, 0,
- SDE_FETCH_UBWC, 1),
+ SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED),
- INTERLEAVED_RGB_FMT(RGBA8888,
+ INTERLEAVED_RGB_FMT_TILED(XBGR8888,
+ COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
+ C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+ false, 4, 0,
+ SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED),
+
+ INTERLEAVED_RGB_FMT_TILED(RGBA8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
true, 4, 0,
- SDE_FETCH_UBWC, 1),
+ SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED),
- INTERLEAVED_RGB_FMT(BGRA8888,
+ INTERLEAVED_RGB_FMT_TILED(BGRA8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
true, 4, 0,
- SDE_FETCH_UBWC, 1),
+ SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED),
- INTERLEAVED_RGB_FMT(BGRX8888,
+ INTERLEAVED_RGB_FMT_TILED(BGRX8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
false, 4, 0,
- SDE_FETCH_UBWC, 1),
+ SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED),
- INTERLEAVED_RGB_FMT(XRGB8888,
+ INTERLEAVED_RGB_FMT_TILED(XRGB8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
false, 4, 0,
- SDE_FETCH_UBWC, 1),
+ SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED),
- INTERLEAVED_RGB_FMT(RGBX8888,
+ INTERLEAVED_RGB_FMT_TILED(RGBX8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
false, 4, 0,
- SDE_FETCH_UBWC, 1),
+ SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED),
- PSEUDO_YUV_FMT(NV12,
+ INTERLEAVED_RGB_FMT_TILED(ABGR2101010,
+ COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
+ C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+ true, 4, SDE_FORMAT_FLAG_DX,
+ SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED),
+
+ INTERLEAVED_RGB_FMT_TILED(XBGR2101010,
+ COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
+ C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+ true, 4, SDE_FORMAT_FLAG_DX,
+ SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED),
+
+ PSEUDO_YUV_FMT_TILED(NV12,
0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C1_B_Cb, C2_R_Cr,
SDE_CHROMA_420, SDE_FORMAT_FLAG_YUV,
- SDE_FETCH_UBWC, 2),
+ SDE_FETCH_UBWC, 2, SDE_TILE_HEIGHT_NV12),
- PSEUDO_YUV_FMT(NV21,
+ PSEUDO_YUV_FMT_TILED(NV21,
0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C2_R_Cr, C1_B_Cb,
SDE_CHROMA_420, SDE_FORMAT_FLAG_YUV,
- SDE_FETCH_UBWC, 2),
+ SDE_FETCH_UBWC, 2, SDE_TILE_HEIGHT_NV12),
};
static const struct sde_format sde_format_map_p010_tile[] = {
- PSEUDO_YUV_FMT_LOOSE(NV12,
+ PSEUDO_YUV_FMT_LOOSE_TILED(NV12,
0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C1_B_Cb, C2_R_Cr,
SDE_CHROMA_420, (SDE_FORMAT_FLAG_YUV | SDE_FORMAT_FLAG_DX),
- SDE_FETCH_UBWC, 2),
+ SDE_FETCH_UBWC, 2, SDE_TILE_HEIGHT_NV12),
};
static const struct sde_format sde_format_map_tp10_tile[] = {
- PSEUDO_YUV_FMT(NV12,
+ PSEUDO_YUV_FMT_TILED(NV12,
0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C1_B_Cb, C2_R_Cr,
SDE_CHROMA_420, (SDE_FORMAT_FLAG_YUV | SDE_FORMAT_FLAG_DX),
- SDE_FETCH_UBWC, 2),
+ SDE_FETCH_UBWC, 2, SDE_TILE_HEIGHT_NV12),
};
/*
@@ -492,42 +585,42 @@
* the data will be passed by user-space.
*/
static const struct sde_format sde_format_map_ubwc[] = {
- INTERLEAVED_RGB_FMT(BGR565,
+ INTERLEAVED_RGB_FMT_TILED(BGR565,
0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT,
C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3,
false, 2, SDE_FORMAT_FLAG_COMPRESSED,
- SDE_FETCH_UBWC, 2),
+ SDE_FETCH_UBWC, 2, SDE_TILE_HEIGHT_UBWC),
- INTERLEAVED_RGB_FMT(ABGR8888,
+ INTERLEAVED_RGB_FMT_TILED(ABGR8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
true, 4, SDE_FORMAT_FLAG_COMPRESSED,
- SDE_FETCH_UBWC, 2),
+ SDE_FETCH_UBWC, 2, SDE_TILE_HEIGHT_UBWC),
- INTERLEAVED_RGB_FMT(XBGR8888,
+ INTERLEAVED_RGB_FMT_TILED(XBGR8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
false, 4, SDE_FORMAT_FLAG_COMPRESSED,
- SDE_FETCH_UBWC, 2),
+ SDE_FETCH_UBWC, 2, SDE_TILE_HEIGHT_UBWC),
- INTERLEAVED_RGB_FMT(ABGR2101010,
+ INTERLEAVED_RGB_FMT_TILED(ABGR2101010,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
true, 4, SDE_FORMAT_FLAG_DX | SDE_FORMAT_FLAG_COMPRESSED,
- SDE_FETCH_UBWC, 2),
+ SDE_FETCH_UBWC, 2, SDE_TILE_HEIGHT_UBWC),
- INTERLEAVED_RGB_FMT(XBGR2101010,
+ INTERLEAVED_RGB_FMT_TILED(XBGR2101010,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
true, 4, SDE_FORMAT_FLAG_DX | SDE_FORMAT_FLAG_COMPRESSED,
- SDE_FETCH_UBWC, 2),
+ SDE_FETCH_UBWC, 2, SDE_TILE_HEIGHT_UBWC),
- PSEUDO_YUV_FMT(NV12,
+ PSEUDO_YUV_FMT_TILED(NV12,
0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C1_B_Cb, C2_R_Cr,
SDE_CHROMA_420, SDE_FORMAT_FLAG_YUV |
SDE_FORMAT_FLAG_COMPRESSED,
- SDE_FETCH_UBWC, 4),
+ SDE_FETCH_UBWC, 4, SDE_TILE_HEIGHT_NV12),
};
static const struct sde_format sde_format_map_p010[] = {
@@ -539,21 +632,21 @@
};
static const struct sde_format sde_format_map_p010_ubwc[] = {
- PSEUDO_YUV_FMT_LOOSE(NV12,
+ PSEUDO_YUV_FMT_LOOSE_TILED(NV12,
0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C1_B_Cb, C2_R_Cr,
SDE_CHROMA_420, (SDE_FORMAT_FLAG_YUV | SDE_FORMAT_FLAG_DX |
SDE_FORMAT_FLAG_COMPRESSED),
- SDE_FETCH_UBWC, 4),
+ SDE_FETCH_UBWC, 4, SDE_TILE_HEIGHT_NV12),
};
static const struct sde_format sde_format_map_tp10_ubwc[] = {
- PSEUDO_YUV_FMT(NV12,
+ PSEUDO_YUV_FMT_TILED(NV12,
0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C1_B_Cb, C2_R_Cr,
SDE_CHROMA_420, (SDE_FORMAT_FLAG_YUV | SDE_FORMAT_FLAG_DX |
SDE_FORMAT_FLAG_COMPRESSED),
- SDE_FETCH_UBWC, 4),
+ SDE_FETCH_UBWC, 4, SDE_TILE_HEIGHT_NV12),
};
/* _sde_get_v_h_subsample_rate - Get subsample rates for all formats we support
@@ -701,7 +794,8 @@
const struct sde_format *fmt,
const uint32_t width,
const uint32_t height,
- struct sde_hw_fmt_layout *layout)
+ struct sde_hw_fmt_layout *layout,
+ const uint32_t *pitches)
{
int i;
@@ -751,6 +845,17 @@
}
}
+ /*
+ * linear format: allow user allocated pitches if they are greater than
+ * the requirement.
+ * ubwc format: pitch values are computed uniformly across
+ * all the components based on ubwc specifications.
+ */
+ for (i = 0; i < layout->num_planes && i < SDE_MAX_PLANES; ++i) {
+ if (pitches && layout->plane_pitch[i] < pitches[i])
+ layout->plane_pitch[i] = pitches[i];
+ }
+
for (i = 0; i < SDE_MAX_PLANES; i++)
layout->total_size += layout->plane_size[i];
@@ -761,7 +866,8 @@
const struct sde_format *fmt,
const uint32_t w,
const uint32_t h,
- struct sde_hw_fmt_layout *layout)
+ struct sde_hw_fmt_layout *layout,
+ const uint32_t *pitches)
{
if (!layout || !fmt) {
DRM_ERROR("invalid pointer\n");
@@ -776,7 +882,7 @@
if (SDE_FORMAT_IS_UBWC(fmt) || SDE_FORMAT_IS_TILE(fmt))
return _sde_format_get_plane_sizes_ubwc(fmt, w, h, layout);
- return _sde_format_get_plane_sizes_linear(fmt, w, h, layout);
+ return _sde_format_get_plane_sizes_linear(fmt, w, h, layout, pitches);
}
int sde_format_get_block_size(const struct sde_format *fmt,
@@ -801,6 +907,7 @@
const uint32_t format,
const uint32_t width,
const uint32_t height,
+ const uint32_t *pitches,
const uint64_t *modifiers,
const uint32_t modifiers_len)
{
@@ -811,7 +918,10 @@
if (!fmt)
return 0;
- if (sde_format_get_plane_sizes(fmt, width, height, &layout))
+ if (!pitches)
+ return -EINVAL;
+
+ if (sde_format_get_plane_sizes(fmt, width, height, &layout, pitches))
layout.total_size = 0;
return layout.total_size;
@@ -830,7 +940,10 @@
return -EINVAL;
}
- base_addr = msm_framebuffer_iova(fb, aspace, 0);
+ if (aspace)
+ base_addr = msm_framebuffer_iova(fb, aspace, 0);
+ else
+ base_addr = msm_framebuffer_phys(fb, 0);
if (!base_addr) {
DRM_ERROR("failed to retrieve base addr\n");
return -EFAULT;
@@ -917,7 +1030,7 @@
/* Can now check the pitches given vs pitches expected */
for (i = 0; i < layout->num_planes; ++i) {
- if (layout->plane_pitch[i] != fb->pitches[i]) {
+ if (layout->plane_pitch[i] > fb->pitches[i]) {
DRM_ERROR("plane %u expected pitch %u, fb %u\n",
i, layout->plane_pitch[i], fb->pitches[i]);
return -EINVAL;
@@ -926,7 +1039,11 @@
/* Populate addresses for simple formats here */
for (i = 0; i < layout->num_planes; ++i) {
- layout->plane_addr[i] = msm_framebuffer_iova(fb, aspace, i);
+ if (aspace)
+ layout->plane_addr[i] =
+ msm_framebuffer_iova(fb, aspace, i);
+ else
+ layout->plane_addr[i] = msm_framebuffer_phys(fb, i);
if (!layout->plane_addr[i]) {
DRM_ERROR("failed to retrieve base addr\n");
return -EFAULT;
@@ -959,7 +1076,7 @@
/* Populate the plane sizes etc via get_format */
ret = sde_format_get_plane_sizes(layout->format, fb->width, fb->height,
- layout);
+ layout, fb->pitches);
if (ret)
return ret;
@@ -1063,7 +1180,7 @@
num_base_fmt_planes = drm_format_num_planes(fmt->base.pixel_format);
ret = sde_format_get_plane_sizes(fmt, cmd->width, cmd->height,
- &layout);
+ &layout, cmd->pitches);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/msm/sde/sde_formats.h b/drivers/gpu/drm/msm/sde/sde_formats.h
index 2333a72..58065ab 100644
--- a/drivers/gpu/drm/msm/sde/sde_formats.h
+++ b/drivers/gpu/drm/msm/sde/sde_formats.h
@@ -64,6 +64,8 @@
* @w: width of the buffer
* @h: height of the buffer
* @layout: layout of the buffer
+ * @pitches: array of size [SDE_MAX_PLANES] to populate
+ * pitch for each plane
*
* Return: size of the buffer
*/
@@ -71,7 +73,8 @@
const struct sde_format *fmt,
const uint32_t w,
const uint32_t h,
- struct sde_hw_fmt_layout *layout);
+ struct sde_hw_fmt_layout *layout,
+ const uint32_t *pitches);
/**
* sde_format_get_block_size - get block size of given format when
@@ -137,6 +140,8 @@
* @format: DRM pixel format
* @width: pixel width
* @height: pixel height
+ * @pitches: array of size [SDE_MAX_PLANES] to populate
+ * pitch for each plane
* @modifiers: array to populate with drm modifiers, can be NULL
* @modifiers_len: length of modifers array
*
@@ -146,6 +151,7 @@
const uint32_t format,
const uint32_t width,
const uint32_t height,
+ const uint32_t *pitches,
const uint64_t *modifiers,
const uint32_t modifiers_len);
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
index b1772ed..0e1ab51 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
@@ -945,6 +945,7 @@
}
sblk->format_list = sde_cfg->vig_formats;
+ sblk->virt_format_list = sde_cfg->dma_formats;
}
static void _sde_sspp_setup_rgb(struct sde_mdss_cfg *sde_cfg,
@@ -997,6 +998,7 @@
}
sblk->format_list = sde_cfg->dma_formats;
+ sblk->virt_format_list = NULL;
}
static void _sde_sspp_setup_cursor(struct sde_mdss_cfg *sde_cfg,
@@ -1010,6 +1012,7 @@
sblk->maxupscale = SSPP_UNITY_SCALE;
sblk->maxdwnscale = SSPP_UNITY_SCALE;
sblk->format_list = sde_cfg->cursor_formats;
+ sblk->virt_format_list = NULL;
sspp->id = SSPP_CURSOR0 + *cursor_count;
snprintf(sspp->name, SDE_HW_BLK_NAME_LEN, "sspp_%u",
sspp->id - SSPP_VIG0);
@@ -1025,6 +1028,7 @@
sblk->maxupscale = SSPP_UNITY_SCALE;
sblk->maxdwnscale = SSPP_UNITY_SCALE;
sblk->format_list = sde_cfg->dma_formats;
+ sblk->virt_format_list = sde_cfg->dma_formats;
sspp->id = SSPP_DMA0 + *dma_count;
sspp->clk_ctrl = SDE_CLK_CTRL_DMA0 + *dma_count;
snprintf(sspp->name, SDE_HW_BLK_NAME_LEN, "sspp_%u",
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
index db5a6b4..fa10a88 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
@@ -395,6 +395,7 @@
* @danger_vblank: danger priority during vertical blanking
* @pixel_ram_size: size of latency hiding and de-tiling buffer in bytes
* @smart_dma_priority: hw priority of rect1 of multirect pipe
+ * @max_per_pipe_bw: maximum allowable bandwidth of this pipe in kBps
* @src_blk:
* @scaler_blk:
* @csc_blk:
@@ -403,7 +404,7 @@
* @pcc_blk:
* @igc_blk:
* @format_list: Pointer to list of supported formats
- * @max_per_pipe_bw: maximum allowable bandwidth of this pipe in kBps
+ * @virt_format_list: Pointer to list of supported formats for virtual planes
*/
struct sde_sspp_sub_blks {
u32 maxlinewidth;
@@ -425,6 +426,7 @@
struct sde_pp_blk igc_blk;
const struct sde_format_extended *format_list;
+ const struct sde_format_extended *virt_format_list;
};
/**
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_color_proc_common_v4.h b/drivers/gpu/drm/msm/sde/sde_hw_color_proc_common_v4.h
index 5cbfe8e..6896ba7 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_color_proc_common_v4.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_color_proc_common_v4.h
@@ -13,10 +13,10 @@
#define _SDE_HW_COLOR_PROC_COMMON_V4_H_
#define GAMUT_TABLE_SEL_OFF 0x4
-#define GAMUT_SCALEA_OFFSET_OFF 0x10
-#define GAMUT_SCALEB_OFFSET_OFF 0x50
-#define GAMUT_LOWER_COLOR_OFF 0xc
#define GAMUT_UPPER_COLOR_OFF 0x8
+#define GAMUT_LOWER_COLOR_OFF 0xc
+#define GAMUT_SCALEA_OFFSET_OFF 0x10
+#define GAMUT_SCALEB_OFFSET_OFF 0xe0
#define GAMUT_TABLE0_SEL BIT(12)
#define GAMUT_MAP_EN BIT(1)
#define GAMUT_EN BIT(0)
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_color_proc_v4.c b/drivers/gpu/drm/msm/sde/sde_hw_color_proc_v4.c
index 4da0456..dcfd81d 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_color_proc_v4.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_color_proc_v4.c
@@ -18,6 +18,7 @@
u32 *opcode)
{
u32 reg, tbl_len, tbl_off, scale_off, i, j;
+ u32 scale_tbl_len, scale_tbl_off;
u32 *scale_data;
if (!payload || !opcode || !hw) {
@@ -50,7 +51,7 @@
*opcode = gamut_mode_5 << 2;
*opcode |= GAMUT_MAP_EN;
tbl_len = GAMUT_3D_MODE5_TBL_SZ;
- tbl_off = 0;
+ tbl_off = GAMUT_MODE_5_OFF;
scale_off = GAMUT_SCALEB_OFFSET_OFF;
break;
default:
@@ -75,12 +76,18 @@
}
if ((*opcode & GAMUT_MAP_EN)) {
- scale_data = &payload->scale_off[0][0];
- tbl_off = base + scale_off;
- tbl_len = GAMUT_3D_SCALE_OFF_TBL_NUM * GAMUT_3D_SCALE_OFF_SZ;
- for (i = 0; i < tbl_len; i++)
- SDE_REG_WRITE(hw, tbl_off + (i * sizeof(u32)),
- scale_data[i]);
+ if (scale_off == GAMUT_SCALEA_OFFSET_OFF)
+ scale_tbl_len = GAMUT_3D_SCALE_OFF_SZ;
+ else
+ scale_tbl_len = GAMUT_3D_SCALEB_OFF_SZ;
+ for (i = 0; i < GAMUT_3D_SCALE_OFF_TBL_NUM; i++) {
+ scale_tbl_off = base + scale_off + i * scale_tbl_len;
+ scale_data = &payload->scale_off[i][0];
+ for (j = 0; j < scale_tbl_len; j++)
+ SDE_REG_WRITE(hw,
+ scale_tbl_off + (j * sizeof(u32)),
+ scale_data[j]);
+ }
}
SDE_REG_WRITE(hw, base, *opcode);
return 0;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c
index e88f40f..ff796f7 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c
@@ -69,9 +69,13 @@
static int sde_hw_pp_setup_te_config(struct sde_hw_pingpong *pp,
struct sde_hw_tear_check *te)
{
- struct sde_hw_blk_reg_map *c = &pp->hw;
+ struct sde_hw_blk_reg_map *c;
int cfg;
+ if (!pp || !te)
+ return -EINVAL;
+ c = &pp->hw;
+
cfg = BIT(19); /*VSYNC_COUNTER_EN */
if (te->hw_vsync_mode)
cfg |= BIT(20);
@@ -149,26 +153,38 @@
static void sde_hw_pp_dsc_enable(struct sde_hw_pingpong *pp)
{
- struct sde_hw_blk_reg_map *c = &pp->hw;
+ struct sde_hw_blk_reg_map *c;
+
+ if (!pp)
+ return;
+ c = &pp->hw;
SDE_REG_WRITE(c, PP_DSC_MODE, 1);
}
static void sde_hw_pp_dsc_disable(struct sde_hw_pingpong *pp)
{
- struct sde_hw_blk_reg_map *c = &pp->hw;
+ struct sde_hw_blk_reg_map *c;
+
+ if (!pp)
+ return;
+ c = &pp->hw;
SDE_REG_WRITE(c, PP_DSC_MODE, 0);
}
static int sde_hw_pp_setup_dsc(struct sde_hw_pingpong *pp)
{
- struct sde_hw_blk_reg_map *pp_c = &pp->hw;
+ struct sde_hw_blk_reg_map *c;
int data;
- data = SDE_REG_READ(pp_c, PP_DCE_DATA_OUT_SWAP);
+ if (!pp)
+ return -EINVAL;
+ c = &pp->hw;
+
+ data = SDE_REG_READ(c, PP_DCE_DATA_OUT_SWAP);
data |= BIT(18); /* endian flip */
- SDE_REG_WRITE(pp_c, PP_DCE_DATA_OUT_SWAP, data);
+ SDE_REG_WRITE(c, PP_DCE_DATA_OUT_SWAP, data);
return 0;
}
@@ -225,7 +241,11 @@
static int sde_hw_pp_enable_te(struct sde_hw_pingpong *pp, bool enable)
{
- struct sde_hw_blk_reg_map *c = &pp->hw;
+ struct sde_hw_blk_reg_map *c;
+
+ if (!pp)
+ return -EINVAL;
+ c = &pp->hw;
SDE_REG_WRITE(c, PP_TEAR_CHECK_EN, enable);
return 0;
@@ -257,9 +277,13 @@
static int sde_hw_pp_get_vsync_info(struct sde_hw_pingpong *pp,
struct sde_hw_pp_vsync_info *info)
{
- struct sde_hw_blk_reg_map *c = &pp->hw;
+ struct sde_hw_blk_reg_map *c;
u32 val;
+ if (!pp || !info)
+ return -EINVAL;
+ c = &pp->hw;
+
val = SDE_REG_READ(c, PP_VSYNC_INIT_VAL);
info->rd_ptr_init_val = val & 0xffff;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c
index 9a5035a..9199048 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c
@@ -582,6 +582,49 @@
return 0;
}
+static void sde_reg_dma_aspace_cb(void *cb_data, bool attach)
+{
+ struct sde_reg_dma_buffer *dma_buf = NULL;
+ struct msm_gem_address_space *aspace = NULL;
+ u32 iova_aligned, offset;
+ int rc;
+
+ if (!cb_data) {
+ DRM_ERROR("aspace cb called with invalid dma_buf\n");
+ return;
+ }
+
+ dma_buf = (struct sde_reg_dma_buffer *)cb_data;
+ aspace = dma_buf->aspace;
+
+ if (attach) {
+ rc = msm_gem_get_iova(dma_buf->buf, aspace, &dma_buf->iova);
+ if (rc) {
+ DRM_ERROR("failed to get the iova rc %d\n", rc);
+ return;
+ }
+
+ dma_buf->vaddr = msm_gem_get_vaddr(dma_buf->buf);
+ if (IS_ERR_OR_NULL(dma_buf->vaddr)) {
+ DRM_ERROR("failed to get va rc %d\n", rc);
+ return;
+ }
+
+ iova_aligned = (dma_buf->iova + GUARD_BYTES) & ALIGNED_OFFSET;
+ offset = iova_aligned - dma_buf->iova;
+ dma_buf->iova = dma_buf->iova + offset;
+ dma_buf->vaddr = (void *)(((u8 *)dma_buf->vaddr) + offset);
+ dma_buf->next_op_allowed = DECODE_SEL_OP;
+ } else {
+ /* invalidate the stored iova */
+ dma_buf->iova = 0;
+
+ /* return the virtual address mapping */
+ msm_gem_put_vaddr(dma_buf->buf);
+ msm_gem_vunmap(dma_buf->buf);
+ }
+}
+
static struct sde_reg_dma_buffer *alloc_reg_dma_buf_v1(u32 size)
{
struct sde_reg_dma_buffer *dma_buf = NULL;
@@ -616,10 +659,20 @@
goto free_gem;
}
+ /* register to aspace */
+ rc = msm_gem_address_space_register_cb(aspace,
+ sde_reg_dma_aspace_cb,
+ (void *)dma_buf);
+ if (rc) {
+ DRM_ERROR("failed to register callback %d", rc);
+ goto free_gem;
+ }
+
+ dma_buf->aspace = aspace;
rc = msm_gem_get_iova(dma_buf->buf, aspace, &dma_buf->iova);
if (rc) {
DRM_ERROR("failed to get the iova rc %d\n", rc);
- goto free_gem;
+ goto free_aspace_cb;
}
dma_buf->vaddr = msm_gem_get_vaddr(dma_buf->buf);
@@ -640,6 +693,9 @@
put_iova:
msm_gem_put_iova(dma_buf->buf, aspace);
+free_aspace_cb:
+ msm_gem_address_space_unregister_cb(aspace, sde_reg_dma_aspace_cb,
+ dma_buf);
free_gem:
msm_gem_free_object(dma_buf->buf);
fail:
@@ -656,6 +712,8 @@
if (dma_buf->buf) {
msm_gem_put_iova(dma_buf->buf, 0);
+ msm_gem_address_space_unregister_cb(dma_buf->aspace,
+ sde_reg_dma_aspace_cb, dma_buf);
mutex_lock(®_dma->drm_dev->struct_mutex);
msm_gem_free_object(dma_buf->buf);
mutex_unlock(®_dma->drm_dev->struct_mutex);
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c
index 70427ab..55cb260 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c
@@ -26,6 +26,7 @@
REG_DMA_HEADERS_BUFFER_SZ)
#define GAMUT_SCALE_OFF_LEN (GAMUT_3D_SCALE_OFF_SZ * \
GAMUT_3D_SCALE_OFF_TBL_NUM * sizeof(u32))
+#define GAMUT_SCALE_OFF_LEN_12 (GAMUT_3D_SCALEB_OFF_SZ * sizeof(u32))
#define GC_LUT_MEM_SIZE ((sizeof(struct drm_msm_pgc_lut)) + \
REG_DMA_HEADERS_BUFFER_SZ)
@@ -430,6 +431,8 @@
struct sde_reg_dma_kickoff_cfg kick_off;
struct sde_hw_cp_cfg *hw_cfg = cfg;
u32 op_mode, reg, tbl_len, tbl_off, scale_off, i;
+ u32 scale_tbl_len, scale_tbl_off;
+ u32 *scale_data;
struct sde_reg_dma_setup_ops_cfg dma_write_cfg;
struct sde_hw_reg_dma_ops *dma_ops;
int rc;
@@ -493,14 +496,24 @@
}
if (op_mode & GAMUT_MAP_EN) {
- REG_DMA_SETUP_OPS(dma_write_cfg,
- ctx->cap->sblk->gamut.base + scale_off,
- payload->scale_off[0], GAMUT_SCALE_OFF_LEN,
- REG_BLK_WRITE_SINGLE, 0, 0);
- rc = dma_ops->setup_payload(&dma_write_cfg);
- if (rc) {
- DRM_ERROR("write scale/off reg failed ret %d\n", rc);
- return;
+ if (scale_off == GAMUT_SCALEA_OFFSET_OFF)
+ scale_tbl_len = GAMUT_SCALE_OFF_LEN;
+ else
+ scale_tbl_len = GAMUT_SCALE_OFF_LEN_12;
+
+ for (i = 0; i < GAMUT_3D_SCALE_OFF_TBL_NUM; i++) {
+ scale_tbl_off = ctx->cap->sblk->gamut.base + scale_off +
+ (i * scale_tbl_len);
+ scale_data = &payload->scale_off[i][0];
+ REG_DMA_SETUP_OPS(dma_write_cfg, scale_tbl_off,
+ scale_data, scale_tbl_len,
+ REG_BLK_WRITE_SINGLE, 0, 0);
+ rc = dma_ops->setup_payload(&dma_write_cfg);
+ if (rc) {
+ DRM_ERROR("write scale/off reg failed ret %d\n",
+ rc);
+ return;
+ }
}
}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_rot.c b/drivers/gpu/drm/msm/sde/sde_hw_rot.c
index bbd5931..1a00517 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_rot.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_rot.c
@@ -62,6 +62,16 @@
}
/**
+ * _sde_hw_rot_reg_dump - perform register dump
+ * @ptr: private pointer to rotator platform device
+ * return: None
+ */
+static void _sde_hw_rot_reg_dump(void *ptr)
+{
+ sde_rotator_inline_reg_dump((struct platform_device *) ptr);
+}
+
+/**
* sde_hw_rot_start - start rotator before any commit
* @hw: Pointer to rotator hardware driver
* return: 0 if success; error code otherwise
@@ -78,6 +88,10 @@
pdev = hw->caps->pdev;
+ rc = sde_dbg_reg_register_cb(hw->name, _sde_hw_rot_reg_dump, pdev);
+ if (rc)
+ SDE_ERROR("failed to register debug dump %d\n", rc);
+
hw->rot_ctx = sde_rotator_inline_open(pdev);
if (IS_ERR_OR_NULL(hw->rot_ctx)) {
rc = PTR_ERR(hw->rot_ctx);
@@ -95,13 +109,16 @@
*/
static void sde_hw_rot_stop(struct sde_hw_rot *hw)
{
- if (!hw) {
+ if (!hw || !hw->caps || !hw->caps->pdev) {
SDE_ERROR("invalid parameter\n");
return;
}
sde_rotator_inline_release(hw->rot_ctx);
hw->rot_ctx = NULL;
+
+ sde_dbg_reg_unregister_cb(hw->name, _sde_hw_rot_reg_dump,
+ hw->caps->pdev);
}
/**
@@ -576,6 +593,7 @@
return -EINVAL;
}
+ rot_cmd.sequence_id = data->sequence_id;
rot_cmd.video_mode = data->video_mode;
rot_cmd.fps = data->fps;
@@ -667,10 +685,8 @@
hw_cmd);
rc = sde_rotator_inline_commit(hw->rot_ctx, &rot_cmd, cmd_type);
- if (rc) {
- SDE_ERROR("failed to commit inline rotation %d\n", rc);
+ if (rc)
return rc;
- }
/* return to caller */
data->priv_handle = rot_cmd.priv_handle;
@@ -899,6 +915,7 @@
c->idx = idx;
c->caps = cfg;
_setup_rot_ops(&c->ops, c->caps->features);
+ snprintf(c->name, ARRAY_SIZE(c->name), "sde_rot_%d", idx - ROT_0);
rc = sde_hw_blk_init(&c->base, SDE_HW_BLK_ROT, idx, &sde_hw_rot_ops);
if (rc) {
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_rot.h b/drivers/gpu/drm/msm/sde/sde_hw_rot.h
index e490052..1237858 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_rot.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_rot.h
@@ -18,6 +18,8 @@
#include "sde_hw_util.h"
#include "sde_hw_blk.h"
+#define SDE_HW_ROT_NAME_SIZE 80
+
struct sde_hw_rot;
/**
@@ -137,6 +139,7 @@
struct sde_hw_rot {
struct sde_hw_blk base;
struct sde_hw_blk_reg_map hw;
+ char name[SDE_HW_ROT_NAME_SIZE];
int idx;
const struct sde_rot_cfg *caps;
struct sde_hw_rot_ops ops;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
index 85af820..a4564c1 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
@@ -314,8 +314,8 @@
{
struct sde_hw_blk_reg_map *c;
u32 chroma_samp, unpack, src_format;
- u32 secure = 0, secure_bit_mask;
u32 opmode = 0;
+ u32 fast_clear = 0;
u32 op_mode_off, unpack_pat_off, format_off;
u32 idx;
@@ -326,12 +326,10 @@
op_mode_off = SSPP_SRC_OP_MODE;
unpack_pat_off = SSPP_SRC_UNPACK_PATTERN;
format_off = SSPP_SRC_FORMAT;
- secure_bit_mask = (rect_mode == SDE_SSPP_RECT_SOLO) ? 0xF : 0x5;
} else {
op_mode_off = SSPP_SRC_OP_MODE_REC1;
unpack_pat_off = SSPP_SRC_UNPACK_PATTERN_REC1;
format_off = SSPP_SRC_FORMAT_REC1;
- secure_bit_mask = 0xA;
}
c = &ctx->hw;
@@ -339,12 +337,6 @@
opmode &= ~(MDSS_MDP_OP_FLIP_LR | MDSS_MDP_OP_FLIP_UD |
MDSS_MDP_OP_BWC_EN | MDSS_MDP_OP_PE_OVERRIDE);
- secure = SDE_REG_READ(c, SSPP_SRC_ADDR_SW_STATUS + idx);
- if (flags & SDE_SSPP_SECURE_OVERLAY_SESSION)
- secure |= secure_bit_mask;
- else
- secure &= ~secure_bit_mask;
-
if (flags & SDE_SSPP_FLIP_LR)
opmode |= MDSS_MDP_OP_FLIP_LR;
if (flags & SDE_SSPP_FLIP_UD)
@@ -385,10 +377,12 @@
SDE_REG_WRITE(c, SSPP_FETCH_CONFIG,
SDE_FETCH_CONFIG_RESET_VALUE |
ctx->mdp->highest_bank_bit << 18);
- if (IS_UBWC_20_SUPPORTED(ctx->catalog->ubwc_version))
+ if (IS_UBWC_20_SUPPORTED(ctx->catalog->ubwc_version)) {
+ fast_clear = fmt->alpha_enable ? BIT(31) : 0;
SDE_REG_WRITE(c, SSPP_UBWC_STATIC_CTRL,
- BIT(31) | (ctx->mdp->ubwc_swizzle) |
+ fast_clear | (ctx->mdp->ubwc_swizzle) |
(ctx->mdp->highest_bank_bit << 4));
+ }
}
opmode |= MDSS_MDP_OP_PE_OVERRIDE;
@@ -412,12 +406,40 @@
SDE_REG_WRITE(c, format_off + idx, src_format);
SDE_REG_WRITE(c, unpack_pat_off + idx, unpack);
SDE_REG_WRITE(c, op_mode_off + idx, opmode);
- SDE_REG_WRITE(c, SSPP_SRC_ADDR_SW_STATUS + idx, secure);
/* clear previous UBWC error */
SDE_REG_WRITE(c, SSPP_UBWC_ERROR_STATUS + idx, BIT(31));
}
+static void sde_hw_sspp_setup_secure(struct sde_hw_pipe *ctx,
+ enum sde_sspp_multirect_index rect_mode,
+ bool enable)
+{
+ struct sde_hw_blk_reg_map *c;
+ u32 secure = 0, secure_bit_mask;
+ u32 idx;
+
+ if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx))
+ return;
+
+ if (rect_mode == SDE_SSPP_RECT_SOLO || rect_mode == SDE_SSPP_RECT_0)
+ secure_bit_mask = (rect_mode == SDE_SSPP_RECT_SOLO) ? 0xF :
+ 0x5;
+ else
+ secure_bit_mask = 0xA;
+
+ c = &ctx->hw;
+
+ secure = SDE_REG_READ(c, SSPP_SRC_ADDR_SW_STATUS + idx);
+ if (enable)
+ secure |= secure_bit_mask;
+ else
+ secure &= ~secure_bit_mask;
+
+ SDE_REG_WRITE(c, SSPP_SRC_ADDR_SW_STATUS + idx, secure);
+}
+
+
static void sde_hw_sspp_setup_pe_config(struct sde_hw_pipe *ctx,
struct sde_hw_pixel_ext *pe_ext)
{
@@ -768,6 +790,16 @@
SDE_REG_WRITE(&ctx->hw, QSEED3_OP_MODE + idx, op_mode);
}
+static u32 _sde_hw_sspp_get_scaler3_ver(struct sde_hw_pipe *ctx)
+{
+ u32 idx;
+
+ if (!ctx || _sspp_subblk_offset(ctx, SDE_SSPP_SCALER_QSEED3, &idx))
+ return 0;
+
+ return SDE_REG_READ(&ctx->hw, QSEED3_HW_VERSION + idx);
+}
+
/**
* sde_hw_sspp_setup_rects()
*/
@@ -1140,6 +1172,7 @@
c->ops.setup_sourceaddress = sde_hw_sspp_setup_sourceaddress;
c->ops.setup_solidfill = sde_hw_sspp_setup_solidfill;
c->ops.setup_pe = sde_hw_sspp_setup_pe_config;
+ c->ops.setup_secure_address = sde_hw_sspp_setup_secure;
}
if (test_bit(SDE_SSPP_EXCL_RECT, &features))
@@ -1167,8 +1200,10 @@
if (sde_hw_sspp_multirect_enabled(c->cap))
c->ops.setup_multirect = sde_hw_sspp_setup_multirect;
- if (test_bit(SDE_SSPP_SCALER_QSEED3, &features))
+ if (test_bit(SDE_SSPP_SCALER_QSEED3, &features)) {
c->ops.setup_scaler = _sde_hw_sspp_setup_scaler3;
+ c->ops.get_scaler_ver = _sde_hw_sspp_get_scaler3_ver;
+ }
if (test_bit(SDE_SSPP_HSIC, &features)) {
/* TODO: add version based assignment here as inline or macro */
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_sspp.h b/drivers/gpu/drm/msm/sde/sde_hw_sspp.h
index 8d14715..8700627 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_sspp.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_sspp.h
@@ -575,6 +575,12 @@
void *scaler_cfg);
/**
+ * get_scaler_ver - get scaler h/w version
+ * @ctx: Pointer to pipe context
+ */
+ u32 (*get_scaler_ver)(struct sde_hw_pipe *ctx);
+
+ /**
* setup_sys_cache - setup system cache configuration
* @ctx: Pointer to pipe context
* @cfg: Pointer to system cache configuration
@@ -607,6 +613,16 @@
*/
void (*setup_cdp)(struct sde_hw_pipe *ctx,
struct sde_hw_pipe_cdp_cfg *cfg);
+
+ /**
+ * setup_secure_address - setup secureity status of the source address
+ * @ctx: Pointer to pipe context
+ * @index: rectangle index in multirect
+ * @enable: enable content protected buffer state
+ */
+ void (*setup_secure_address)(struct sde_hw_pipe *ctx,
+ enum sde_sspp_multirect_index index,
+ bool enable);
};
/**
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_top.c b/drivers/gpu/drm/msm/sde/sde_hw_top.c
index 613ac53..ecb445d 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_top.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_top.c
@@ -348,6 +348,18 @@
SDE_REG_WRITE(&c, UBWC_STATIC, m->mdp[0].ubwc_static);
}
+static void sde_hw_intf_audio_select(struct sde_hw_mdp *mdp)
+{
+ struct sde_hw_blk_reg_map *c;
+
+ if (!mdp)
+ return;
+
+ c = &mdp->hw;
+
+ SDE_REG_WRITE(c, HDMI_DP_CORE_SELECT, 0x1);
+}
+
static void _setup_mdp_ops(struct sde_hw_mdp_ops *ops,
unsigned long cap)
{
@@ -360,6 +372,7 @@
ops->get_safe_status = sde_hw_get_safe_status;
ops->setup_dce = sde_hw_setup_dce;
ops->reset_ubwc = sde_hw_reset_ubwc;
+ ops->intf_audio_select = sde_hw_intf_audio_select;
}
static const struct sde_mdp_cfg *_top_offset(enum sde_mdp mdp,
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_top.h b/drivers/gpu/drm/msm/sde/sde_hw_top.h
index 86c4219..0ca5af9 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_top.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_top.h
@@ -182,6 +182,12 @@
* @m: pointer to mdss catalog data
*/
void (*reset_ubwc)(struct sde_hw_mdp *mdp, struct sde_mdss_cfg *m);
+
+ /**
+ * intf_audio_select - select the external interface for audio
+ * @mdp: mdp top context driver
+ */
+ void (*intf_audio_select)(struct sde_hw_mdp *mdp);
};
struct sde_hw_mdp {
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_vbif.c b/drivers/gpu/drm/msm/sde/sde_hw_vbif.c
index b5c273a..90a2ca9 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_vbif.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_vbif.c
@@ -22,7 +22,7 @@
#define VBIF_QOS_REMAP_01 0x0024
#define VBIF_QOS_REMAP_10 0x0028
#define VBIF_QOS_REMAP_11 0x002C
-#define VBIF_WRITE_GATHTER_EN 0x00AC
+#define VBIF_WRITE_GATHER_EN 0x00AC
#define VBIF_IN_RD_LIM_CONF0 0x00B0
#define VBIF_IN_RD_LIM_CONF1 0x00B4
#define VBIF_IN_RD_LIM_CONF2 0x00B8
@@ -33,11 +33,34 @@
#define VBIF_OUT_WR_LIM_CONF0 0x00D4
#define VBIF_OUT_AXI_AMEMTYPE_CONF0 0x0160
#define VBIF_OUT_AXI_AMEMTYPE_CONF1 0x0164
+#define VBIF_XIN_PND_ERR 0x0190
+#define VBIF_XIN_SRC_ERR 0x0194
+#define VBIF_XIN_CLR_ERR 0x019C
#define VBIF_XIN_HALT_CTRL0 0x0200
#define VBIF_XIN_HALT_CTRL1 0x0204
#define VBIF_XINL_QOS_RP_REMAP_000 0x0550
#define VBIF_XINL_QOS_LVL_REMAP_000 0x0590
+static void sde_hw_clear_errors(struct sde_hw_vbif *vbif,
+ u32 *pnd_errors, u32 *src_errors)
+{
+ struct sde_hw_blk_reg_map *c;
+ u32 pnd, src;
+
+ if (!vbif)
+ return;
+ c = &vbif->hw;
+ pnd = SDE_REG_READ(c, VBIF_XIN_PND_ERR);
+ src = SDE_REG_READ(c, VBIF_XIN_SRC_ERR);
+
+ if (pnd_errors)
+ *pnd_errors = pnd;
+ if (src_errors)
+ *src_errors = src;
+
+ SDE_REG_WRITE(c, VBIF_XIN_CLR_ERR, pnd | src);
+}
+
static void sde_hw_set_mem_type(struct sde_hw_vbif *vbif,
u32 xin_id, u32 value)
{
@@ -167,6 +190,21 @@
SDE_REG_WRITE(c, VBIF_XINL_QOS_LVL_REMAP_000 + reg_high, reg_val_lvl);
}
+static void sde_hw_set_write_gather_en(struct sde_hw_vbif *vbif, u32 xin_id)
+{
+ struct sde_hw_blk_reg_map *c;
+ u32 reg_val;
+
+ if (!vbif || xin_id >= MAX_XIN_COUNT)
+ return;
+
+ c = &vbif->hw;
+
+ reg_val = SDE_REG_READ(c, VBIF_WRITE_GATHER_EN);
+ reg_val |= BIT(xin_id);
+ SDE_REG_WRITE(c, VBIF_WRITE_GATHER_EN, reg_val);
+}
+
static void _setup_vbif_ops(struct sde_hw_vbif_ops *ops,
unsigned long cap)
{
@@ -177,6 +215,8 @@
if (test_bit(SDE_VBIF_QOS_REMAP, &cap))
ops->set_qos_remap = sde_hw_set_qos_remap;
ops->set_mem_type = sde_hw_set_mem_type;
+ ops->clear_errors = sde_hw_clear_errors;
+ ops->set_write_gather_en = sde_hw_set_write_gather_en;
}
static const struct sde_vbif_cfg *_top_offset(enum sde_vbif vbif,
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_vbif.h b/drivers/gpu/drm/msm/sde/sde_hw_vbif.h
index 80a9e5a..84f0e04 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_vbif.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_vbif.h
@@ -80,6 +80,25 @@
*/
void (*set_mem_type)(struct sde_hw_vbif *vbif,
u32 xin_id, u32 value);
+
+ /**
+ * clear_errors - clear any vbif errors
+ * This function clears any detected pending/source errors
+ * on the VBIF interface, and optionally returns the detected
+ * error mask(s).
+ * @vbif: vbif context driver
+ * @pnd_errors: pointer to pending error reporting variable
+ * @src_errors: pointer to source error reporting variable
+ */
+ void (*clear_errors)(struct sde_hw_vbif *vbif,
+ u32 *pnd_errors, u32 *src_errors);
+
+ /**
+ * set_write_gather_en - set write_gather enable
+ * @vbif: vbif context driver
+ * @xin_id: client interface identifier
+ */
+ void (*set_write_gather_en)(struct sde_hw_vbif *vbif, u32 xin_id);
};
struct sde_hw_vbif {
diff --git a/drivers/gpu/drm/msm/sde/sde_hwio.h b/drivers/gpu/drm/msm/sde/sde_hwio.h
index c95bace..cc020d9 100644
--- a/drivers/gpu/drm/msm/sde/sde_hwio.h
+++ b/drivers/gpu/drm/msm/sde/sde_hwio.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. 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 and
@@ -52,6 +52,7 @@
#define SPLIT_DISPLAY_LOWER_PIPE_CTRL 0x3F0
#define SPLIT_DISPLAY_TE_LINE_INTERVAL 0x3F4
#define INTF_SW_RESET_MASK 0x3FC
+#define HDMI_DP_CORE_SELECT 0x408
#define MDP_OUT_CTL_0 0x410
#define MDP_VSYNC_SEL 0x414
#define DCE_SEL 0x450
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index 42af245..4efddb4 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -348,66 +348,7 @@
sde_crtc_vblank(crtc, false);
}
-static void sde_kms_prepare_commit(struct msm_kms *kms,
- struct drm_atomic_state *state)
-{
- struct sde_kms *sde_kms;
- struct msm_drm_private *priv;
- struct drm_device *dev;
- struct drm_encoder *encoder;
-
- if (!kms)
- return;
- sde_kms = to_sde_kms(kms);
- dev = sde_kms->dev;
-
- if (!dev || !dev->dev_private)
- return;
- priv = dev->dev_private;
-
- sde_power_resource_enable(&priv->phandle, sde_kms->core_client, true);
-
- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
- if (encoder->crtc != NULL)
- sde_encoder_prepare_commit(encoder);
-
-}
-
-static void sde_kms_commit(struct msm_kms *kms,
- struct drm_atomic_state *old_state)
-{
- struct drm_crtc *crtc;
- struct drm_crtc_state *old_crtc_state;
- int i;
-
- for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) {
- if (crtc->state->active) {
- SDE_EVT32(DRMID(crtc));
- sde_crtc_commit_kickoff(crtc);
- }
- }
-}
-
-static void sde_kms_complete_commit(struct msm_kms *kms,
- struct drm_atomic_state *old_state)
-{
- struct sde_kms *sde_kms;
- struct msm_drm_private *priv;
-
- if (!kms || !old_state)
- return;
- sde_kms = to_sde_kms(kms);
-
- if (!sde_kms->dev || !sde_kms->dev->dev_private)
- return;
- priv = sde_kms->dev->dev_private;
-
- sde_power_resource_enable(&priv->phandle, sde_kms->core_client, false);
-
- SDE_EVT32(SDE_EVTLOG_FUNC_EXIT);
-}
-
-static void sde_kms_wait_for_tx_complete(struct msm_kms *kms,
+static void sde_kms_wait_for_frame_transfer_complete(struct msm_kms *kms,
struct drm_crtc *crtc)
{
struct drm_encoder *encoder;
@@ -450,6 +391,178 @@
}
}
+static int sde_kms_prepare_secure_transition(struct msm_kms *kms,
+ struct drm_atomic_state *state)
+{
+ struct drm_crtc *crtc;
+ struct drm_crtc_state *old_crtc_state;
+
+ struct drm_plane *plane;
+ struct drm_plane_state *plane_state;
+ struct sde_kms *sde_kms = to_sde_kms(kms);
+ struct drm_device *dev = sde_kms->dev;
+ int i, ops = 0, ret = 0;
+ bool old_valid_fb = false;
+
+ for_each_crtc_in_state(state, crtc, old_crtc_state, i) {
+ if (!crtc->state || !crtc->state->active)
+ continue;
+ /*
+ * It is safe to assume only one active crtc,
+ * and compatible translation modes on the
+ * planes staged on this crtc.
+ * otherwise validation would have failed.
+ * For this CRTC,
+ */
+
+ /*
+ * 1. Check if old state on the CRTC has planes
+ * staged with valid fbs
+ */
+ for_each_plane_in_state(state, plane, plane_state, i) {
+ if (!plane_state->crtc)
+ continue;
+ if (plane_state->fb) {
+ old_valid_fb = true;
+ break;
+ }
+ }
+
+ /*
+ * 2.Get the operations needed to be performed before
+ * secure transition can be initiated.
+ */
+ ops = sde_crtc_get_secure_transition_ops(crtc,
+ old_crtc_state,
+ old_valid_fb);
+ if (ops < 0) {
+ SDE_ERROR("invalid secure operations %x\n", ops);
+ return ops;
+ }
+
+ if (!ops)
+ goto no_ops;
+
+ SDE_DEBUG("%d:secure operations(%x) started on state:%pK\n",
+ crtc->base.id,
+ ops,
+ crtc->state);
+
+ /* 3. Perform operations needed for secure transition */
+ if (ops & SDE_KMS_OPS_WAIT_FOR_TX_DONE) {
+ SDE_DEBUG("wait_for_transfer_done\n");
+ sde_kms_wait_for_frame_transfer_complete(kms, crtc);
+ }
+ if (ops & SDE_KMS_OPS_CLEANUP_PLANE_FB) {
+ SDE_DEBUG("cleanup planes\n");
+ drm_atomic_helper_cleanup_planes(dev, state);
+ }
+ if (ops & SDE_KMS_OPS_CRTC_SECURE_STATE_CHANGE) {
+ SDE_DEBUG("secure ctrl\n");
+ sde_crtc_secure_ctrl(crtc, false);
+ }
+ if (ops & SDE_KMS_OPS_PREPARE_PLANE_FB) {
+ SDE_DEBUG("prepare planes %d",
+ crtc->state->plane_mask);
+ drm_atomic_crtc_for_each_plane(plane,
+ crtc) {
+ const struct drm_plane_helper_funcs *funcs;
+
+ plane_state = plane->state;
+ funcs = plane->helper_private;
+
+ SDE_DEBUG("psde:%d FB[%u]\n",
+ plane->base.id,
+ plane->fb->base.id);
+ if (!funcs)
+ continue;
+
+ if (funcs->prepare_fb(plane, plane_state)) {
+ ret = funcs->prepare_fb(plane,
+ plane_state);
+ if (ret)
+ return ret;
+ }
+ }
+ }
+ SDE_DEBUG("secure operations completed\n");
+ }
+
+no_ops:
+ return 0;
+}
+
+static void sde_kms_prepare_commit(struct msm_kms *kms,
+ struct drm_atomic_state *state)
+{
+ struct sde_kms *sde_kms;
+ struct msm_drm_private *priv;
+ struct drm_device *dev;
+ struct drm_encoder *encoder;
+
+ if (!kms)
+ return;
+ sde_kms = to_sde_kms(kms);
+ dev = sde_kms->dev;
+
+ if (!dev || !dev->dev_private)
+ return;
+ priv = dev->dev_private;
+
+ sde_power_resource_enable(&priv->phandle, sde_kms->core_client, true);
+
+ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
+ if (encoder->crtc != NULL)
+ sde_encoder_prepare_commit(encoder);
+
+ /*
+ * NOTE: for secure use cases we want to apply the new HW
+ * configuration only after completing preparation for secure
+ * transitions prepare below if any transtions is required.
+ */
+ sde_kms_prepare_secure_transition(kms, state);
+}
+
+static void sde_kms_commit(struct msm_kms *kms,
+ struct drm_atomic_state *old_state)
+{
+ struct drm_crtc *crtc;
+ struct drm_crtc_state *old_crtc_state;
+ int i;
+
+ for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) {
+ if (crtc->state->active) {
+ SDE_EVT32(DRMID(crtc));
+ sde_crtc_commit_kickoff(crtc);
+ }
+ }
+}
+
+static void sde_kms_complete_commit(struct msm_kms *kms,
+ struct drm_atomic_state *old_state)
+{
+ struct sde_kms *sde_kms;
+ struct msm_drm_private *priv;
+ struct drm_crtc *crtc;
+ struct drm_crtc_state *old_crtc_state;
+ int i;
+
+ if (!kms || !old_state)
+ return;
+ sde_kms = to_sde_kms(kms);
+
+ if (!sde_kms->dev || !sde_kms->dev->dev_private)
+ return;
+ priv = sde_kms->dev->dev_private;
+
+ for_each_crtc_in_state(old_state, crtc, old_crtc_state, i)
+ sde_crtc_complete_commit(crtc, old_crtc_state);
+
+ sde_power_resource_enable(&priv->phandle, sde_kms->core_client, false);
+
+ SDE_EVT32_VERBOSE(SDE_EVTLOG_FUNC_EXIT);
+}
+
static void sde_kms_wait_for_commit_done(struct msm_kms *kms,
struct drm_crtc *crtc)
{
@@ -635,14 +748,16 @@
.post_init = dsi_conn_post_init,
.detect = dsi_conn_detect,
.get_modes = dsi_connector_get_modes,
+ .put_modes = dsi_connector_put_modes,
.mode_valid = dsi_conn_mode_valid,
.get_info = dsi_display_get_info,
.set_backlight = dsi_display_set_backlight,
.soft_reset = dsi_display_soft_reset,
.pre_kickoff = dsi_conn_pre_kickoff,
.clk_ctrl = dsi_display_clk_ctrl,
- .get_topology = dsi_conn_get_topology,
- .get_dst_format = dsi_display_get_dst_format
+ .set_power = dsi_display_set_power,
+ .get_mode_info = dsi_conn_get_mode_info,
+ .get_dst_format = dsi_display_get_dst_format,
};
static const struct sde_connector_ops wb_ops = {
.post_init = sde_wb_connector_post_init,
@@ -651,7 +766,7 @@
.set_property = sde_wb_connector_set_property,
.get_info = sde_wb_get_info,
.soft_reset = NULL,
- .get_topology = sde_wb_get_topology,
+ .get_mode_info = sde_wb_get_mode_info,
.get_dst_format = NULL
};
static const struct sde_connector_ops dp_ops = {
@@ -660,7 +775,7 @@
.get_modes = dp_connector_get_modes,
.mode_valid = dp_connector_mode_valid,
.get_info = dp_connector_get_info,
- .get_topology = dp_connector_get_topology,
+ .get_mode_info = dp_connector_get_mode_info,
};
struct msm_display_info info;
struct drm_encoder *encoder;
@@ -1135,7 +1250,7 @@
}
ret = sde_format_get_plane_sizes(fbo->fmt, fbo->width, fbo->height,
- &fbo->layout);
+ &fbo->layout, fbo->layout.plane_pitch);
if (ret) {
SDE_ERROR("failed to get plane sizes\n");
goto done;
@@ -1341,6 +1456,70 @@
sde_reg_dma_deinit();
}
+int sde_kms_mmu_detach(struct sde_kms *sde_kms, bool secure_only)
+{
+ int i;
+
+ if (!sde_kms)
+ return -EINVAL;
+
+ for (i = 0; i < MSM_SMMU_DOMAIN_MAX; i++) {
+ struct msm_mmu *mmu;
+ struct msm_gem_address_space *aspace = sde_kms->aspace[i];
+
+ if (!aspace)
+ continue;
+
+ mmu = sde_kms->aspace[i]->mmu;
+
+ if (secure_only &&
+ !aspace->mmu->funcs->is_domain_secure(mmu))
+ continue;
+
+ /* cleanup aspace before detaching */
+ msm_gem_aspace_domain_attach_detach_update(aspace, true);
+
+ SDE_DEBUG("Detaching domain:%d\n", i);
+ aspace->mmu->funcs->detach(mmu, (const char **)iommu_ports,
+ ARRAY_SIZE(iommu_ports));
+
+ aspace->domain_attached = false;
+ }
+
+ return 0;
+}
+
+int sde_kms_mmu_attach(struct sde_kms *sde_kms, bool secure_only)
+{
+ int i;
+
+ if (!sde_kms)
+ return -EINVAL;
+
+ for (i = 0; i < MSM_SMMU_DOMAIN_MAX; i++) {
+ struct msm_mmu *mmu;
+ struct msm_gem_address_space *aspace = sde_kms->aspace[i];
+
+ if (!aspace)
+ continue;
+
+ mmu = sde_kms->aspace[i]->mmu;
+
+ if (secure_only &&
+ !aspace->mmu->funcs->is_domain_secure(mmu))
+ continue;
+
+ SDE_DEBUG("Attaching domain:%d\n", i);
+ aspace->mmu->funcs->attach(mmu, (const char **)iommu_ports,
+ ARRAY_SIZE(iommu_ports));
+
+ msm_gem_aspace_domain_attach_detach_update(aspace, false);
+ aspace->domain_attached = true;
+ }
+
+ return 0;
+}
+
static void sde_kms_destroy(struct msm_kms *kms)
{
struct sde_kms *sde_kms;
@@ -1373,6 +1552,108 @@
sde_crtc_cancel_pending_flip(priv->crtcs[i], file);
}
+static int sde_kms_check_secure_transition(struct msm_kms *kms,
+ struct drm_atomic_state *state)
+{
+ struct sde_kms *sde_kms;
+ struct drm_device *dev;
+ struct drm_crtc *crtc;
+ struct drm_crtc *sec_crtc = NULL, *temp_crtc = NULL;
+ struct drm_crtc_state *crtc_state;
+ int secure_crtc_cnt = 0, active_crtc_cnt = 0;
+ int secure_global_crtc_cnt = 0, active_mode_crtc_cnt = 0;
+ int i;
+
+ if (!kms || !state) {
+ return -EINVAL;
+ SDE_ERROR("invalid arguments\n");
+ }
+
+ /* iterate state object for active and secure crtc */
+ for_each_crtc_in_state(state, crtc, crtc_state, i) {
+ if (!crtc_state->active)
+ continue;
+ active_crtc_cnt++;
+ if (sde_crtc_get_secure_level(crtc, crtc_state) ==
+ SDE_DRM_SEC_ONLY) {
+ sec_crtc = crtc;
+ secure_crtc_cnt++;
+ }
+ }
+
+ /* bail out from further validation if no secure ctrc */
+ if (!secure_crtc_cnt)
+ return 0;
+
+ if ((secure_crtc_cnt > MAX_ALLOWED_SECURE_CLIENT_CNT) ||
+ (secure_crtc_cnt &&
+ (active_crtc_cnt > MAX_ALLOWED_CRTC_CNT_DURING_SECURE))) {
+ SDE_ERROR("Secure check failed active:%d, secure:%d\n",
+ active_crtc_cnt, secure_crtc_cnt);
+ return -EPERM;
+ }
+
+ sde_kms = to_sde_kms(kms);
+ dev = sde_kms->dev;
+ /* iterate global list for active and secure crtc */
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+
+ if (!crtc->state->active)
+ continue;
+
+ active_mode_crtc_cnt++;
+
+ if (sde_crtc_get_secure_level(crtc, crtc->state) ==
+ SDE_DRM_SEC_ONLY) {
+ secure_global_crtc_cnt++;
+ temp_crtc = crtc;
+ }
+ }
+
+ /**
+ * if more than one crtc is active fail
+ * check if the previous and current commit secure
+ * are same
+ */
+ if (secure_crtc_cnt && ((active_mode_crtc_cnt > 1) ||
+ (secure_global_crtc_cnt && (temp_crtc != sec_crtc))))
+ SDE_ERROR("Secure check failed active:%d crtc_id:%d\n",
+ active_mode_crtc_cnt, temp_crtc->base.id);
+
+ return 0;
+}
+
+static int sde_kms_atomic_check(struct msm_kms *kms,
+ struct drm_atomic_state *state)
+{
+ struct sde_kms *sde_kms;
+ struct drm_device *dev;
+ int ret;
+
+ if (!kms || !state)
+ return -EINVAL;
+
+ sde_kms = to_sde_kms(kms);
+ dev = sde_kms->dev;
+
+ if (sde_kms_is_suspend_blocked(dev)) {
+ SDE_DEBUG("suspended, skip atomic_check\n");
+ return -EBUSY;
+ }
+
+ ret = drm_atomic_helper_check(dev, state);
+ if (ret)
+ return ret;
+ /*
+ * Check if any secure transition(moving CRTC between secure and
+ * non-secure state and vice-versa) is allowed or not. when moving
+ * to secure state, planes with fb_mode set to dir_translated only can
+ * be staged on the CRTC, and only one CRTC can be active during
+ * Secure state
+ */
+ return sde_kms_check_secure_transition(kms, state);
+}
+
static struct msm_gem_address_space*
_sde_kms_get_address_space(struct msm_kms *kms,
unsigned int domain)
@@ -1393,7 +1674,173 @@
if (domain >= MSM_SMMU_DOMAIN_MAX)
return NULL;
- return sde_kms->aspace[domain];
+ return (sde_kms->aspace[domain] &&
+ sde_kms->aspace[domain]->domain_attached) ?
+ sde_kms->aspace[domain] : NULL;
+}
+
+static void _sde_kms_post_open(struct msm_kms *kms, struct drm_file *file)
+{
+ struct drm_device *dev = NULL;
+ struct sde_kms *sde_kms = NULL;
+
+ if (!kms) {
+ SDE_ERROR("invalid kms\n");
+ return;
+ }
+
+ sde_kms = to_sde_kms(kms);
+ dev = sde_kms->dev;
+
+ if (!dev) {
+ SDE_ERROR("invalid device\n");
+ return;
+ }
+
+ if (dev->mode_config.funcs->output_poll_changed)
+ dev->mode_config.funcs->output_poll_changed(dev);
+}
+
+static int sde_kms_pm_suspend(struct device *dev)
+{
+ struct drm_device *ddev;
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_connector *conn;
+ struct drm_atomic_state *state;
+ struct sde_kms *sde_kms;
+ int ret = 0;
+
+ if (!dev)
+ return -EINVAL;
+
+ ddev = dev_get_drvdata(dev);
+ if (!ddev || !ddev_to_msm_kms(ddev))
+ return -EINVAL;
+
+ sde_kms = to_sde_kms(ddev_to_msm_kms(ddev));
+ SDE_EVT32(0);
+
+ /* disable hot-plug polling */
+ drm_kms_helper_poll_disable(ddev);
+
+ /* acquire modeset lock(s) */
+ drm_modeset_acquire_init(&ctx, 0);
+
+retry:
+ ret = drm_modeset_lock_all_ctx(ddev, &ctx);
+ if (ret)
+ goto unlock;
+
+ /* save current state for resume */
+ if (sde_kms->suspend_state)
+ drm_atomic_state_free(sde_kms->suspend_state);
+ sde_kms->suspend_state = drm_atomic_helper_duplicate_state(ddev, &ctx);
+ if (IS_ERR_OR_NULL(sde_kms->suspend_state)) {
+ DRM_ERROR("failed to back up suspend state\n");
+ sde_kms->suspend_state = NULL;
+ goto unlock;
+ }
+
+ /* create atomic state to disable all CRTCs */
+ state = drm_atomic_state_alloc(ddev);
+ if (IS_ERR_OR_NULL(state)) {
+ DRM_ERROR("failed to allocate crtc disable state\n");
+ goto unlock;
+ }
+
+ state->acquire_ctx = &ctx;
+ drm_for_each_connector(conn, ddev) {
+ struct drm_crtc_state *crtc_state;
+ uint64_t lp;
+
+ if (!conn->state || !conn->state->crtc ||
+ conn->dpms != DRM_MODE_DPMS_ON)
+ continue;
+
+ lp = sde_connector_get_lp(conn);
+ if (lp == SDE_MODE_DPMS_LP1) {
+ /* transition LP1->LP2 on pm suspend */
+ ret = sde_connector_set_property_for_commit(conn, state,
+ CONNECTOR_PROP_LP, SDE_MODE_DPMS_LP2);
+ if (ret) {
+ DRM_ERROR("failed to set lp2 for conn %d\n",
+ conn->base.id);
+ drm_atomic_state_free(state);
+ goto unlock;
+ }
+ } else if (lp != SDE_MODE_DPMS_LP2) {
+ /* force CRTC to be inactive */
+ crtc_state = drm_atomic_get_crtc_state(state,
+ conn->state->crtc);
+ if (IS_ERR_OR_NULL(crtc_state)) {
+ DRM_ERROR("failed to get crtc %d state\n",
+ conn->state->crtc->base.id);
+ drm_atomic_state_free(state);
+ goto unlock;
+ }
+ crtc_state->active = false;
+ }
+ }
+
+ /* commit the "disable all" state */
+ ret = drm_atomic_commit(state);
+ if (ret < 0) {
+ DRM_ERROR("failed to disable crtcs, %d\n", ret);
+ drm_atomic_state_free(state);
+ } else {
+ sde_kms->suspend_block = true;
+ }
+
+unlock:
+ if (ret == -EDEADLK) {
+ drm_modeset_backoff(&ctx);
+ goto retry;
+ }
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+
+ return 0;
+}
+
+static int sde_kms_pm_resume(struct device *dev)
+{
+ struct drm_device *ddev;
+ struct sde_kms *sde_kms;
+ int ret;
+
+ if (!dev)
+ return -EINVAL;
+
+ ddev = dev_get_drvdata(dev);
+ if (!ddev || !ddev_to_msm_kms(ddev))
+ return -EINVAL;
+
+ sde_kms = to_sde_kms(ddev_to_msm_kms(ddev));
+
+ SDE_EVT32(sde_kms->suspend_state != NULL);
+
+ drm_mode_config_reset(ddev);
+
+ drm_modeset_lock_all(ddev);
+
+ sde_kms->suspend_block = false;
+
+ if (sde_kms->suspend_state) {
+ sde_kms->suspend_state->acquire_ctx =
+ ddev->mode_config.acquire_ctx;
+ ret = drm_atomic_commit(sde_kms->suspend_state);
+ if (ret < 0) {
+ DRM_ERROR("failed to restore state, %d\n", ret);
+ drm_atomic_state_free(sde_kms->suspend_state);
+ }
+ sde_kms->suspend_state = NULL;
+ }
+ drm_modeset_unlock_all(ddev);
+
+ /* enable hot-plug polling */
+ drm_kms_helper_poll_enable(ddev);
+
+ return 0;
}
static const struct msm_kms_funcs kms_funcs = {
@@ -1409,15 +1856,19 @@
.commit = sde_kms_commit,
.complete_commit = sde_kms_complete_commit,
.wait_for_crtc_commit_done = sde_kms_wait_for_commit_done,
- .wait_for_tx_complete = sde_kms_wait_for_tx_complete,
+ .wait_for_tx_complete = sde_kms_wait_for_frame_transfer_complete,
.enable_vblank = sde_kms_enable_vblank,
.disable_vblank = sde_kms_disable_vblank,
.check_modified_format = sde_format_check_modified_format,
+ .atomic_check = sde_kms_atomic_check,
.get_format = sde_get_msm_format,
.round_pixclk = sde_kms_round_pixclk,
+ .pm_suspend = sde_kms_pm_suspend,
+ .pm_resume = sde_kms_pm_resume,
.destroy = sde_kms_destroy,
.register_events = _sde_kms_register_events,
.get_address_space = _sde_kms_get_address_space,
+ .postopen = _sde_kms_post_open,
};
/* the caller api needs to turn on clock before calling it */
@@ -1463,7 +1914,7 @@
continue;
}
- aspace = msm_gem_smmu_address_space_create(sde_kms->dev->dev,
+ aspace = msm_gem_smmu_address_space_create(sde_kms->dev,
mmu, "sde");
if (IS_ERR(aspace)) {
ret = PTR_ERR(aspace);
@@ -1480,7 +1931,7 @@
msm_gem_address_space_destroy(aspace);
goto fail;
}
-
+ aspace->domain_attached = true;
}
return 0;
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.h b/drivers/gpu/drm/msm/sde/sde_kms.h
index d818fdf..0ddfb30 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.h
+++ b/drivers/gpu/drm/msm/sde/sde_kms.h
@@ -89,10 +89,24 @@
#define SDE_NAME_SIZE 12
-
/* timeout in frames waiting for frame done */
#define SDE_FRAME_DONE_TIMEOUT 60
+/* max active secure client counts allowed */
+#define MAX_ALLOWED_SECURE_CLIENT_CNT 1
+
+/* max active crtc when secure client is active */
+#define MAX_ALLOWED_CRTC_CNT_DURING_SECURE 1
+
+/* max virtual encoders per secure crtc */
+#define MAX_ALLOWED_ENCODER_CNT_PER_SECURE_CRTC 1
+
+/* defines the operations required for secure state transition */
+#define SDE_KMS_OPS_CRTC_SECURE_STATE_CHANGE BIT(0)
+#define SDE_KMS_OPS_WAIT_FOR_TX_DONE BIT(1)
+#define SDE_KMS_OPS_CLEANUP_PLANE_FB BIT(2)
+#define SDE_KMS_OPS_PREPARE_PLANE_FB BIT(3)
+
/*
* struct sde_irq_callback - IRQ callback handlers
* @list: list to callback
@@ -184,6 +198,10 @@
struct sde_core_perf perf;
+ /* saved atomic state during system suspend */
+ struct drm_atomic_state *suspend_state;
+ bool suspend_block;
+
struct sde_rm rm;
bool rm_init;
@@ -214,6 +232,33 @@
bool sde_is_custom_client(void);
/**
+ * sde_kms_is_suspend_state - whether or not the system is pm suspended
+ * @dev: Pointer to drm device
+ * Return: Suspend status
+ */
+static inline bool sde_kms_is_suspend_state(struct drm_device *dev)
+{
+ if (!ddev_to_msm_kms(dev))
+ return false;
+
+ return to_sde_kms(ddev_to_msm_kms(dev))->suspend_state != NULL;
+}
+
+/**
+ * sde_kms_is_suspend_blocked - whether or not commits are blocked due to pm
+ * suspend status
+ * @dev: Pointer to drm device
+ * Return: True if commits should be rejected due to pm suspend
+ */
+static inline bool sde_kms_is_suspend_blocked(struct drm_device *dev)
+{
+ if (!sde_kms_is_suspend_state(dev))
+ return false;
+
+ return to_sde_kms(ddev_to_msm_kms(dev))->suspend_block;
+}
+
+/**
* Debugfs functions - extra helper functions for debugfs support
*
* Main debugfs documentation is located at,
@@ -500,4 +545,13 @@
*/
void sde_kms_fbo_unreference(struct sde_kms_fbo *fbo);
+/**
+ * smmu attach/detach functions
+ * @sde_kms: poiner to sde_kms structure
+ * @secure_only: if true only secure contexts are attached/detached, else
+ * all contexts are attached/detached/
+ */
+int sde_kms_mmu_attach(struct sde_kms *sde_kms, bool secure_only);
+int sde_kms_mmu_detach(struct sde_kms *sde_kms, bool secure_only);
+
#endif /* __sde_kms_H__ */
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index 665315d..40dad76 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -73,8 +73,6 @@
R_MAX
};
-#define TX_MODE_BUFFER_LINE_THRES 2
-
#define SDE_QSEED3_DEFAULT_PRELOAD_H 0x4
#define SDE_QSEED3_DEFAULT_PRELOAD_V 0x3
@@ -258,16 +256,16 @@
((src_width + 32) * fmt->bpp);
} else {
/* non NV12 */
- total_fl = (fixed_buff_size / 2 - hflip_bytes) /
- ((src_width + 32) * fmt->bpp * 2);
+ total_fl = (fixed_buff_size / 2 - hflip_bytes) * 2 /
+ ((src_width + 32) * fmt->bpp);
}
} else {
if (pstate->multirect_mode == SDE_SSPP_MULTIRECT_PARALLEL) {
- total_fl = (fixed_buff_size / 2 - hflip_bytes) /
- ((src_width + 32) * fmt->bpp * 2);
+ total_fl = (fixed_buff_size / 2 - hflip_bytes) * 2 /
+ ((src_width + 32) * fmt->bpp);
} else {
- total_fl = (fixed_buff_size - hflip_bytes) /
- ((src_width + 32) * fmt->bpp * 2);
+ total_fl = (fixed_buff_size - hflip_bytes) * 2 /
+ ((src_width + 32) * fmt->bpp);
}
}
@@ -675,7 +673,7 @@
SDE_DEBUG("plane%d size:%llu time:%llu\n",
plane->base.id, cfg.size, cfg.time);
- SDE_EVT32(DRMID(plane), cfg.size, cfg.time);
+ SDE_EVT32_VERBOSE(DRMID(plane), cfg.size, cfg.time);
psde->pipe_hw->ops.setup_ts_prefill(psde->pipe_hw, &cfg,
pstate->multirect_index);
}
@@ -925,7 +923,7 @@
else if (ret)
SDE_ERROR_PLANE(psde, "failed to get format layout, %d\n", ret);
else if (psde->pipe_hw->ops.setup_sourceaddress) {
- SDE_EVT32(psde->pipe_hw->idx,
+ SDE_EVT32_VERBOSE(psde->pipe_hw->idx,
pipe_cfg->layout.width,
pipe_cfg->layout.height,
pipe_cfg->layout.plane_addr[0],
@@ -957,15 +955,15 @@
cfg->dir_lut = msm_property_get_blob(
&psde->property_info,
- pstate->property_blobs, &cfg->dir_len,
+ &pstate->property_state, &cfg->dir_len,
PLANE_PROP_SCALER_LUT_ED);
cfg->cir_lut = msm_property_get_blob(
&psde->property_info,
- pstate->property_blobs, &cfg->cir_len,
+ &pstate->property_state, &cfg->cir_len,
PLANE_PROP_SCALER_LUT_CIR);
cfg->sep_lut = msm_property_get_blob(
&psde->property_info,
- pstate->property_blobs, &cfg->sep_len,
+ &pstate->property_state, &cfg->sep_len,
PLANE_PROP_SCALER_LUT_SEP);
if (!cfg->dir_lut || !cfg->cir_lut || !cfg->sep_lut)
ret = -ENODATA;
@@ -1276,7 +1274,7 @@
if (psde->pipe_hw->ops.setup_pa_memcolor) {
/* Skin memory color setup */
memcol = msm_property_get_blob(&psde->property_info,
- pstate->property_blobs,
+ &pstate->property_state,
&memcol_sz,
PLANE_PROP_SKIN_COLOR);
psde->pipe_hw->ops.setup_pa_memcolor(psde->pipe_hw,
@@ -1284,7 +1282,7 @@
/* Sky memory color setup */
memcol = msm_property_get_blob(&psde->property_info,
- pstate->property_blobs,
+ &pstate->property_state,
&memcol_sz,
PLANE_PROP_SKY_COLOR);
psde->pipe_hw->ops.setup_pa_memcolor(psde->pipe_hw,
@@ -1292,7 +1290,7 @@
/* Foliage memory color setup */
memcol = msm_property_get_blob(&psde->property_info,
- pstate->property_blobs,
+ &pstate->property_state,
&memcol_sz,
PLANE_PROP_FOLIAGE_COLOR);
psde->pipe_hw->ops.setup_pa_memcolor(psde->pipe_hw,
@@ -1575,14 +1573,13 @@
* enumerating over all planes attached to the same rotator
* @plane: Pointer to drm plane
* @state: Pointer to drm state to be updated
- * return: none
+ * return: 0 if success; error code otherwise
*/
-static void sde_plane_rot_calc_cfg(struct drm_plane *plane,
+static int sde_plane_rot_calc_cfg(struct drm_plane *plane,
struct drm_plane_state *state)
{
struct sde_plane_state *pstate;
struct sde_plane_rot_state *rstate;
- struct sde_hw_blk *hw_blk;
struct drm_crtc_state *cstate;
struct drm_rect *in_rot, *out_rot;
struct drm_plane *attached_plane;
@@ -1593,24 +1590,19 @@
if (!plane || !state || !state->state) {
SDE_ERROR("invalid parameters\n");
- return;
+ return -EINVAL;
}
cstate = _sde_plane_get_crtc_state(state);
if (IS_ERR_OR_NULL(cstate)) {
ret = PTR_ERR(cstate);
SDE_ERROR("invalid crtc state %d\n", ret);
- return;
+ return ret;
}
pstate = to_sde_plane_state(state);
rstate = &pstate->rot;
- if (!rstate->rot_hw) {
- SDE_ERROR("invalid rotator hw\n");
- return;
- }
-
in_rot = &rstate->in_rot_rect;
in_rot->x1 = state->src_x;
in_rot->y1 = state->src_y;
@@ -1636,8 +1628,6 @@
rstate->out_src_rect = rstate->out_rot_rect;
- hw_blk = &rstate->rot_hw->base;
-
/* enumerating over all planes attached to the same rotator */
drm_atomic_crtc_state_for_each_plane(attached_plane, cstate) {
struct drm_plane_state *attached_state;
@@ -1710,6 +1700,71 @@
attached_out_rect.y2 = dst_y + dst_h;
}
+ /* check source split left/right mismatch */
+ if (attached_out_rect.y1 != rstate->out_src_rect.y1 ||
+ attached_out_rect.y2 != rstate->out_src_rect.y2) {
+ SDE_ERROR(
+ "plane%d.%u src:%dx%d+%d+%d rot:0x%llx fb:%d plane%d.%u src:%dx%d+%d+%d rot:0x%llx fb:%d mismatch\n",
+ plane->base.id,
+ rstate->sequence_id,
+ state->src_w >> 16,
+ state->src_h >> 16,
+ state->src_x >> 16,
+ state->src_y >> 16,
+ sde_plane_get_property(pstate,
+ PLANE_PROP_ROTATION),
+ state->fb ?
+ state->fb->base.id :
+ -1,
+ attached_plane->base.id,
+ attached_rstate->sequence_id,
+ attached_state->src_w >> 16,
+ attached_state->src_h >> 16,
+ attached_state->src_x >> 16,
+ attached_state->src_y >> 16,
+ sde_plane_get_property(attached_pstate,
+ PLANE_PROP_ROTATION),
+ attached_state->fb ?
+ attached_state->fb->base.id :
+ -1);
+ SDE_ERROR(
+ "plane%d.%u sspp:%dx%d+%d+%d plane%d.%u sspp:%dx%d+%d+%d\n",
+ plane->base.id,
+ rstate->sequence_id,
+ (rstate->out_src_rect.x2 -
+ rstate->out_src_rect.x1) >> 16,
+ (rstate->out_src_rect.y2 -
+ rstate->out_src_rect.y1) >> 16,
+ rstate->out_src_rect.x1 >> 16,
+ rstate->out_src_rect.y1 >> 16,
+ attached_plane->base.id,
+ attached_rstate->sequence_id,
+ (attached_out_rect.x2 -
+ attached_out_rect.x1) >> 16,
+ (attached_out_rect.y2 -
+ attached_out_rect.y1) >> 16,
+ attached_out_rect.x1 >> 16,
+ attached_out_rect.y1 >> 16);
+ SDE_EVT32(DRMID(plane),
+ rstate->sequence_id,
+ rstate->out_src_rect.x1 >> 16,
+ rstate->out_src_rect.y1 >> 16,
+ (rstate->out_src_rect.x2 -
+ rstate->out_src_rect.x1) >> 16,
+ (rstate->out_src_rect.y2 -
+ rstate->out_src_rect.y1) >> 16,
+ attached_plane->base.id,
+ attached_rstate->sequence_id,
+ attached_out_rect.x1 >> 16,
+ attached_out_rect.y1 >> 16,
+ (attached_out_rect.x2 -
+ attached_out_rect.x1) >> 16,
+ (attached_out_rect.y2 -
+ attached_out_rect.y1) >> 16,
+ SDE_EVTLOG_ERROR);
+ return -EINVAL;
+ }
+
/* find relative sspp position */
if (attached_out_rect.x1 < rstate->out_src_rect.x1)
xpos++;
@@ -1753,7 +1808,7 @@
drm_rect_height(&rstate->out_rot_rect) >> 16,
rstate->out_rot_rect.x1 >> 16,
rstate->out_rot_rect.y1 >> 16);
- SDE_EVT32_VERBOSE(DRMID(plane), rstate->sequence_id,
+ SDE_EVT32(DRMID(plane), rstate->sequence_id,
rstate->out_xpos, rstate->nplane,
in_rot->x1 >> 16, in_rot->y1 >> 16,
drm_rect_width(in_rot) >> 16,
@@ -1762,6 +1817,8 @@
rstate->out_rot_rect.y1 >> 16,
drm_rect_width(&rstate->out_rot_rect) >> 16,
drm_rect_height(&rstate->out_rot_rect) >> 16);
+
+ return 0;
}
/**
@@ -1840,8 +1897,8 @@
rot_cmd->src_rect_y = rstate->in_rot_rect.y1 >> 16;
rot_cmd->src_rect_w = drm_rect_width(&rstate->in_rot_rect) >> 16;
rot_cmd->src_rect_h = drm_rect_height(&rstate->in_rot_rect) >> 16;
- rot_cmd->dst_rect_x = rstate->out_rot_rect.x1 >> 16;
- rot_cmd->dst_rect_y = rstate->out_rot_rect.y1 >> 16;
+ rot_cmd->dst_rect_x = 0;
+ rot_cmd->dst_rect_y = 0;
rot_cmd->dst_rect_w = drm_rect_width(&rstate->out_rot_rect) >> 16;
rot_cmd->dst_rect_h = drm_rect_height(&rstate->out_rot_rect) >> 16;
@@ -1886,10 +1943,8 @@
}
ret = rstate->rot_hw->ops.commit(rstate->rot_hw, rot_cmd, hw_cmd);
- if (ret) {
- SDE_ERROR("failed to commit rotator %d\n", ret);
+ if (ret)
return ret;
- }
rstate->out_rotation = rstate->in_rotation;
rstate->out_fb_flags = rot_cmd->dst_modifier ?
@@ -2017,7 +2072,9 @@
}
/* need to re-calc based on all newly validated plane states */
- sde_plane_rot_calc_cfg(plane, new_state);
+ ret = sde_plane_rot_calc_cfg(plane, new_state);
+ if (ret)
+ return ret;
/* check if stream buffer is already attached to rotator */
if (sde_plane_enabled(new_state) && !new_rstate->out_fb)
@@ -2222,6 +2279,8 @@
SDE_ERROR("plane%d.%d no available rotator, fb %d\n",
plane->base.id, rstate->sequence_id,
state->fb ? state->fb->base.id : -1);
+ SDE_EVT32(DRMID(plane), rstate->sequence_id,
+ SDE_EVTLOG_ERROR);
return -EINVAL;
}
@@ -2249,13 +2308,20 @@
SDE_DEBUG("plane%d.%d use rotator, fb %d\n",
plane->base.id, rstate->sequence_id, fb_id);
- sde_plane_rot_calc_cfg(plane, state);
+ ret = sde_plane_rot_calc_cfg(plane, state);
+ if (ret)
+ return ret;
ret = sde_plane_rot_submit_command(plane, state,
SDE_HW_ROT_CMD_VALIDATE);
if (ret)
return ret;
+ if (rstate->nplane != old_rstate->nplane ||
+ rstate->out_xpos != old_rstate->out_xpos)
+ pstate->dirty |= SDE_PLANE_DIRTY_FORMAT |
+ SDE_PLANE_DIRTY_RECTS;
+
/* check if stream buffer is already attached to rotator */
_sde_plane_rot_get_fb(plane, cstate, rstate);
@@ -2353,16 +2419,18 @@
sde_plane_rot_submit_command(plane, state, SDE_HW_ROT_CMD_COMMIT);
}
-/**
- * sde_plane_rot_flush - perform final flush related rotator options
- * @plane: Pointer to drm plane
- * @pstate: Pointer to sde plane state
- */
-static void sde_plane_rot_flush(struct drm_plane *plane,
- struct sde_plane_state *pstate)
+void sde_plane_kickoff(struct drm_plane *plane)
{
- if (!plane || !pstate || !pstate->rot.rot_hw ||
- !pstate->rot.rot_hw->ops.commit)
+ struct sde_plane_state *pstate;
+
+ if (!plane || !plane->state) {
+ SDE_ERROR("invalid plane\n");
+ return;
+ }
+
+ pstate = to_sde_plane_state(plane->state);
+
+ if (!pstate->rot.rot_hw || !pstate->rot.rot_hw->ops.commit)
return;
pstate->rot.rot_hw->ops.commit(pstate->rot.rot_hw,
@@ -2546,14 +2614,28 @@
struct sde_plane *sde_plane[R_MAX];
const struct sde_format *fmt[R_MAX];
bool q16_data = true;
- int i, buffer_lines = TX_MODE_BUFFER_LINE_THRES;
+ int i, buffer_lines;
+ unsigned int max_tile_height = 1;
bool parallel_fetch_qualified = true;
+ bool has_tiled_rect = false;
for (i = 0; i < R_MAX; i++) {
const struct msm_format *msm_fmt;
- int width_threshold;
drm_state[i] = i ? plane->r1 : plane->r0;
+ msm_fmt = msm_framebuffer_format(drm_state[i]->fb);
+ fmt[i] = to_sde_format(msm_fmt);
+
+ if (SDE_FORMAT_IS_UBWC(fmt[i])) {
+ has_tiled_rect = true;
+ if (fmt[i]->tile_height > max_tile_height)
+ max_tile_height = fmt[i]->tile_height;
+ }
+ }
+
+ for (i = 0; i < R_MAX; i++) {
+ int width_threshold;
+
pstate[i] = to_sde_plane_state(drm_state[i]);
sde_plane[i] = to_sde_plane(drm_state[i]->plane);
@@ -2575,8 +2657,6 @@
return -EINVAL;
}
- msm_fmt = msm_framebuffer_format(drm_state[i]->fb);
- fmt[i] = to_sde_format(msm_fmt);
if (SDE_FORMAT_IS_YUV(fmt[i])) {
SDE_ERROR_PLANE(sde_plane[i],
"Unsupported format for multirect mode\n");
@@ -2591,7 +2671,7 @@
* width for tiled formats.
*/
width_threshold = sde_plane[i]->pipe_sblk->maxlinewidth;
- if (SDE_FORMAT_IS_UBWC(fmt[i]))
+ if (has_tiled_rect)
width_threshold /= 2;
if (parallel_fetch_qualified && src[i].w > width_threshold)
@@ -2610,8 +2690,7 @@
}
/* TIME_MX Mode */
- if (SDE_FORMAT_IS_UBWC(fmt[R0]))
- buffer_lines = 2 * fmt[R0]->tile_height;
+ buffer_lines = 2 * max_tile_height;
if ((dst[R1].y >= dst[R0].y + dst[R0].h + buffer_lines) ||
(dst[R0].y >= dst[R1].y + dst[R1].h + buffer_lines)) {
@@ -2705,10 +2784,13 @@
new_rstate = &to_sde_plane_state(new_state)->rot;
- ret = msm_framebuffer_prepare(new_rstate->out_fb, pstate->aspace);
- if (ret) {
- SDE_ERROR("failed to prepare framebuffer\n");
- return ret;
+ if (pstate->aspace) {
+ ret = msm_framebuffer_prepare(new_rstate->out_fb,
+ pstate->aspace);
+ if (ret) {
+ SDE_ERROR("failed to prepare framebuffer\n");
+ return ret;
+ }
}
/* validate framebuffer layout before commit */
@@ -3140,10 +3222,6 @@
return ret;
}
-/**
- * sde_plane_flush - final plane operations before commit flush
- * @plane: Pointer to drm plane structure
- */
void sde_plane_flush(struct drm_plane *plane)
{
struct sde_plane *psde;
@@ -3171,21 +3249,33 @@
psde->pipe_hw->ops.setup_csc(psde->pipe_hw, psde->csc_ptr);
/* force black color fill during suspend */
- if (msm_is_suspend_state(plane->dev) && suspend_blank)
+ if (sde_kms_is_suspend_state(plane->dev) && suspend_blank)
_sde_plane_color_fill(psde, 0x0, 0x0);
/* flag h/w flush complete */
if (plane->state)
pstate->pending = false;
+}
- /* signal inline rotator start */
- sde_plane_rot_flush(plane, pstate);
+/**
+ * sde_plane_set_error: enable/disable error condition
+ * @plane: pointer to drm_plane structure
+ */
+void sde_plane_set_error(struct drm_plane *plane, bool error)
+{
+ struct sde_plane *psde;
+
+ if (!plane)
+ return;
+
+ psde = to_sde_plane(plane);
+ psde->is_error = error;
}
static int sde_plane_sspp_atomic_update(struct drm_plane *plane,
struct drm_plane_state *old_state)
{
- uint32_t nplanes, src_flags = 0x0;
+ uint32_t nplanes, src_flags;
struct sde_plane *psde;
struct drm_plane_state *state;
struct sde_plane_state *pstate;
@@ -3198,7 +3288,6 @@
const struct sde_rect *crtc_roi;
bool q16_data = true;
int idx;
- int mode;
if (!plane) {
SDE_ERROR("invalid plane\n");
@@ -3250,7 +3339,8 @@
}
/* determine what needs to be refreshed */
- while ((idx = msm_property_pop_dirty(&psde->property_info)) >= 0) {
+ while ((idx = msm_property_pop_dirty(&psde->property_info,
+ &pstate->property_state)) >= 0) {
switch (idx) {
case PLANE_PROP_SCALER_V1:
case PLANE_PROP_SCALER_V2:
@@ -3331,10 +3421,19 @@
_sde_plane_set_qos_ctrl(plane, false, SDE_PLANE_QOS_PANIC_CTRL);
/* update secure session flag */
- mode = sde_plane_get_property(pstate, PLANE_PROP_FB_TRANSLATION_MODE);
- if ((mode == SDE_DRM_FB_SEC) ||
- (mode == SDE_DRM_FB_SEC_DIR_TRANS))
- src_flags |= SDE_SSPP_SECURE_OVERLAY_SESSION;
+ if (pstate->dirty & SDE_PLANE_DIRTY_FB_TRANSLATION_MODE) {
+ bool enable = false;
+ int mode = sde_plane_get_property(pstate,
+ PLANE_PROP_FB_TRANSLATION_MODE);
+
+ if ((mode == SDE_DRM_FB_SEC) ||
+ (mode == SDE_DRM_FB_SEC_DIR_TRANS))
+ enable = true;
+ /* update secure session flag */
+ psde->pipe_hw->ops.setup_secure_address(psde->pipe_hw,
+ pstate->multirect_index,
+ enable);
+ }
/* update roi config */
if (pstate->dirty & SDE_PLANE_DIRTY_RECTS) {
@@ -3413,9 +3512,9 @@
pstate->multirect_mode);
}
- if (((pstate->dirty & SDE_PLANE_DIRTY_FORMAT) ||
- (src_flags & SDE_SSPP_SECURE_OVERLAY_SESSION)) &&
+ if ((pstate->dirty & SDE_PLANE_DIRTY_FORMAT) &&
psde->pipe_hw->ops.setup_format) {
+ src_flags = 0x0;
SDE_DEBUG_PLANE(psde, "rotation 0x%X\n", rstate->out_rotation);
if (rstate->out_rotation & DRM_REFLECT_X)
src_flags |= SDE_SSPP_FLIP_LR;
@@ -3624,7 +3723,6 @@
{SDE_DRM_FB_SEC_DIR_TRANS, "sec_direct_translation"},
};
const struct sde_format_extended *format_list;
- struct sde_format_extended *virt_format_list = NULL;
struct sde_kms_info *info;
struct sde_plane *psde = to_sde_plane(plane);
int zpos_max = 255;
@@ -3767,29 +3865,10 @@
DRM_MODE_PROP_IMMUTABLE, PLANE_PROP_INFO);
sde_kms_info_reset(info);
- format_list = psde->pipe_sblk->format_list;
-
- if (master_plane_id) {
- int index, array_size;
-
- array_size = ARRAY_SIZE(plane_formats)
- + ARRAY_SIZE(rgb_10bit_formats);
- virt_format_list = kcalloc(array_size,
- sizeof(struct sde_format_extended), GFP_KERNEL);
- if (!virt_format_list) {
- SDE_ERROR(
- "failed to allocate virtual pipe format list\n");
- return;
- }
-
- index = sde_copy_formats(virt_format_list, array_size,
- 0, plane_formats, ARRAY_SIZE(plane_formats));
- sde_copy_formats(virt_format_list, array_size,
- index, rgb_10bit_formats,
- ARRAY_SIZE(rgb_10bit_formats));
-
- format_list = virt_format_list;
-
+ if (!master_plane_id) {
+ format_list = psde->pipe_sblk->format_list;
+ } else {
+ format_list = psde->pipe_sblk->virt_format_list;
sde_kms_info_add_keyint(info, "primary_smart_plane_id",
master_plane_id);
}
@@ -3805,6 +3884,10 @@
sde_kms_info_stop(info);
}
+ if (psde->pipe_hw && psde->pipe_hw->ops.get_scaler_ver)
+ sde_kms_info_add_keyint(info, "scaler_step_ver",
+ psde->pipe_hw->ops.get_scaler_ver(psde->pipe_hw));
+
sde_kms_info_add_keyint(info, "max_linewidth",
psde->pipe_sblk->maxlinewidth);
sde_kms_info_add_keyint(info, "max_upscale",
@@ -3822,7 +3905,6 @@
PLANE_PROP_INFO);
kfree(info);
- kfree(virt_format_list);
if (psde->features & BIT(SDE_SSPP_MEMCOLOR)) {
snprintf(feature_name, sizeof(feature_name), "%s%d",
@@ -3908,7 +3990,8 @@
}
/* force property to be dirty, even if the pointer didn't change */
- msm_property_set_dirty(&psde->property_info, PLANE_PROP_SCALER_V1);
+ msm_property_set_dirty(&psde->property_info,
+ &pstate->property_state, PLANE_PROP_SCALER_V1);
/* populate from user space */
pe = &pstate->pixel_ext;
@@ -3974,7 +4057,8 @@
}
/* force property to be dirty, even if the pointer didn't change */
- msm_property_set_dirty(&psde->property_info, PLANE_PROP_SCALER_V2);
+ msm_property_set_dirty(&psde->property_info,
+ &pstate->property_state, PLANE_PROP_SCALER_V2);
/* populate from user space */
pe = &pstate->pixel_ext;
@@ -4091,8 +4175,7 @@
} else {
pstate = to_sde_plane_state(state);
ret = msm_property_atomic_set(&psde->property_info,
- pstate->property_values, pstate->property_blobs,
- property, val);
+ &pstate->property_state, property, val);
if (!ret) {
idx = msm_property_index(&psde->property_info,
property);
@@ -4109,7 +4192,7 @@
break;
case PLANE_PROP_SCALER_V2:
_sde_plane_set_scaler_v2(psde, pstate,
- (void *)val);
+ (void *)val);
break;
case PLANE_PROP_EXCL_RECT_V1:
_sde_plane_set_excl_rect_v1(psde, pstate,
@@ -4154,8 +4237,7 @@
pstate = to_sde_plane_state(state);
sde_plane_rot_install_caps(plane);
ret = msm_property_atomic_get(&psde->property_info,
- pstate->property_values, pstate->property_blobs,
- property, val);
+ &pstate->property_state, property, val);
}
return ret;
@@ -4216,7 +4298,7 @@
/* destroy value helper */
msm_property_destroy_state(&psde->property_info, pstate,
- pstate->property_values, pstate->property_blobs);
+ &pstate->property_state);
}
static struct drm_plane_state *
@@ -4247,13 +4329,14 @@
/* duplicate value helper */
msm_property_duplicate_state(&psde->property_info, old_state, pstate,
- pstate->property_values, pstate->property_blobs);
+ &pstate->property_state, pstate->property_values);
/* clear out any input fence */
pstate->input_fence = 0;
input_fence_default = msm_property_get_default(
&psde->property_info, PLANE_PROP_INPUT_FENCE);
- msm_property_set_property(&psde->property_info, pstate->property_values,
+ msm_property_set_property(&psde->property_info,
+ &pstate->property_state,
PLANE_PROP_INPUT_FENCE, input_fence_default);
pstate->dirty = 0x0;
@@ -4293,7 +4376,8 @@
/* reset value helper */
msm_property_reset_state(&psde->property_info, pstate,
- pstate->property_values, pstate->property_blobs);
+ &pstate->property_state,
+ pstate->property_values);
pstate->base.plane = plane;
@@ -4568,7 +4652,6 @@
{
struct drm_plane *plane = NULL, *master_plane = NULL;
const struct sde_format_extended *format_list;
- struct sde_format_extended *virt_format_list = NULL;
struct sde_plane *psde;
struct msm_drm_private *priv;
struct sde_kms *kms;
@@ -4637,30 +4720,10 @@
goto clean_sspp;
}
- format_list = psde->pipe_sblk->format_list;
-
- if (master_plane_id) {
- int index, array_size;
-
- array_size = ARRAY_SIZE(plane_formats)
- + ARRAY_SIZE(rgb_10bit_formats);
- virt_format_list = kcalloc(array_size,
- sizeof(struct sde_format_extended),
- GFP_KERNEL);
- if (!virt_format_list) {
- SDE_ERROR(
- "failed to allocate virtual pipe format list\n");
- goto clean_sspp;
- }
-
- index = sde_copy_formats(virt_format_list, array_size,
- 0, plane_formats, ARRAY_SIZE(plane_formats));
- sde_copy_formats(virt_format_list, array_size,
- index, rgb_10bit_formats,
- ARRAY_SIZE(rgb_10bit_formats));
-
- format_list = virt_format_list;
- }
+ if (!master_plane_id)
+ format_list = psde->pipe_sblk->format_list;
+ else
+ format_list = psde->pipe_sblk->virt_format_list;
psde->nformats = sde_populate_formats(format_list,
psde->formats,
@@ -4709,6 +4772,5 @@
clean_plane:
kfree(psde);
exit:
- kfree(virt_format_list);
return ERR_PTR(ret);
}
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.h b/drivers/gpu/drm/msm/sde/sde_plane.h
index 2f0068a..913647f 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.h
+++ b/drivers/gpu/drm/msm/sde/sde_plane.h
@@ -119,8 +119,8 @@
/**
* struct sde_plane_state: Define sde extension of drm plane state object
* @base: base drm plane state object
+ * @property_state: Local storage for msm_prop properties
* @property_values: cached plane property values
- * @property_blobs: blob properties
* @aspace: pointer to address space for input/output buffers
* @input_fence: dereferenced input fence pointer
* @stage: assigned by crtc blender
@@ -136,8 +136,8 @@
*/
struct sde_plane_state {
struct drm_plane_state base;
- uint64_t property_values[PLANE_PROP_COUNT];
- struct drm_property_blob *property_blobs[PLANE_PROP_BLOBCOUNT];
+ struct msm_property_state property_state;
+ struct msm_property_value property_values[PLANE_PROP_COUNT];
struct msm_gem_address_space *aspace;
void *input_fence;
enum sde_stage stage;
@@ -178,8 +178,8 @@
* @X: Property index, from enum msm_mdp_plane_property
* Returns: Integer value of requested property
*/
-#define sde_plane_get_property(S, X) \
- ((S) && ((X) < PLANE_PROP_COUNT) ? ((S)->property_values[(X)]) : 0)
+#define sde_plane_get_property(S, X) ((S) && ((X) < PLANE_PROP_COUNT) ? \
+ ((S)->property_values[(X)].value) : 0)
/**
* sde_plane_pipe - return sspp identifier for the given plane
@@ -227,6 +227,18 @@
void sde_plane_flush(struct drm_plane *plane);
/**
+ * sde_plane_kickoff - final plane operations before commit kickoff
+ * @plane: Pointer to drm plane structure
+ */
+void sde_plane_kickoff(struct drm_plane *plane);
+
+/**
+ * sde_plane_set_error: enable/disable error condition
+ * @plane: pointer to drm_plane structure
+ */
+void sde_plane_set_error(struct drm_plane *plane, bool error);
+
+/**
* sde_plane_init - create new sde plane for the given pipe
* @dev: Pointer to DRM device
* @pipe: sde hardware pipe identifier
diff --git a/drivers/gpu/drm/msm/sde/sde_reg_dma.h b/drivers/gpu/drm/msm/sde/sde_reg_dma.h
index 70d995a..b9d7843 100644
--- a/drivers/gpu/drm/msm/sde/sde_reg_dma.h
+++ b/drivers/gpu/drm/msm/sde/sde_reg_dma.h
@@ -171,6 +171,7 @@
/**
* struct sde_reg_dma_buffer - defines reg dma buffer structure.
* @drm_gem_object *buf: drm gem handle for the buffer
+ * @asapce : pointer to address space
* @buffer_size: buffer size
* @index: write pointer index
* @iova: device address
@@ -180,6 +181,7 @@
*/
struct sde_reg_dma_buffer {
struct drm_gem_object *buf;
+ struct msm_gem_address_space *aspace;
u32 buffer_size;
u32 index;
u32 iova;
diff --git a/drivers/gpu/drm/msm/sde/sde_rm.c b/drivers/gpu/drm/msm/sde/sde_rm.c
index 0382ed0..be3a8af 100644
--- a/drivers/gpu/drm/msm/sde/sde_rm.c
+++ b/drivers/gpu/drm/msm/sde/sde_rm.c
@@ -1150,7 +1150,7 @@
(void) msm_property_set_property(
sde_connector_get_propinfo(conn),
- sde_connector_get_property_values(conn->state),
+ sde_connector_get_property_state(conn->state),
CONNECTOR_PROP_TOPOLOGY_NAME,
SDE_RM_TOPOLOGY_NONE);
}
@@ -1170,7 +1170,7 @@
ret = msm_property_set_property(
sde_connector_get_propinfo(conn_state->connector),
- sde_connector_get_property_values(conn_state),
+ sde_connector_get_property_state(conn_state),
CONNECTOR_PROP_TOPOLOGY_NAME,
rsvp->topology);
if (ret) {
@@ -1267,7 +1267,7 @@
(void) msm_property_set_property(
sde_connector_get_propinfo(
conn_state->connector),
- sde_connector_get_property_values(conn_state),
+ sde_connector_get_property_state(conn_state),
CONNECTOR_PROP_TOPOLOGY_NAME,
SDE_RM_TOPOLOGY_NONE);
}
diff --git a/drivers/gpu/drm/msm/sde/sde_trace.h b/drivers/gpu/drm/msm/sde/sde_trace.h
index 47fc39b..19cda3e 100644
--- a/drivers/gpu/drm/msm/sde/sde_trace.h
+++ b/drivers/gpu/drm/msm/sde/sde_trace.h
@@ -179,7 +179,7 @@
memset(&__entry->data[cnt], 0,
(SDE_TRACE_EVTLOG_SIZE - cnt) * sizeof(u32));
),
- TP_printk("%d|%s:%d|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u",
+ TP_printk("%d|%s:%d|%x|%x|%x|%x|%x|%x|%x|%x|%x|%x|%x|%x|%x|%x|%x",
__entry->pid, __get_str(evtlog_tag),
__entry->tag_id,
__entry->data[0], __entry->data[1],
diff --git a/drivers/gpu/drm/msm/sde/sde_vbif.c b/drivers/gpu/drm/msm/sde/sde_vbif.c
index 847572b..7fcd03e 100644
--- a/drivers/gpu/drm/msm/sde/sde_vbif.c
+++ b/drivers/gpu/drm/msm/sde/sde_vbif.c
@@ -184,6 +184,10 @@
!vbif->ops.set_halt_ctrl)
return;
+ /* set write_gather_en for all write clients */
+ if (vbif->ops.set_write_gather_en && !params->rd)
+ vbif->ops.set_write_gather_en(vbif, params->xin_id);
+
ot_lim = _sde_vbif_get_ot_limit(vbif, params) & 0xFF;
if (ot_lim == 0)
@@ -265,6 +269,29 @@
mdp->ops.setup_clk_force_ctrl(mdp, params->clk_ctrl, false);
}
+void sde_vbif_clear_errors(struct sde_kms *sde_kms)
+{
+ struct sde_hw_vbif *vbif;
+ u32 i, pnd, src;
+
+ if (!sde_kms) {
+ SDE_ERROR("invalid argument\n");
+ return;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(sde_kms->hw_vbif); i++) {
+ vbif = sde_kms->hw_vbif[i];
+ if (vbif && vbif->ops.clear_errors) {
+ vbif->ops.clear_errors(vbif, &pnd, &src);
+ if (pnd || src) {
+ SDE_EVT32(i, pnd, src);
+ SDE_DEBUG("VBIF %d: pnd 0x%X, src 0x%X\n",
+ vbif->idx - VBIF_0, pnd, src);
+ }
+ }
+ }
+}
+
void sde_vbif_init_memtypes(struct sde_kms *sde_kms)
{
struct sde_hw_vbif *vbif;
diff --git a/drivers/gpu/drm/msm/sde/sde_vbif.h b/drivers/gpu/drm/msm/sde/sde_vbif.h
index f1da68b1..a4830a0 100644
--- a/drivers/gpu/drm/msm/sde/sde_vbif.h
+++ b/drivers/gpu/drm/msm/sde/sde_vbif.h
@@ -67,6 +67,12 @@
struct sde_vbif_set_qos_params *params);
/**
+ * sde_vbif_clear_errors - clear any vbif errors
+ * @sde_kms: SDE handler
+ */
+void sde_vbif_clear_errors(struct sde_kms *sde_kms);
+
+/**
* sde_vbif_init_memtypes - initialize xin memory types for vbif
* @sde_kms: SDE handler
*/
diff --git a/drivers/gpu/drm/msm/sde/sde_wb.c b/drivers/gpu/drm/msm/sde/sde_wb.c
index ceda16e..145acea 100644
--- a/drivers/gpu/drm/msm/sde/sde_wb.c
+++ b/drivers/gpu/drm/msm/sde/sde_wb.c
@@ -283,28 +283,31 @@
wb_dev->wb_cfg->sblk->maxlinewidth :
SDE_WB_MODE_MAX_WIDTH;
info->max_height = SDE_WB_MODE_MAX_HEIGHT;
- info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_NONE;
return 0;
}
-int sde_wb_get_topology(const struct drm_display_mode *drm_mode,
- struct msm_display_topology *topology, u32 max_mixer_width)
+int sde_wb_get_mode_info(const struct drm_display_mode *drm_mode,
+ struct msm_mode_info *mode_info, u32 max_mixer_width)
{
const u32 dual_lm = 2;
const u32 single_lm = 1;
const u32 single_intf = 1;
const u32 no_enc = 0;
+ struct msm_display_topology *topology;
- if (!drm_mode || !topology || !max_mixer_width) {
+ if (!drm_mode || !mode_info || !max_mixer_width) {
pr_err("invalid params\n");
return -EINVAL;
}
+ topology = &mode_info->topology;
topology->num_lm = (max_mixer_width <= drm_mode->hdisplay) ?
dual_lm : single_lm;
topology->num_enc = no_enc;
topology->num_intf = single_intf;
+ mode_info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_NONE;
+
return 0;
}
diff --git a/drivers/gpu/drm/msm/sde/sde_wb.h b/drivers/gpu/drm/msm/sde/sde_wb.h
index 205ff24..aa57d3e 100644
--- a/drivers/gpu/drm/msm/sde/sde_wb.h
+++ b/drivers/gpu/drm/msm/sde/sde_wb.h
@@ -186,15 +186,14 @@
int sde_wb_get_info(struct msm_display_info *info, void *display);
/**
- * sde_wb_get_topology - retrieve current topology for the mode selected
+ * sde_wb_get_mode_info - retrieve information of the mode selected
* @drm_mode: Display mode set for the display
- * @topology: Out parameter. Topology for the mode.
+ * @mode_info: Out parameter. information of the mode.
* @max_mixer_width: max width supported by HW layer mixer
* Returns: zero on success
*/
-int sde_wb_get_topology(const struct drm_display_mode *drm_mode,
- struct msm_display_topology *topology,
- u32 max_mixer_width);
+int sde_wb_get_mode_info(const struct drm_display_mode *drm_mode,
+ struct msm_mode_info *mode_info, u32 max_mixer_width);
/**
* sde_wb_connector_get_wb - retrieve writeback device of the given connector
diff --git a/drivers/gpu/drm/msm/sde_dbg.c b/drivers/gpu/drm/msm/sde_dbg.c
index 58448ca..7e58c2f 100644
--- a/drivers/gpu/drm/msm/sde_dbg.c
+++ b/drivers/gpu/drm/msm/sde_dbg.c
@@ -56,6 +56,8 @@
#define MMSS_VBIF_TEST_BUS_OUT 0x230
/* Vbif error info */
+#define MMSS_VBIF_PND_ERR 0x190
+#define MMSS_VBIF_SRC_ERR 0x194
#define MMSS_VBIF_XIN_HALT_CTRL1 0x204
#define MMSS_VBIF_ERR_INFO 0X1a0
#define MMSS_VBIF_ERR_INFO_1 0x1a4
@@ -104,6 +106,8 @@
* @buf: buffer used for manual register dumping
* @buf_len: buffer length used for manual register dumping
* @reg_dump: address for the mem dump if no ranges used
+ * @cb: callback for external dump function, null if not defined
+ * @cb_ptr: private pointer to callback function
*/
struct sde_dbg_reg_base {
struct list_head reg_base_head;
@@ -116,6 +120,8 @@
char *buf;
size_t buf_len;
u32 *reg_dump;
+ void (*cb)(void *ptr);
+ void *cb_ptr;
};
struct sde_debug_bus_entry {
@@ -2142,16 +2148,17 @@
size_t len;
struct sde_dbg_reg_range *range_node;
- if (!dbg || !dbg->base) {
+ if (!dbg || !(dbg->base || dbg->cb)) {
pr_err("dbg base is null!\n");
return;
}
dev_info(sde_dbg_base.dev, "%s:=========%s DUMP=========\n", __func__,
dbg->name);
-
+ if (dbg->cb) {
+ dbg->cb(dbg->cb_ptr);
/* If there is a list to dump the registers by ranges, use the ranges */
- if (!list_empty(&dbg->sub_range_list)) {
+ } else if (!list_empty(&dbg->sub_range_list)) {
/* sort the list by start address first */
list_sort(NULL, &dbg->sub_range_list, _sde_dump_reg_range_cmp);
list_for_each_entry(range_node, &dbg->sub_range_list, head) {
@@ -2300,10 +2307,14 @@
mem_base + head->wr_addr);
wmb(); /* make sure test bits were written */
- if (bus->cmn.flags & DBGBUS_FLAGS_DSPP)
+ if (bus->cmn.flags & DBGBUS_FLAGS_DSPP) {
offset = DBGBUS_DSPP_STATUS;
- else
+ /* keep DSPP test point enabled */
+ if (head->wr_addr != DBGBUS_DSPP)
+ writel_relaxed(0xF, mem_base + DBGBUS_DSPP);
+ } else {
offset = head->wr_addr + 0x4;
+ }
status = readl_relaxed(mem_base + offset);
@@ -2325,7 +2336,9 @@
/* Disable debug bus once we are done */
writel_relaxed(0, mem_base + head->wr_addr);
-
+ if (bus->cmn.flags & DBGBUS_FLAGS_DSPP &&
+ head->wr_addr != DBGBUS_DSPP)
+ writel_relaxed(0x0, mem_base + DBGBUS_DSPP);
}
_sde_dbg_enable_power(false);
@@ -2373,7 +2386,7 @@
u32 **dump_mem = NULL;
u32 *dump_addr = NULL;
u32 value, d0, d1;
- unsigned long reg;
+ unsigned long reg, reg1, reg2;
struct vbif_debug_bus_entry *head;
phys_addr_t phys = 0;
int i, list_size = 0;
@@ -2447,13 +2460,18 @@
wmb();
/**
- * Extract VBIF error info based on XIN halt status.
- * If the XIN client is not in HALT state, then retrieve the
- * VBIF error info for it.
+ * Extract VBIF error info based on XIN halt and error status.
+ * If the XIN client is not in HALT state, or an error is detected,
+ * then retrieve the VBIF error info for it.
*/
reg = readl_relaxed(mem_base + MMSS_VBIF_XIN_HALT_CTRL1);
- dev_err(sde_dbg_base.dev, "XIN HALT:0x%lX\n", reg);
+ reg1 = readl_relaxed(mem_base + MMSS_VBIF_PND_ERR);
+ reg2 = readl_relaxed(mem_base + MMSS_VBIF_SRC_ERR);
+ dev_err(sde_dbg_base.dev,
+ "XIN HALT:0x%lX, PND ERR:0x%lX, SRC ERR:0x%lX\n",
+ reg, reg1, reg2);
reg >>= 16;
+ reg &= ~(reg1 | reg2);
for (i = 0; i < MMSS_VBIF_CLIENT_NUM; i++) {
if (!test_bit(0, ®)) {
writel_relaxed(i, mem_base + MMSS_VBIF_ERR_INFO);
@@ -3172,6 +3190,60 @@
return 0;
}
+int sde_dbg_reg_register_cb(const char *name, void (*cb)(void *), void *ptr)
+{
+ struct sde_dbg_base *dbg_base = &sde_dbg_base;
+ struct sde_dbg_reg_base *reg_base;
+
+ if (!name || !strlen(name)) {
+ pr_err("no debug name provided\n");
+ return -EINVAL;
+ }
+
+ reg_base = kzalloc(sizeof(*reg_base), GFP_KERNEL);
+ if (!reg_base)
+ return -ENOMEM;
+
+ strlcpy(reg_base->name, name, sizeof(reg_base->name));
+ reg_base->base = NULL;
+ reg_base->max_offset = 0;
+ reg_base->off = 0;
+ reg_base->cnt = DEFAULT_BASE_REG_CNT;
+ reg_base->reg_dump = NULL;
+ reg_base->cb = cb;
+ reg_base->cb_ptr = ptr;
+
+ /* Initialize list to make sure check for null list will be valid */
+ INIT_LIST_HEAD(®_base->sub_range_list);
+
+ pr_debug("%s cb: %pK cb_ptr: %pK\n", reg_base->name,
+ reg_base->cb, reg_base->cb_ptr);
+
+ list_add(®_base->reg_base_head, &dbg_base->reg_base_list);
+
+ return 0;
+}
+
+void sde_dbg_reg_unregister_cb(const char *name, void (*cb)(void *), void *ptr)
+{
+ struct sde_dbg_base *dbg_base = &sde_dbg_base;
+ struct sde_dbg_reg_base *reg_base;
+
+ if (!dbg_base)
+ return;
+
+ list_for_each_entry(reg_base, &dbg_base->reg_base_list, reg_base_head) {
+ if (strlen(reg_base->name) &&
+ !strcmp(reg_base->name, name)) {
+ pr_debug("%s cb: %pK cb_ptr: %pK\n", reg_base->name,
+ reg_base->cb, reg_base->cb_ptr);
+ list_del(®_base->reg_base_head);
+ kfree(reg_base);
+ break;
+ }
+ }
+}
+
void sde_dbg_reg_register_dump_range(const char *base_name,
const char *range_name, u32 offset_start, u32 offset_end,
uint32_t xin_id)
diff --git a/drivers/gpu/drm/msm/sde_dbg.h b/drivers/gpu/drm/msm/sde_dbg.h
index e14d60e..a266574 100644
--- a/drivers/gpu/drm/msm/sde_dbg.h
+++ b/drivers/gpu/drm/msm/sde_dbg.h
@@ -25,6 +25,11 @@
#define SDE_EVTLOG_FUNC_CASE3 0x5555
#define SDE_EVTLOG_FUNC_CASE4 0x6666
#define SDE_EVTLOG_FUNC_CASE5 0x7777
+#define SDE_EVTLOG_FUNC_CASE6 0x8888
+#define SDE_EVTLOG_FUNC_CASE7 0x9999
+#define SDE_EVTLOG_FUNC_CASE8 0xaaaa
+#define SDE_EVTLOG_FUNC_CASE9 0xbbbb
+#define SDE_EVTLOG_FUNC_CASE10 0xcccc
#define SDE_EVTLOG_PANIC 0xdead
#define SDE_EVTLOG_FATAL 0xbad
#define SDE_EVTLOG_ERROR 0xebad
@@ -251,6 +256,26 @@
size_t max_offset);
/**
+ * sde_dbg_reg_register_cb - register a hw register callback for later
+ * dumping.
+ * @name: name of base region
+ * @cb: callback of external region
+ * @cb_ptr: private pointer of external region
+ * Returns: 0 or -ERROR
+ */
+int sde_dbg_reg_register_cb(const char *name, void (*cb)(void *), void *ptr);
+
+/**
+ * sde_dbg_reg_unregister_cb - register a hw unregister callback for later
+ * dumping.
+ * @name: name of base region
+ * @cb: callback of external region
+ * @cb_ptr: private pointer of external region
+ * Returns: None
+ */
+void sde_dbg_reg_unregister_cb(const char *name, void (*cb)(void *), void *ptr);
+
+/**
* sde_dbg_reg_register_dump_range - register a hw register sub-region for
* later register dumping associated with base specified by
* sde_dbg_reg_register_base
diff --git a/drivers/gpu/drm/msm/sde_edid_parser.c b/drivers/gpu/drm/msm/sde_edid_parser.c
index 130bd1f..3d6c2ea 100644
--- a/drivers/gpu/drm/msm/sde_edid_parser.c
+++ b/drivers/gpu/drm/msm/sde_edid_parser.c
@@ -228,10 +228,17 @@
{
u8 cea_mode = 0;
struct drm_display_mode *mode;
+ u32 mode_fmt_flags = 0;
/* Need to add Y420 support flag to the modes */
list_for_each_entry(mode, &connector->probed_modes, head) {
+ /* Cache the format flags before clearing */
+ mode_fmt_flags = mode->flags;
+ /* Clear the RGB/YUV format flags before calling upstream API */
+ mode->flags &= ~SDE_DRM_MODE_FLAG_FMT_MASK;
cea_mode = drm_match_cea_mode(mode);
+ /* Restore the format flags */
+ mode->flags = mode_fmt_flags;
if ((cea_mode != 0) && (cea_mode == video_format)) {
SDE_EDID_DEBUG("%s found match for %d ", __func__,
video_format);
@@ -245,7 +252,7 @@
const u8 *db)
{
u32 offset = 0;
- u8 len = 0;
+ u8 cmdb_len = 0;
u8 svd_len = 0;
const u8 *svd = NULL;
u32 i = 0, j = 0;
@@ -261,10 +268,8 @@
return;
}
SDE_EDID_DEBUG("%s +\n", __func__);
- len = db[0] & 0x1f;
+ cmdb_len = db[0] & 0x1f;
- if (len < 7)
- return;
/* Byte 3 to L+1 contain SVDs */
offset += 2;
@@ -272,20 +277,24 @@
if (svd) {
/*moving to the next byte as vic info begins there*/
- ++svd;
svd_len = svd[0] & 0x1f;
+ ++svd;
}
for (i = 0; i < svd_len; i++, j++) {
- video_format = *svd & 0x7F;
- if (db[offset] & (1 << j))
+ video_format = *(svd + i) & 0x7F;
+ if (cmdb_len == 1) {
+ /* If cmdb_len is 1, it means all SVDs support YUV */
+ sde_edid_set_y420_support(connector, video_format);
+ } else if (db[offset] & (1 << j)) {
sde_edid_set_y420_support(connector, video_format);
- if (j & 0x80) {
- j = j/8;
- offset++;
- if (offset >= len)
- break;
+ if (j & 0x80) {
+ j = j/8;
+ offset++;
+ if (offset >= cmdb_len)
+ break;
+ }
}
}
@@ -562,6 +571,11 @@
struct sde_edid_ctrl *edid_ctrl = (struct sde_edid_ctrl *)(input);
struct edid *edid = edid_ctrl->edid;
+ if (!edid) {
+ SDE_ERROR("invalid edid input\n");
+ return 0;
+ }
+
if ((edid->revision < 3) || !(edid->input & DRM_EDID_INPUT_DIGITAL))
return 0;
diff --git a/drivers/gpu/drm/msm/sde_edid_parser.h b/drivers/gpu/drm/msm/sde_edid_parser.h
index eb68439..b58b322 100644
--- a/drivers/gpu/drm/msm/sde_edid_parser.h
+++ b/drivers/gpu/drm/msm/sde_edid_parser.h
@@ -33,6 +33,8 @@
#define SDE_CEA_EXT 0x02
#define SDE_EXTENDED_TAG 0x07
+#define SDE_DRM_MODE_FLAG_FMT_MASK (0x3 << 20)
+
enum extended_data_block_types {
VIDEO_CAPABILITY_DATA_BLOCK = 0x0,
VENDOR_SPECIFIC_VIDEO_DATA_BLOCK = 0x01,
diff --git a/drivers/gpu/drm/msm/sde_hdcp.h b/drivers/gpu/drm/msm/sde_hdcp.h
new file mode 100644
index 0000000..05d290b
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde_hdcp.h
@@ -0,0 +1,75 @@
+/* Copyright (c) 2012, 2014-2017, The Linux Foundation. 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 and
+ * only 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 __SDE_HDCP_H__
+#define __SDE_HDCP_H__
+
+#include <soc/qcom/scm.h>
+
+#include <linux/types.h>
+#include <linux/bitops.h>
+#include <linux/debugfs.h>
+#include <linux/of_device.h>
+#include <linux/i2c.h>
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_edid.h>
+#include "sde_kms.h"
+
+enum sde_hdcp_client_id {
+ HDCP_CLIENT_HDMI,
+ HDCP_CLIENT_DP,
+};
+
+enum sde_hdcp_states {
+ HDCP_STATE_INACTIVE,
+ HDCP_STATE_AUTHENTICATING,
+ HDCP_STATE_AUTHENTICATED,
+ HDCP_STATE_AUTH_FAIL,
+ HDCP_STATE_AUTH_ENC_NONE,
+ HDCP_STATE_AUTH_ENC_1X,
+ HDCP_STATE_AUTH_ENC_2P2
+};
+
+struct sde_hdcp_init_data {
+ struct dss_io_data *core_io;
+ struct dss_io_data *qfprom_io;
+ struct dss_io_data *hdcp_io;
+ struct drm_dp_aux *drm_aux;
+ struct mutex *mutex;
+ struct workqueue_struct *workq;
+ void *cb_data;
+ void (*notify_status)(void *cb_data, enum sde_hdcp_states status);
+ u8 sink_rx_status;
+ unsigned char *revision;
+ u32 phy_addr;
+ bool sec_access;
+ enum sde_hdcp_client_id client_id;
+};
+
+struct sde_hdcp_ops {
+ int (*isr)(void *ptr);
+ int (*cp_irq)(void *ptr);
+ int (*reauthenticate)(void *input);
+ int (*authenticate)(void *hdcp_ctrl);
+ bool (*feature_supported)(void *input);
+ void (*off)(void *hdcp_ctrl);
+};
+
+void *sde_hdcp_1x_init(struct sde_hdcp_init_data *init_data);
+void sde_hdcp_1x_deinit(void *input);
+struct sde_hdcp_ops *sde_hdcp_1x_start(void *input);
+void *sde_dp_hdcp2p2_init(struct sde_hdcp_init_data *init_data);
+void sde_dp_hdcp2p2_deinit(void *input);
+const char *sde_hdcp_state_name(enum sde_hdcp_states hdcp_state);
+struct sde_hdcp_ops *sde_dp_hdcp2p2_start(void *input);
+#endif /* __SDE_HDCP_H__ */
diff --git a/drivers/gpu/drm/msm/sde_hdcp_1x.c b/drivers/gpu/drm/msm/sde_hdcp_1x.c
new file mode 100644
index 0000000..7951c23
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde_hdcp_1x.c
@@ -0,0 +1,1579 @@
+/* Copyright (c) 2010-2017, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+#define pr_fmt(fmt) "[sde-hdcp1x] %s: " fmt, __func__
+
+#include <linux/io.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/stat.h>
+#include <linux/iopoll.h>
+#include <linux/hdcp_qseecom.h>
+#include <drm/drm_dp_helper.h>
+#include "sde_hdcp.h"
+#include "hdmi.xml.h"
+#include "video/msm_hdmi_hdcp_mgr.h"
+#include "dp/dp_reg.h"
+
+#define SDE_HDCP_STATE_NAME (sde_hdcp_state_name(hdcp->hdcp_state))
+
+/* QFPROM Registers for HDMI/HDCP */
+#define QFPROM_RAW_FEAT_CONFIG_ROW0_LSB (0x000000F8)
+#define QFPROM_RAW_FEAT_CONFIG_ROW0_MSB (0x000000FC)
+#define QFPROM_RAW_VERSION_4 (0x000000A8)
+#define SEC_CTRL_HW_VERSION (0x00006000)
+#define HDCP_KSV_LSB (0x000060D8)
+#define HDCP_KSV_MSB (0x000060DC)
+#define HDCP_KSV_VERSION_4_OFFSET (0x00000014)
+
+/* SEC_CTRL version that supports HDCP SEL */
+#define HDCP_SEL_MIN_SEC_VERSION (0x50010000)
+
+/* HDCP Keys state based on HDMI_HDCP_LINK0_STATUS:KEYS_STATE */
+#define HDCP_KEYS_STATE_NO_KEYS 0
+#define HDCP_KEYS_STATE_NOT_CHECKED 1
+#define HDCP_KEYS_STATE_CHECKING 2
+#define HDCP_KEYS_STATE_VALID 3
+#define HDCP_KEYS_STATE_AKSV_NOT_VALID 4
+#define HDCP_KEYS_STATE_CHKSUM_MISMATCH 5
+#define HDCP_KEYS_STATE_PROD_AKSV 6
+#define HDCP_KEYS_STATE_RESERVED 7
+
+#define TZ_HDCP_CMD_ID 0x00004401
+
+#define HDCP_INT_CLR (isr->auth_success_ack | isr->auth_fail_ack | \
+ isr->auth_fail_info_ack | isr->tx_req_ack | \
+ isr->encryption_ready_ack | \
+ isr->encryption_not_ready_ack | isr->tx_req_done_ack)
+
+#define HDCP_INT_EN (isr->auth_success_mask | isr->auth_fail_mask | \
+ isr->encryption_ready_mask | \
+ isr->encryption_not_ready_mask)
+
+#define HDCP_POLL_SLEEP_US (20 * 1000)
+#define HDCP_POLL_TIMEOUT_US (HDCP_POLL_SLEEP_US * 100)
+
+#define sde_hdcp_1x_state(x) (hdcp->hdcp_state == x)
+
+struct sde_hdcp_sink_addr {
+ char *name;
+ u32 addr;
+ u32 len;
+};
+
+struct sde_hdcp_1x_reg_data {
+ u32 reg_id;
+ struct sde_hdcp_sink_addr *sink;
+};
+
+struct sde_hdcp_sink_addr_map {
+ /* addresses to read from sink */
+ struct sde_hdcp_sink_addr bcaps;
+ struct sde_hdcp_sink_addr bksv;
+ struct sde_hdcp_sink_addr r0;
+ struct sde_hdcp_sink_addr bstatus;
+ struct sde_hdcp_sink_addr cp_irq_status;
+ struct sde_hdcp_sink_addr ksv_fifo;
+ struct sde_hdcp_sink_addr v_h0;
+ struct sde_hdcp_sink_addr v_h1;
+ struct sde_hdcp_sink_addr v_h2;
+ struct sde_hdcp_sink_addr v_h3;
+ struct sde_hdcp_sink_addr v_h4;
+
+ /* addresses to write to sink */
+ struct sde_hdcp_sink_addr an;
+ struct sde_hdcp_sink_addr aksv;
+ struct sde_hdcp_sink_addr ainfo;
+};
+
+struct sde_hdcp_int_set {
+ /* interrupt register */
+ u32 int_reg;
+
+ /* interrupt enable/disable masks */
+ u32 auth_success_mask;
+ u32 auth_fail_mask;
+ u32 encryption_ready_mask;
+ u32 encryption_not_ready_mask;
+ u32 tx_req_mask;
+ u32 tx_req_done_mask;
+
+ /* interrupt acknowledgment */
+ u32 auth_success_ack;
+ u32 auth_fail_ack;
+ u32 auth_fail_info_ack;
+ u32 encryption_ready_ack;
+ u32 encryption_not_ready_ack;
+ u32 tx_req_ack;
+ u32 tx_req_done_ack;
+
+ /* interrupt status */
+ u32 auth_success_int;
+ u32 auth_fail_int;
+ u32 encryption_ready;
+ u32 encryption_not_ready;
+ u32 tx_req_int;
+ u32 tx_req_done_int;
+};
+
+struct sde_hdcp_reg_set {
+ u32 status;
+ u32 keys_offset;
+ u32 r0_offset;
+ u32 v_offset;
+ u32 ctrl;
+ u32 aksv_lsb;
+ u32 aksv_msb;
+ u32 entropy_ctrl0;
+ u32 entropy_ctrl1;
+ u32 sec_sha_ctrl;
+ u32 sec_sha_data;
+ u32 sha_status;
+
+ u32 data2_0;
+ u32 data3;
+ u32 data4;
+ u32 data5;
+ u32 data6;
+
+ u32 sec_data0;
+ u32 sec_data1;
+ u32 sec_data7;
+ u32 sec_data8;
+ u32 sec_data9;
+ u32 sec_data10;
+ u32 sec_data11;
+ u32 sec_data12;
+
+ u32 reset;
+ u32 reset_bit;
+
+ u32 repeater;
+};
+
+#define HDCP_REG_SET_CLIENT_HDMI \
+ {0}
+
+#define HDCP_REG_SET_CLIENT_DP \
+{DP_HDCP_STATUS, 16, 14, 13, DP_HDCP_CTRL, \
+ DP_HDCP_SW_LOWER_AKSV, DP_HDCP_SW_UPPER_AKSV, \
+ DP_HDCP_ENTROPY_CTRL0, DP_HDCP_ENTROPY_CTRL1, \
+ HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_CTRL, \
+ HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_DATA, \
+ DP_HDCP_SHA_STATUS, DP_HDCP_RCVPORT_DATA2_0, \
+ DP_HDCP_RCVPORT_DATA3, DP_HDCP_RCVPORT_DATA4, \
+ DP_HDCP_RCVPORT_DATA5, DP_HDCP_RCVPORT_DATA6, \
+ HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA0, \
+ HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA1, \
+ HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA7, \
+ HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA8, \
+ HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA9, \
+ HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA10, \
+ HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA11, \
+ HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA12, \
+ DP_SW_RESET, BIT(1), BIT(1)}
+
+#define HDCP_HDMI_SINK_ADDR_MAP \
+ {{"bcaps", 0x40, 1}, {"bksv", 0x00, 5}, {"r0'", 0x08, 2}, \
+ {"bstatus", 0x41, 2}, {"??", 0x0, 0}, {"ksv-fifo", 0x43, 0}, \
+ {"v_h0", 0x20, 4}, {"v_h1", 0x24, 4}, {"v_h2", 0x28, 4}, \
+ {"v_h3", 0x2c, 4}, {"v_h4", 0x30, 4}, {"an", 0x18, 8}, \
+ {"aksv", 0x10, 5}, {"ainfo", 0x00, 0},}
+
+#define HDCP_DP_SINK_ADDR_MAP \
+ {{"bcaps", 0x68028, 1}, {"bksv", 0x68000, 5}, {"r0'", 0x68005, 2}, \
+ {"binfo", 0x6802A, 2}, {"cp_irq_status", 0x68029, 1}, \
+ {"ksv-fifo", 0x6802C, 0}, {"v_h0", 0x68014, 4}, {"v_h1", 0x68018, 4}, \
+ {"v_h2", 0x6801C, 4}, {"v_h3", 0x68020, 4}, {"v_h4", 0x68024, 4}, \
+ {"an", 0x6800C, 8}, {"aksv", 0x68007, 5}, {"ainfo", 0x6803B, 1} }
+
+#define HDCP_HDMI_INT_SET \
+ {0}
+
+#define HDCP_DP_INT_SET \
+ {DP_INTR_STATUS2, \
+ BIT(17), BIT(20), BIT(24), BIT(27), 0, 0, \
+ BIT(16), BIT(19), BIT(21), BIT(23), BIT(26), 0, 0, \
+ BIT(15), BIT(18), BIT(22), BIT(25), 0, 0}
+
+struct sde_hdcp_1x {
+ u8 bcaps;
+ u32 tp_msgid;
+ u32 an_0, an_1, aksv_0, aksv_1;
+ bool sink_r0_ready;
+ bool reauth;
+ bool ksv_ready;
+ enum sde_hdcp_states hdcp_state;
+ struct HDCP_V2V1_MSG_TOPOLOGY cached_tp;
+ struct HDCP_V2V1_MSG_TOPOLOGY current_tp;
+ struct delayed_work hdcp_auth_work;
+ struct completion r0_checked;
+ struct completion sink_r0_available;
+ struct sde_hdcp_init_data init_data;
+ struct sde_hdcp_ops *ops;
+ struct sde_hdcp_reg_set reg_set;
+ struct sde_hdcp_int_set int_set;
+ struct sde_hdcp_sink_addr_map sink_addr;
+ struct workqueue_struct *workq;
+};
+
+const char *sde_hdcp_state_name(enum sde_hdcp_states hdcp_state)
+{
+ switch (hdcp_state) {
+ case HDCP_STATE_INACTIVE: return "HDCP_STATE_INACTIVE";
+ case HDCP_STATE_AUTHENTICATING: return "HDCP_STATE_AUTHENTICATING";
+ case HDCP_STATE_AUTHENTICATED: return "HDCP_STATE_AUTHENTICATED";
+ case HDCP_STATE_AUTH_FAIL: return "HDCP_STATE_AUTH_FAIL";
+ default: return "???";
+ }
+}
+
+static int sde_hdcp_1x_count_one(u8 *array, u8 len)
+{
+ int i, j, count = 0;
+
+ for (i = 0; i < len; i++)
+ for (j = 0; j < 8; j++)
+ count += (((array[i] >> j) & 0x1) ? 1 : 0);
+ return count;
+}
+
+static int sde_hdcp_1x_load_keys(void *input)
+{
+ int rc = 0;
+ bool use_sw_keys = false;
+ u32 reg_val;
+ u32 ksv_lsb_addr, ksv_msb_addr;
+ u32 aksv_lsb, aksv_msb;
+ u8 aksv[5];
+ struct dss_io_data *io;
+ struct dss_io_data *qfprom_io;
+ struct sde_hdcp_1x *hdcp = input;
+ struct sde_hdcp_reg_set *reg_set;
+
+ if (!hdcp || !hdcp->init_data.core_io ||
+ !hdcp->init_data.qfprom_io) {
+ pr_err("invalid input\n");
+ rc = -EINVAL;
+ goto end;
+ }
+
+ if (!sde_hdcp_1x_state(HDCP_STATE_INACTIVE) &&
+ !sde_hdcp_1x_state(HDCP_STATE_AUTH_FAIL)) {
+ pr_err("%s: invalid state. returning\n",
+ SDE_HDCP_STATE_NAME);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ io = hdcp->init_data.core_io;
+ qfprom_io = hdcp->init_data.qfprom_io;
+ reg_set = &hdcp->reg_set;
+
+ /* On compatible hardware, use SW keys */
+ reg_val = DSS_REG_R(qfprom_io, SEC_CTRL_HW_VERSION);
+ if (reg_val >= HDCP_SEL_MIN_SEC_VERSION) {
+ reg_val = DSS_REG_R(qfprom_io,
+ QFPROM_RAW_FEAT_CONFIG_ROW0_MSB +
+ QFPROM_RAW_VERSION_4);
+
+ if (!(reg_val & BIT(23)))
+ use_sw_keys = true;
+ }
+
+ if (use_sw_keys) {
+ if (hdcp1_set_keys(&aksv_msb, &aksv_lsb)) {
+ pr_err("setting hdcp SW keys failed\n");
+ rc = -EINVAL;
+ goto end;
+ }
+ } else {
+ /* Fetch aksv from QFPROM, this info should be public. */
+ ksv_lsb_addr = HDCP_KSV_LSB;
+ ksv_msb_addr = HDCP_KSV_MSB;
+
+ if (hdcp->init_data.sec_access) {
+ ksv_lsb_addr += HDCP_KSV_VERSION_4_OFFSET;
+ ksv_msb_addr += HDCP_KSV_VERSION_4_OFFSET;
+ }
+
+ aksv_lsb = DSS_REG_R(qfprom_io, ksv_lsb_addr);
+ aksv_msb = DSS_REG_R(qfprom_io, ksv_msb_addr);
+ }
+
+ pr_debug("%s: AKSV=%02x%08x\n", SDE_HDCP_STATE_NAME,
+ aksv_msb, aksv_lsb);
+
+ aksv[0] = aksv_lsb & 0xFF;
+ aksv[1] = (aksv_lsb >> 8) & 0xFF;
+ aksv[2] = (aksv_lsb >> 16) & 0xFF;
+ aksv[3] = (aksv_lsb >> 24) & 0xFF;
+ aksv[4] = aksv_msb & 0xFF;
+
+ /* check there are 20 ones in AKSV */
+ if (sde_hdcp_1x_count_one(aksv, 5) != 20) {
+ pr_err("AKSV bit count failed\n");
+ rc = -EINVAL;
+ goto end;
+ }
+
+ DSS_REG_W(io, reg_set->aksv_lsb, aksv_lsb);
+ DSS_REG_W(io, reg_set->aksv_msb, aksv_msb);
+
+ /* Setup seed values for random number An */
+ DSS_REG_W(io, reg_set->entropy_ctrl0, 0xB1FFB0FF);
+ DSS_REG_W(io, reg_set->entropy_ctrl1, 0xF00DFACE);
+
+ /* make sure hw is programmed */
+ wmb();
+
+ /* enable hdcp engine */
+ DSS_REG_W(io, reg_set->ctrl, 0x1);
+
+ hdcp->hdcp_state = HDCP_STATE_AUTHENTICATING;
+end:
+ return rc;
+}
+
+static int sde_hdcp_1x_read(struct sde_hdcp_1x *hdcp,
+ struct sde_hdcp_sink_addr *sink,
+ u8 *buf, bool realign)
+{
+ int const max_size = 15;
+ int rc = 0, read_size = 0, bytes_read = 0;
+
+ if (hdcp->init_data.client_id == HDCP_CLIENT_DP) {
+ int size = sink->len, offset = sink->addr;
+
+ do {
+ read_size = min(size, max_size);
+
+ bytes_read = drm_dp_dpcd_read(hdcp->init_data.drm_aux,
+ offset, buf, read_size);
+ if (bytes_read != read_size) {
+ pr_err("fail: offset(0x%x), size(0x%x), rc(0x%x)\n",
+ offset, read_size, bytes_read);
+ break;
+ }
+
+ buf += read_size;
+ offset += read_size;
+ size -= read_size;
+ } while (size > 0);
+ }
+
+ return rc;
+}
+
+static int sde_hdcp_1x_write(struct sde_hdcp_1x *hdcp,
+ struct sde_hdcp_sink_addr *sink, u8 *buf)
+{
+ int const max_size = 16;
+ int rc = 0, write_size = 0, bytes_written = 0;
+
+ if (hdcp->init_data.client_id == HDCP_CLIENT_DP) {
+ int size = sink->len, offset = sink->addr;
+
+ do {
+ write_size = min(size, max_size);
+
+ bytes_written =
+ drm_dp_dpcd_write(hdcp->init_data.drm_aux,
+ offset, buf, write_size);
+ if (bytes_written != write_size) {
+ pr_err("fail: offset(0x%x), size(0x%x), rc(0x%x)\n",
+ offset, write_size, bytes_written);
+ break;
+ }
+
+ buf += write_size;
+ offset += write_size;
+ size -= write_size;
+ } while (size > 0);
+ }
+
+ return rc;
+}
+
+static void sde_hdcp_1x_enable_interrupts(struct sde_hdcp_1x *hdcp)
+{
+ u32 intr_reg;
+ struct dss_io_data *io;
+ struct sde_hdcp_int_set *isr;
+
+ io = hdcp->init_data.core_io;
+ isr = &hdcp->int_set;
+
+ intr_reg = DSS_REG_R(io, isr->int_reg);
+
+ intr_reg |= HDCP_INT_CLR | HDCP_INT_EN;
+
+ DSS_REG_W(io, isr->int_reg, intr_reg);
+}
+
+static int sde_hdcp_1x_read_bcaps(struct sde_hdcp_1x *hdcp)
+{
+ int rc;
+ struct sde_hdcp_reg_set *reg_set = &hdcp->reg_set;
+ struct dss_io_data *hdcp_io = hdcp->init_data.hdcp_io;
+
+ if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ pr_err("invalid state\n");
+ return -EINVAL;
+ }
+
+ rc = sde_hdcp_1x_read(hdcp, &hdcp->sink_addr.bcaps,
+ &hdcp->bcaps, false);
+ if (rc) {
+ pr_err("error reading bcaps\n");
+ goto error;
+ }
+
+ pr_debug("bcaps read: 0x%x\n", hdcp->bcaps);
+
+ hdcp->current_tp.ds_type = hdcp->bcaps & reg_set->repeater ?
+ DS_REPEATER : DS_RECEIVER;
+
+ pr_debug("ds: %s\n", hdcp->current_tp.ds_type == DS_REPEATER ?
+ "repeater" : "receiver");
+
+ /* Write BCAPS to the hardware */
+ DSS_REG_W(hdcp_io, reg_set->sec_data12, hdcp->bcaps);
+error:
+ return rc;
+}
+
+static int sde_hdcp_1x_wait_for_hw_ready(struct sde_hdcp_1x *hdcp)
+{
+ int rc;
+ u32 link0_status;
+ struct sde_hdcp_reg_set *reg_set = &hdcp->reg_set;
+ struct dss_io_data *io = hdcp->init_data.core_io;
+
+ if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ pr_err("invalid state\n");
+ return -EINVAL;
+ }
+
+ /* Wait for HDCP keys to be checked and validated */
+ rc = readl_poll_timeout(io->base + reg_set->status, link0_status,
+ ((link0_status >> reg_set->keys_offset) & 0x7)
+ == HDCP_KEYS_STATE_VALID ||
+ !sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING),
+ HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US);
+ if (rc) {
+ pr_err("key not ready\n");
+ goto error;
+ }
+
+ /*
+ * 1.1_Features turned off by default.
+ * No need to write AInfo since 1.1_Features is disabled.
+ */
+ DSS_REG_W(io, reg_set->data4, 0);
+
+ /* Wait for An0 and An1 bit to be ready */
+ rc = readl_poll_timeout(io->base + reg_set->status, link0_status,
+ (link0_status & (BIT(8) | BIT(9))) ||
+ !sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING),
+ HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US);
+ if (rc) {
+ pr_err("An not ready\n");
+ goto error;
+ }
+
+ /* As per hardware recommendations, wait before reading An */
+ msleep(20);
+error:
+ if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING))
+ rc = -EINVAL;
+
+ return rc;
+}
+
+static int sde_hdcp_1x_send_an_aksv_to_sink(struct sde_hdcp_1x *hdcp)
+{
+ int rc;
+ u8 an[8], aksv[5];
+
+ if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ pr_err("invalid state\n");
+ return -EINVAL;
+ }
+
+ an[0] = hdcp->an_0 & 0xFF;
+ an[1] = (hdcp->an_0 >> 8) & 0xFF;
+ an[2] = (hdcp->an_0 >> 16) & 0xFF;
+ an[3] = (hdcp->an_0 >> 24) & 0xFF;
+ an[4] = hdcp->an_1 & 0xFF;
+ an[5] = (hdcp->an_1 >> 8) & 0xFF;
+ an[6] = (hdcp->an_1 >> 16) & 0xFF;
+ an[7] = (hdcp->an_1 >> 24) & 0xFF;
+
+ pr_debug("an read: 0x%2x%2x%2x%2x%2x%2x%2x%2x\n",
+ an[7], an[6], an[5], an[4], an[3], an[2], an[1], an[0]);
+
+ rc = sde_hdcp_1x_write(hdcp, &hdcp->sink_addr.an, an);
+ if (rc) {
+ pr_err("error writing an to sink\n");
+ goto error;
+ }
+
+ /* Copy An and AKSV to byte arrays for transmission */
+ aksv[0] = hdcp->aksv_0 & 0xFF;
+ aksv[1] = (hdcp->aksv_0 >> 8) & 0xFF;
+ aksv[2] = (hdcp->aksv_0 >> 16) & 0xFF;
+ aksv[3] = (hdcp->aksv_0 >> 24) & 0xFF;
+ aksv[4] = hdcp->aksv_1 & 0xFF;
+
+ pr_debug("aksv read: 0x%2x%2x%2x%2x%2x\n",
+ aksv[4], aksv[3], aksv[2], aksv[1], aksv[0]);
+
+ rc = sde_hdcp_1x_write(hdcp, &hdcp->sink_addr.aksv, aksv);
+ if (rc) {
+ pr_err("error writing aksv to sink\n");
+ goto error;
+ }
+error:
+ return rc;
+}
+
+static int sde_hdcp_1x_read_an_aksv_from_hw(struct sde_hdcp_1x *hdcp)
+{
+ struct dss_io_data *io = hdcp->init_data.core_io;
+ struct sde_hdcp_reg_set *reg_set = &hdcp->reg_set;
+
+ if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ pr_err("invalid state\n");
+ return -EINVAL;
+ }
+
+ hdcp->an_0 = DSS_REG_R(io, reg_set->data5);
+ if (hdcp->init_data.client_id == HDCP_CLIENT_DP) {
+ udelay(1);
+ hdcp->an_0 = DSS_REG_R(io, reg_set->data5);
+ }
+
+ hdcp->an_1 = DSS_REG_R(io, reg_set->data6);
+ if (hdcp->init_data.client_id == HDCP_CLIENT_DP) {
+ udelay(1);
+ hdcp->an_1 = DSS_REG_R(io, reg_set->data6);
+ }
+
+ /* Read AKSV */
+ hdcp->aksv_0 = DSS_REG_R(io, reg_set->data3);
+ hdcp->aksv_1 = DSS_REG_R(io, reg_set->data4);
+
+ return 0;
+}
+
+static int sde_hdcp_1x_get_bksv_from_sink(struct sde_hdcp_1x *hdcp)
+{
+ int rc;
+ u8 *bksv = hdcp->current_tp.bksv;
+ u32 link0_bksv_0, link0_bksv_1;
+ struct sde_hdcp_reg_set *reg_set = &hdcp->reg_set;
+ struct dss_io_data *hdcp_io = hdcp->init_data.hdcp_io;
+
+ rc = sde_hdcp_1x_read(hdcp, &hdcp->sink_addr.bksv, bksv, false);
+ if (rc) {
+ pr_err("error reading bksv from sink\n");
+ goto error;
+ }
+
+ pr_debug("bksv read: 0x%2x%2x%2x%2x%2x\n",
+ bksv[4], bksv[3], bksv[2], bksv[1], bksv[0]);
+
+ /* check there are 20 ones in BKSV */
+ if (sde_hdcp_1x_count_one(bksv, 5) != 20) {
+ pr_err("%s: BKSV doesn't have 20 1's and 20 0's\n",
+ SDE_HDCP_STATE_NAME);
+ rc = -EINVAL;
+ goto error;
+ }
+
+ link0_bksv_0 = bksv[3];
+ link0_bksv_0 = (link0_bksv_0 << 8) | bksv[2];
+ link0_bksv_0 = (link0_bksv_0 << 8) | bksv[1];
+ link0_bksv_0 = (link0_bksv_0 << 8) | bksv[0];
+ link0_bksv_1 = bksv[4];
+
+ DSS_REG_W(hdcp_io, reg_set->sec_data0, link0_bksv_0);
+ DSS_REG_W(hdcp_io, reg_set->sec_data1, link0_bksv_1);
+error:
+ return rc;
+}
+
+static void sde_hdcp_1x_enable_sink_irq_hpd(struct sde_hdcp_1x *hdcp)
+{
+ u8 const required_major = 1, required_minor = 2;
+ u8 sink_major = 0, sink_minor = 0;
+ u8 enable_hpd_irq = 0x1;
+ int rc;
+ unsigned char revision = *hdcp->init_data.revision;
+
+ sink_major = (revision >> 4) & 0x0f;
+ sink_minor = revision & 0x0f;
+ pr_debug("revision: %d.%d\n", sink_major, sink_minor);
+
+ if ((sink_minor < required_minor) || (sink_major < required_major) ||
+ (hdcp->current_tp.ds_type != DS_REPEATER)) {
+ pr_debug("sink irq hpd not enabled\n");
+ return;
+ }
+
+ rc = sde_hdcp_1x_write(hdcp, &hdcp->sink_addr.ainfo, &enable_hpd_irq);
+ if (rc)
+ pr_debug("error writing ainfo to sink\n");
+}
+
+static int sde_hdcp_1x_verify_r0(struct sde_hdcp_1x *hdcp)
+{
+ int rc, r0_retry = 3;
+ u8 buf[2];
+ u32 link0_status, timeout_count;
+ u32 const r0_read_delay_us = 1;
+ u32 const r0_read_timeout_us = r0_read_delay_us * 10;
+ struct sde_hdcp_reg_set *reg_set = &hdcp->reg_set;
+ struct dss_io_data *io = hdcp->init_data.core_io;
+
+ if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ pr_err("invalid state\n");
+ return -EINVAL;
+ }
+
+ /* Wait for HDCP R0 computation to be completed */
+ rc = readl_poll_timeout(io->base + reg_set->status, link0_status,
+ (link0_status & BIT(reg_set->r0_offset)) ||
+ !sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING),
+ HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US);
+ if (rc) {
+ pr_err("R0 not ready\n");
+ goto error;
+ }
+
+ /*
+ * HDCP Compliace Test case 1A-01:
+ * Wait here at least 100ms before reading R0'
+ */
+ if (hdcp->init_data.client_id == HDCP_CLIENT_HDMI) {
+ msleep(100);
+ } else {
+ if (!hdcp->sink_r0_ready) {
+ reinit_completion(&hdcp->sink_r0_available);
+ timeout_count = wait_for_completion_timeout(
+ &hdcp->sink_r0_available, HZ / 2);
+
+ if (hdcp->reauth) {
+ pr_err("sink R0 not ready\n");
+ rc = -EINVAL;
+ goto error;
+ }
+ }
+ }
+
+ do {
+ memset(buf, 0, sizeof(buf));
+
+ rc = sde_hdcp_1x_read(hdcp, &hdcp->sink_addr.r0,
+ buf, false);
+ if (rc) {
+ pr_err("error reading R0' from sink\n");
+ goto error;
+ }
+
+ pr_debug("sink R0'read: %2x%2x\n", buf[1], buf[0]);
+
+ DSS_REG_W(io, reg_set->data2_0, (((u32)buf[1]) << 8) | buf[0]);
+
+ rc = readl_poll_timeout(io->base + reg_set->status,
+ link0_status, (link0_status & BIT(12)) ||
+ !sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING),
+ r0_read_delay_us, r0_read_timeout_us);
+ } while (rc && --r0_retry);
+error:
+ if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING))
+ rc = -EINVAL;
+
+ return rc;
+}
+
+static int sde_hdcp_1x_authentication_part1(struct sde_hdcp_1x *hdcp)
+{
+ int rc;
+
+ if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ pr_err("invalid state\n");
+ return -EINVAL;
+ }
+
+ sde_hdcp_1x_enable_interrupts(hdcp);
+
+ rc = sde_hdcp_1x_read_bcaps(hdcp);
+ if (rc)
+ goto error;
+
+ rc = sde_hdcp_1x_wait_for_hw_ready(hdcp);
+ if (rc)
+ goto error;
+
+ rc = sde_hdcp_1x_read_an_aksv_from_hw(hdcp);
+ if (rc)
+ goto error;
+
+ rc = sde_hdcp_1x_get_bksv_from_sink(hdcp);
+ if (rc)
+ goto error;
+
+ rc = sde_hdcp_1x_send_an_aksv_to_sink(hdcp);
+ if (rc)
+ goto error;
+
+ sde_hdcp_1x_enable_sink_irq_hpd(hdcp);
+
+ rc = sde_hdcp_1x_verify_r0(hdcp);
+ if (rc)
+ goto error;
+
+ pr_info("SUCCESSFUL\n");
+
+ return 0;
+error:
+ pr_err("%s: FAILED\n", SDE_HDCP_STATE_NAME);
+
+ return rc;
+}
+
+static int sde_hdcp_1x_transfer_v_h(struct sde_hdcp_1x *hdcp)
+{
+ int rc = 0;
+ struct dss_io_data *io = hdcp->init_data.hdcp_io;
+ struct sde_hdcp_reg_set *reg_set = &hdcp->reg_set;
+ struct sde_hdcp_1x_reg_data reg_data[] = {
+ {reg_set->sec_data7, &hdcp->sink_addr.v_h0},
+ {reg_set->sec_data8, &hdcp->sink_addr.v_h1},
+ {reg_set->sec_data9, &hdcp->sink_addr.v_h2},
+ {reg_set->sec_data10, &hdcp->sink_addr.v_h3},
+ {reg_set->sec_data11, &hdcp->sink_addr.v_h4},
+ };
+ struct sde_hdcp_sink_addr sink = {"V", reg_data->sink->addr};
+ u32 size = ARRAY_SIZE(reg_data);
+ u8 buf[0xFF] = {0};
+ u32 i = 0, len = 0;
+
+ if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ pr_err("invalid state\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < size; i++) {
+ struct sde_hdcp_1x_reg_data *rd = reg_data + i;
+
+ len += rd->sink->len;
+ }
+
+ sink.len = len;
+
+ rc = sde_hdcp_1x_read(hdcp, &sink, buf, false);
+ if (rc) {
+ pr_err("error reading %s\n", sink.name);
+ goto end;
+ }
+
+ for (i = 0; i < size; i++) {
+ struct sde_hdcp_1x_reg_data *rd = reg_data + i;
+ u32 reg_data;
+
+ memcpy(®_data, buf + (sizeof(u32) * i), sizeof(u32));
+ DSS_REG_W(io, rd->reg_id, reg_data);
+ }
+end:
+ return rc;
+}
+
+static int sde_hdcp_1x_validate_downstream(struct sde_hdcp_1x *hdcp)
+{
+ int rc;
+ u8 buf[2] = {0, 0};
+ u8 device_count, depth;
+ u8 max_cascade_exceeded, max_devs_exceeded;
+ u16 bstatus;
+ struct sde_hdcp_reg_set *reg_set = &hdcp->reg_set;
+
+ if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ pr_err("invalid state\n");
+ return -EINVAL;
+ }
+
+ rc = sde_hdcp_1x_read(hdcp, &hdcp->sink_addr.bstatus,
+ buf, false);
+ if (rc) {
+ pr_err("error reading bstatus\n");
+ goto end;
+ }
+
+ bstatus = buf[1];
+ bstatus = (bstatus << 8) | buf[0];
+
+ device_count = bstatus & 0x7F;
+
+ pr_debug("device count %d\n", device_count);
+
+ /* Cascaded repeater depth */
+ depth = (bstatus >> 8) & 0x7;
+ pr_debug("depth %d\n", depth);
+
+ /*
+ * HDCP Compliance 1B-05:
+ * Check if no. of devices connected to repeater
+ * exceed max_devices_connected from bit 7 of Bstatus.
+ */
+ max_devs_exceeded = (bstatus & BIT(7)) >> 7;
+ if (max_devs_exceeded == 0x01) {
+ pr_err("no. of devs connected exceed max allowed\n");
+ rc = -EINVAL;
+ goto end;
+ }
+
+ /*
+ * HDCP Compliance 1B-06:
+ * Check if no. of cascade connected to repeater
+ * exceed max_cascade_connected from bit 11 of Bstatus.
+ */
+ max_cascade_exceeded = (bstatus & BIT(11)) >> 11;
+ if (max_cascade_exceeded == 0x01) {
+ pr_err("no. of cascade connections exceed max allowed\n");
+ rc = -EINVAL;
+ goto end;
+ }
+
+ /* Update topology information */
+ hdcp->current_tp.dev_count = device_count;
+ hdcp->current_tp.max_cascade_exceeded = max_cascade_exceeded;
+ hdcp->current_tp.max_dev_exceeded = max_devs_exceeded;
+ hdcp->current_tp.depth = depth;
+
+ DSS_REG_W(hdcp->init_data.hdcp_io,
+ reg_set->sec_data12, hdcp->bcaps | (bstatus << 8));
+end:
+ return rc;
+}
+
+static int sde_hdcp_1x_read_ksv_fifo(struct sde_hdcp_1x *hdcp)
+{
+ u32 ksv_read_retry = 20, ksv_bytes, rc = 0;
+ u8 *ksv_fifo = hdcp->current_tp.ksv_list;
+
+ if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ pr_err("invalid state\n");
+ return -EINVAL;
+ }
+
+ memset(ksv_fifo, 0, sizeof(hdcp->current_tp.ksv_list));
+
+ /* each KSV is 5 bytes long */
+ ksv_bytes = 5 * hdcp->current_tp.dev_count;
+ hdcp->sink_addr.ksv_fifo.len = ksv_bytes;
+
+ while (ksv_bytes && --ksv_read_retry) {
+ rc = sde_hdcp_1x_read(hdcp, &hdcp->sink_addr.ksv_fifo,
+ ksv_fifo, true);
+ if (rc)
+ pr_err("could not read ksv fifo (%d)\n",
+ ksv_read_retry);
+ else
+ break;
+ }
+
+ if (rc)
+ pr_err("error reading ksv_fifo\n");
+
+ return rc;
+}
+
+static int sde_hdcp_1x_write_ksv_fifo(struct sde_hdcp_1x *hdcp)
+{
+ int i, rc = 0;
+ u8 *ksv_fifo = hdcp->current_tp.ksv_list;
+ u32 ksv_bytes = hdcp->sink_addr.ksv_fifo.len;
+ struct dss_io_data *io = hdcp->init_data.core_io;
+ struct dss_io_data *sec_io = hdcp->init_data.hdcp_io;
+ struct sde_hdcp_reg_set *reg_set = &hdcp->reg_set;
+ u32 sha_status = 0, status;
+
+ if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ pr_err("invalid state\n");
+ return -EINVAL;
+ }
+
+ /* reset SHA Controller */
+ DSS_REG_W(sec_io, reg_set->sec_sha_ctrl, 0x1);
+ DSS_REG_W(sec_io, reg_set->sec_sha_ctrl, 0x0);
+
+ for (i = 0; i < ksv_bytes - 1; i++) {
+ /* Write KSV byte and do not set DONE bit[0] */
+ DSS_REG_W_ND(sec_io, reg_set->sec_sha_data, ksv_fifo[i] << 16);
+
+ /*
+ * Once 64 bytes have been written, we need to poll for
+ * HDCP_SHA_BLOCK_DONE before writing any further
+ */
+ if (i && !((i + 1) % 64)) {
+ rc = readl_poll_timeout(io->base + reg_set->sha_status,
+ sha_status, (sha_status & BIT(0)) ||
+ !sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING),
+ HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US);
+ if (rc) {
+ pr_err("block not done\n");
+ goto error;
+ }
+ }
+ }
+
+ /* Write l to DONE bit[0] */
+ DSS_REG_W_ND(sec_io, reg_set->sec_sha_data,
+ (ksv_fifo[ksv_bytes - 1] << 16) | 0x1);
+
+ /* Now wait for HDCP_SHA_COMP_DONE */
+ rc = readl_poll_timeout(io->base + reg_set->sha_status, sha_status,
+ (sha_status & BIT(4)) ||
+ !sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING),
+ HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US);
+ if (rc) {
+ pr_err("V computation not done\n");
+ goto error;
+ }
+
+ /* Wait for V_MATCHES */
+ rc = readl_poll_timeout(io->base + reg_set->status, status,
+ (status & BIT(reg_set->v_offset)) ||
+ !sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING),
+ HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US);
+ if (rc) {
+ pr_err("V mismatch\n");
+ rc = -EINVAL;
+ }
+error:
+ if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING))
+ rc = -EINVAL;
+
+ return rc;
+}
+
+static int sde_hdcp_1x_wait_for_ksv_ready(struct sde_hdcp_1x *hdcp)
+{
+ int rc, timeout;
+
+ if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ pr_err("invalid state\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Wait until READY bit is set in BCAPS, as per HDCP specifications
+ * maximum permitted time to check for READY bit is five seconds.
+ */
+ rc = sde_hdcp_1x_read(hdcp, &hdcp->sink_addr.bcaps,
+ &hdcp->bcaps, false);
+ if (rc) {
+ pr_err("error reading bcaps\n");
+ goto error;
+ }
+
+ if (hdcp->init_data.client_id == HDCP_CLIENT_HDMI) {
+ timeout = 50;
+
+ while (!(hdcp->bcaps & BIT(5)) && --timeout) {
+ rc = sde_hdcp_1x_read(hdcp,
+ &hdcp->sink_addr.bcaps,
+ &hdcp->bcaps, false);
+ if (rc ||
+ !sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ pr_err("error reading bcaps\n");
+ goto error;
+ }
+ msleep(100);
+ }
+ } else {
+ u8 cp_buf = 0;
+ struct sde_hdcp_sink_addr *sink =
+ &hdcp->sink_addr.cp_irq_status;
+
+ timeout = jiffies_to_msecs(jiffies);
+
+ while (1) {
+ rc = sde_hdcp_1x_read(hdcp, sink, &cp_buf, false);
+ if (rc)
+ goto error;
+
+ if (cp_buf & BIT(0))
+ break;
+
+ /* max timeout of 5 sec as per hdcp 1.x spec */
+ if (abs(timeout - jiffies_to_msecs(jiffies)) > 5000) {
+ timeout = 0;
+ break;
+ }
+
+ if (hdcp->ksv_ready || hdcp->reauth ||
+ !sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING))
+ break;
+
+ /* re-read after a minimum delay */
+ msleep(20);
+ }
+ }
+
+ if (!timeout || hdcp->reauth ||
+ !sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ pr_err("DS KSV not ready\n");
+ rc = -EINVAL;
+ } else {
+ hdcp->ksv_ready = true;
+ }
+error:
+ return rc;
+}
+
+static int sde_hdcp_1x_authentication_part2(struct sde_hdcp_1x *hdcp)
+{
+ int rc;
+ int v_retry = 3;
+
+ rc = sde_hdcp_1x_validate_downstream(hdcp);
+ if (rc)
+ goto error;
+
+ rc = sde_hdcp_1x_read_ksv_fifo(hdcp);
+ if (rc)
+ goto error;
+
+ do {
+ rc = sde_hdcp_1x_transfer_v_h(hdcp);
+ if (rc)
+ goto error;
+
+ /* do not proceed further if no device connected */
+ if (!hdcp->current_tp.dev_count)
+ goto error;
+
+ rc = sde_hdcp_1x_write_ksv_fifo(hdcp);
+ } while (--v_retry && rc);
+error:
+ if (rc) {
+ pr_err("%s: FAILED\n", SDE_HDCP_STATE_NAME);
+ } else {
+ hdcp->hdcp_state = HDCP_STATE_AUTHENTICATED;
+
+ pr_info("SUCCESSFUL\n");
+ }
+
+ return rc;
+}
+
+static void sde_hdcp_1x_cache_topology(struct sde_hdcp_1x *hdcp)
+{
+ if (!hdcp || !hdcp->init_data.core_io) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ memcpy((void *)&hdcp->cached_tp,
+ (void *) &hdcp->current_tp,
+ sizeof(hdcp->cached_tp));
+ hdcp1_cache_repeater_topology((void *)&hdcp->cached_tp);
+}
+
+static void sde_hdcp_1x_notify_topology(void)
+{
+ hdcp1_notify_topology();
+}
+
+static void sde_hdcp_1x_update_auth_status(struct sde_hdcp_1x *hdcp)
+{
+ if (sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATED)) {
+ sde_hdcp_1x_cache_topology(hdcp);
+ sde_hdcp_1x_notify_topology();
+ }
+
+ if (hdcp->init_data.notify_status &&
+ !sde_hdcp_1x_state(HDCP_STATE_INACTIVE)) {
+ hdcp->init_data.notify_status(
+ hdcp->init_data.cb_data,
+ hdcp->hdcp_state);
+ }
+}
+
+static void sde_hdcp_1x_auth_work(struct work_struct *work)
+{
+ int rc;
+ struct delayed_work *dw = to_delayed_work(work);
+ struct sde_hdcp_1x *hdcp = container_of(dw,
+ struct sde_hdcp_1x, hdcp_auth_work);
+ struct dss_io_data *io;
+
+ if (!hdcp) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ pr_err("invalid state\n");
+ return;
+ }
+
+ hdcp->sink_r0_ready = false;
+ hdcp->reauth = false;
+ hdcp->ksv_ready = false;
+
+ io = hdcp->init_data.core_io;
+ /* Enabling Software DDC for HDMI and REF timer for DP */
+ if (hdcp->init_data.client_id == HDCP_CLIENT_HDMI)
+ DSS_REG_W_ND(io, REG_HDMI_DDC_ARBITRATION, DSS_REG_R(io,
+ REG_HDMI_DDC_ARBITRATION) & ~(BIT(4)));
+ else if (hdcp->init_data.client_id == HDCP_CLIENT_DP) {
+ DSS_REG_W(io, DP_DP_HPD_REFTIMER, 0x10013);
+ }
+
+ /*
+ * program hw to enable encryption as soon as
+ * authentication is successful.
+ */
+ hdcp1_set_enc(true);
+
+ rc = sde_hdcp_1x_authentication_part1(hdcp);
+ if (rc)
+ goto end;
+
+ if (hdcp->current_tp.ds_type == DS_REPEATER) {
+ rc = sde_hdcp_1x_wait_for_ksv_ready(hdcp);
+ if (rc)
+ goto end;
+ } else {
+ hdcp->hdcp_state = HDCP_STATE_AUTHENTICATED;
+ goto end;
+ }
+
+ hdcp->ksv_ready = false;
+
+ rc = sde_hdcp_1x_authentication_part2(hdcp);
+ if (rc)
+ goto end;
+
+ /*
+ * Disabling software DDC before going into part3 to make sure
+ * there is no Arbitration between software and hardware for DDC
+ */
+ if (hdcp->init_data.client_id == HDCP_CLIENT_HDMI)
+ DSS_REG_W_ND(io, REG_HDMI_DDC_ARBITRATION, DSS_REG_R(io,
+ REG_HDMI_DDC_ARBITRATION) | (BIT(4)));
+end:
+ if (rc && !sde_hdcp_1x_state(HDCP_STATE_INACTIVE))
+ hdcp->hdcp_state = HDCP_STATE_AUTH_FAIL;
+
+ sde_hdcp_1x_update_auth_status(hdcp);
+}
+
+static int sde_hdcp_1x_authenticate(void *input)
+{
+ struct sde_hdcp_1x *hdcp = (struct sde_hdcp_1x *)input;
+
+ if (!hdcp) {
+ pr_err("invalid input\n");
+ return -EINVAL;
+ }
+
+ flush_delayed_work(&hdcp->hdcp_auth_work);
+
+ if (!sde_hdcp_1x_state(HDCP_STATE_INACTIVE)) {
+ pr_err("invalid state\n");
+ return -EINVAL;
+ }
+
+ if (!sde_hdcp_1x_load_keys(input)) {
+
+ queue_delayed_work(hdcp->workq,
+ &hdcp->hdcp_auth_work, HZ/2);
+ } else {
+ hdcp->hdcp_state = HDCP_STATE_AUTH_FAIL;
+ sde_hdcp_1x_update_auth_status(hdcp);
+ }
+
+ return 0;
+} /* hdcp_1x_authenticate */
+
+static int sde_hdcp_1x_reauthenticate(void *input)
+{
+ struct sde_hdcp_1x *hdcp = (struct sde_hdcp_1x *)input;
+ struct dss_io_data *io;
+ struct sde_hdcp_reg_set *reg_set;
+ struct sde_hdcp_int_set *isr;
+ u32 ret = 0, reg;
+
+ if (!hdcp || !hdcp->init_data.core_io) {
+ pr_err("invalid input\n");
+ return -EINVAL;
+ }
+
+ io = hdcp->init_data.core_io;
+ reg_set = &hdcp->reg_set;
+ isr = &hdcp->int_set;
+
+ if (!sde_hdcp_1x_state(HDCP_STATE_AUTH_FAIL)) {
+ pr_err("invalid state\n");
+ return -EINVAL;
+ }
+
+ /* Disable HDCP interrupts */
+ DSS_REG_W(io, isr->int_reg, DSS_REG_R(io, isr->int_reg) & ~HDCP_INT_EN);
+
+ reg = DSS_REG_R(io, reg_set->reset);
+ DSS_REG_W(io, reg_set->reset, reg | reg_set->reset_bit);
+
+ /* Disable encryption and disable the HDCP block */
+ DSS_REG_W(io, reg_set->ctrl, 0);
+
+ DSS_REG_W(io, reg_set->reset, reg & ~reg_set->reset_bit);
+
+ hdcp->hdcp_state = HDCP_STATE_INACTIVE;
+ sde_hdcp_1x_authenticate(hdcp);
+
+ return ret;
+} /* hdcp_1x_reauthenticate */
+
+static void sde_hdcp_1x_off(void *input)
+{
+ struct sde_hdcp_1x *hdcp = (struct sde_hdcp_1x *)input;
+ struct dss_io_data *io;
+ struct sde_hdcp_reg_set *reg_set;
+ struct sde_hdcp_int_set *isr;
+ int rc = 0;
+ u32 reg;
+
+ if (!hdcp || !hdcp->init_data.core_io) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ io = hdcp->init_data.core_io;
+ reg_set = &hdcp->reg_set;
+ isr = &hdcp->int_set;
+
+ if (sde_hdcp_1x_state(HDCP_STATE_INACTIVE)) {
+ pr_err("invalid state\n");
+ return;
+ }
+
+ /*
+ * Disable HDCP interrupts.
+ * Also, need to set the state to inactive here so that any ongoing
+ * reauth works will know that the HDCP session has been turned off.
+ */
+ mutex_lock(hdcp->init_data.mutex);
+ DSS_REG_W(io, isr->int_reg,
+ DSS_REG_R(io, isr->int_reg) & ~HDCP_INT_EN);
+ hdcp->hdcp_state = HDCP_STATE_INACTIVE;
+ mutex_unlock(hdcp->init_data.mutex);
+
+ /* complete any wait pending */
+ complete_all(&hdcp->sink_r0_available);
+ complete_all(&hdcp->r0_checked);
+ /*
+ * Cancel any pending auth/reauth attempts.
+ * If one is ongoing, this will wait for it to finish.
+ * No more reauthentiaction attempts will be scheduled since we
+ * set the currect state to inactive.
+ */
+ rc = cancel_delayed_work_sync(&hdcp->hdcp_auth_work);
+ if (rc)
+ pr_debug("%s: Deleted hdcp auth work\n",
+ SDE_HDCP_STATE_NAME);
+
+ hdcp1_set_enc(false);
+
+ reg = DSS_REG_R(io, reg_set->reset);
+ DSS_REG_W(io, reg_set->reset, reg | reg_set->reset_bit);
+
+ /* Disable encryption and disable the HDCP block */
+ DSS_REG_W(io, reg_set->ctrl, 0);
+
+ DSS_REG_W(io, reg_set->reset, reg & ~reg_set->reset_bit);
+
+ hdcp->sink_r0_ready = false;
+
+ pr_debug("%s: HDCP: Off\n", SDE_HDCP_STATE_NAME);
+} /* hdcp_1x_off */
+
+static int sde_hdcp_1x_isr(void *input)
+{
+ struct sde_hdcp_1x *hdcp = (struct sde_hdcp_1x *)input;
+ int rc = 0;
+ struct dss_io_data *io;
+ u32 hdcp_int_val;
+ struct sde_hdcp_reg_set *reg_set;
+ struct sde_hdcp_int_set *isr;
+
+ if (!hdcp || !hdcp->init_data.core_io) {
+ pr_err("invalid input\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ io = hdcp->init_data.core_io;
+ reg_set = &hdcp->reg_set;
+ isr = &hdcp->int_set;
+
+ hdcp_int_val = DSS_REG_R(io, isr->int_reg);
+
+ /* Ignore HDCP interrupts if HDCP is disabled */
+ if (sde_hdcp_1x_state(HDCP_STATE_INACTIVE)) {
+ DSS_REG_W(io, isr->int_reg, hdcp_int_val | HDCP_INT_CLR);
+ return 0;
+ }
+
+ if (hdcp_int_val & isr->auth_success_int) {
+ /* AUTH_SUCCESS_INT */
+ DSS_REG_W(io, isr->int_reg,
+ (hdcp_int_val | isr->auth_success_ack));
+ pr_debug("%s: AUTH SUCCESS\n", SDE_HDCP_STATE_NAME);
+
+ if (sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING))
+ complete_all(&hdcp->r0_checked);
+ }
+
+ if (hdcp_int_val & isr->auth_fail_int) {
+ /* AUTH_FAIL_INT */
+ u32 link_status = DSS_REG_R(io, reg_set->status);
+
+ DSS_REG_W(io, isr->int_reg,
+ (hdcp_int_val | isr->auth_fail_ack));
+
+ pr_debug("%s: AUTH FAIL, LINK0_STATUS=0x%08x\n",
+ SDE_HDCP_STATE_NAME, link_status);
+
+ if (sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATED)) {
+ hdcp->hdcp_state = HDCP_STATE_AUTH_FAIL;
+ sde_hdcp_1x_update_auth_status(hdcp);
+ } else if (sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ complete_all(&hdcp->r0_checked);
+ }
+
+ /* Clear AUTH_FAIL_INFO as well */
+ DSS_REG_W(io, isr->int_reg,
+ (hdcp_int_val | isr->auth_fail_info_ack));
+ }
+
+ if (hdcp_int_val & isr->tx_req_int) {
+ /* DDC_XFER_REQ_INT */
+ DSS_REG_W(io, isr->int_reg,
+ (hdcp_int_val | isr->tx_req_ack));
+ pr_debug("%s: DDC_XFER_REQ_INT received\n",
+ SDE_HDCP_STATE_NAME);
+ }
+
+ if (hdcp_int_val & isr->tx_req_done_int) {
+ /* DDC_XFER_DONE_INT */
+ DSS_REG_W(io, isr->int_reg,
+ (hdcp_int_val | isr->tx_req_done_ack));
+ pr_debug("%s: DDC_XFER_DONE received\n",
+ SDE_HDCP_STATE_NAME);
+ }
+
+ if (hdcp_int_val & isr->encryption_ready) {
+ /* Encryption enabled */
+ DSS_REG_W(io, isr->int_reg,
+ (hdcp_int_val | isr->encryption_ready_ack));
+ pr_debug("%s: encryption ready received\n",
+ SDE_HDCP_STATE_NAME);
+ }
+
+ if (hdcp_int_val & isr->encryption_not_ready) {
+ /* Encryption enabled */
+ DSS_REG_W(io, isr->int_reg,
+ (hdcp_int_val | isr->encryption_not_ready_ack));
+ pr_debug("%s: encryption not ready received\n",
+ SDE_HDCP_STATE_NAME);
+ }
+
+error:
+ return rc;
+}
+
+void sde_hdcp_1x_deinit(void *input)
+{
+ struct sde_hdcp_1x *hdcp = (struct sde_hdcp_1x *)input;
+
+ if (!hdcp) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ if (hdcp->workq)
+ destroy_workqueue(hdcp->workq);
+
+ kfree(hdcp);
+} /* hdcp_1x_deinit */
+
+static void sde_hdcp_1x_update_client_reg_set(struct sde_hdcp_1x *hdcp)
+{
+ if (hdcp->init_data.client_id == HDCP_CLIENT_DP) {
+ struct sde_hdcp_reg_set reg_set = HDCP_REG_SET_CLIENT_DP;
+ struct sde_hdcp_sink_addr_map sink_addr = HDCP_DP_SINK_ADDR_MAP;
+ struct sde_hdcp_int_set isr = HDCP_DP_INT_SET;
+
+ hdcp->reg_set = reg_set;
+ hdcp->sink_addr = sink_addr;
+ hdcp->int_set = isr;
+ }
+}
+
+static bool sde_hdcp_1x_is_cp_irq_raised(struct sde_hdcp_1x *hdcp)
+{
+ int ret;
+ u8 buf = 0;
+ struct sde_hdcp_sink_addr sink = {"irq", 0x201, 1};
+
+ ret = sde_hdcp_1x_read(hdcp, &sink, &buf, false);
+ if (ret)
+ pr_err("error reading irq_vector\n");
+
+ return buf & BIT(2) ? true : false;
+}
+
+static void sde_hdcp_1x_clear_cp_irq(struct sde_hdcp_1x *hdcp)
+{
+ int ret;
+ u8 buf = BIT(2);
+ struct sde_hdcp_sink_addr sink = {"irq", 0x201, 1};
+
+ ret = sde_hdcp_1x_write(hdcp, &sink, &buf);
+ if (ret)
+ pr_err("error clearing irq_vector\n");
+}
+
+static int sde_hdcp_1x_cp_irq(void *input)
+{
+ struct sde_hdcp_1x *hdcp = (struct sde_hdcp_1x *)input;
+ u8 buf = 0;
+ int ret;
+
+ if (!hdcp) {
+ pr_err("invalid input\n");
+ goto irq_not_handled;
+ }
+
+ if (!sde_hdcp_1x_is_cp_irq_raised(hdcp)) {
+ pr_debug("cp_irq not raised\n");
+ goto irq_not_handled;
+ }
+
+ ret = sde_hdcp_1x_read(hdcp, &hdcp->sink_addr.cp_irq_status,
+ &buf, false);
+ if (ret) {
+ pr_err("error reading cp_irq_status\n");
+ goto irq_not_handled;
+ }
+
+ if ((buf & BIT(2)) || (buf & BIT(3))) {
+ pr_err("%s\n",
+ buf & BIT(2) ? "LINK_INTEGRITY_FAILURE" :
+ "REAUTHENTICATION_REQUEST");
+
+ hdcp->reauth = true;
+
+ if (!sde_hdcp_1x_state(HDCP_STATE_INACTIVE))
+ hdcp->hdcp_state = HDCP_STATE_AUTH_FAIL;
+
+ complete_all(&hdcp->sink_r0_available);
+ sde_hdcp_1x_update_auth_status(hdcp);
+ } else if (buf & BIT(1)) {
+ pr_debug("R0' AVAILABLE\n");
+ hdcp->sink_r0_ready = true;
+ complete_all(&hdcp->sink_r0_available);
+ } else if ((buf & BIT(0))) {
+ pr_debug("KSVs READY\n");
+
+ hdcp->ksv_ready = true;
+ } else {
+ pr_debug("spurious interrupt\n");
+ }
+
+ sde_hdcp_1x_clear_cp_irq(hdcp);
+ return 0;
+
+irq_not_handled:
+ return -EINVAL;
+}
+
+void *sde_hdcp_1x_init(struct sde_hdcp_init_data *init_data)
+{
+ struct sde_hdcp_1x *hdcp = NULL;
+ char name[20];
+ static struct sde_hdcp_ops ops = {
+ .isr = sde_hdcp_1x_isr,
+ .cp_irq = sde_hdcp_1x_cp_irq,
+ .reauthenticate = sde_hdcp_1x_reauthenticate,
+ .authenticate = sde_hdcp_1x_authenticate,
+ .off = sde_hdcp_1x_off
+ };
+
+ if (!init_data || !init_data->core_io || !init_data->qfprom_io ||
+ !init_data->mutex || !init_data->notify_status ||
+ !init_data->workq || !init_data->cb_data) {
+ pr_err("invalid input\n");
+ goto error;
+ }
+
+ if (init_data->sec_access && !init_data->hdcp_io) {
+ pr_err("hdcp_io required\n");
+ goto error;
+ }
+
+ hdcp = kzalloc(sizeof(*hdcp), GFP_KERNEL);
+ if (!hdcp)
+ goto error;
+
+ hdcp->init_data = *init_data;
+ hdcp->ops = &ops;
+
+ snprintf(name, sizeof(name), "hdcp_1x_%d",
+ hdcp->init_data.client_id);
+
+ hdcp->workq = create_workqueue(name);
+ if (!hdcp->workq) {
+ pr_err("Error creating workqueue\n");
+ kfree(hdcp);
+ goto error;
+ }
+
+ sde_hdcp_1x_update_client_reg_set(hdcp);
+
+ INIT_DELAYED_WORK(&hdcp->hdcp_auth_work, sde_hdcp_1x_auth_work);
+
+ hdcp->hdcp_state = HDCP_STATE_INACTIVE;
+ init_completion(&hdcp->r0_checked);
+ init_completion(&hdcp->sink_r0_available);
+
+ pr_debug("HDCP module initialized. HDCP_STATE=%s\n",
+ SDE_HDCP_STATE_NAME);
+
+ return (void *)hdcp;
+
+error:
+ return NULL;
+} /* hdcp_1x_init */
+
+struct sde_hdcp_ops *sde_hdcp_1x_start(void *input)
+{
+ return ((struct sde_hdcp_1x *)input)->ops;
+}
diff --git a/drivers/gpu/drm/msm/sde_power_handle.c b/drivers/gpu/drm/msm/sde_power_handle.c
index 28a2d4d..e5c83cb 100644
--- a/drivers/gpu/drm/msm/sde_power_handle.c
+++ b/drivers/gpu/drm/msm/sde_power_handle.c
@@ -76,7 +76,7 @@
if (phandle->rsc_client)
ret = sde_rsc_client_state_update(phandle->rsc_client,
- rsc_state, NULL, -1);
+ rsc_state, NULL, SDE_RSC_INVALID_CRTC_ID, NULL);
return ret;
}
diff --git a/drivers/gpu/drm/msm/sde_power_handle.h b/drivers/gpu/drm/msm/sde_power_handle.h
index 78c325d..9cbffa5 100644
--- a/drivers/gpu/drm/msm/sde_power_handle.h
+++ b/drivers/gpu/drm/msm/sde_power_handle.h
@@ -16,7 +16,7 @@
#define MAX_CLIENT_NAME_LEN 128
-#define SDE_POWER_HANDLE_ENABLE_BUS_AB_QUOTA 1600000000
+#define SDE_POWER_HANDLE_ENABLE_BUS_AB_QUOTA 0
#define SDE_POWER_HANDLE_DISABLE_BUS_AB_QUOTA 0
#define SDE_POWER_HANDLE_ENABLE_BUS_IB_QUOTA 1600000000
#define SDE_POWER_HANDLE_DISABLE_BUS_IB_QUOTA 0
diff --git a/drivers/gpu/drm/msm/sde_rsc.c b/drivers/gpu/drm/msm/sde_rsc.c
index 54bdd42..7a52ece 100644
--- a/drivers/gpu/drm/msm/sde_rsc.c
+++ b/drivers/gpu/drm/msm/sde_rsc.c
@@ -58,12 +58,8 @@
#define TRY_CLK_MODE_SWITCH 0xFFFE
#define STATE_UPDATE_NOT_ALLOWED 0xFFFD
-/**
- * Expected primary command mode panel vsync ranges
- * Note: update if a primary panel is expected to run lower than 60fps
- */
-#define PRIMARY_VBLANK_MIN_US (18 * 1000)
-#define PRIMARY_VBLANK_MAX_US (20 * 1000)
+/* Primary panel worst case VSYNC expected to be no less than 30fps */
+#define PRIMARY_VBLANK_WORST_CASE_MS 34
static struct sde_rsc_priv *rsc_prv_list[MAX_RSC_COUNT];
@@ -153,9 +149,22 @@
state = client->current_state;
mutex_unlock(&rsc->client_lock);
- if (state != SDE_RSC_IDLE_STATE)
- sde_rsc_client_state_update(client, SDE_RSC_IDLE_STATE,
- NULL, -1);
+ if (state != SDE_RSC_IDLE_STATE) {
+ int wait_vblank_crtc_id;
+
+ sde_rsc_client_state_update(client, SDE_RSC_IDLE_STATE, NULL,
+ SDE_RSC_INVALID_CRTC_ID, &wait_vblank_crtc_id);
+
+ /* if vblank wait required at shutdown, use a simple sleep */
+ if (wait_vblank_crtc_id != SDE_RSC_INVALID_CRTC_ID) {
+ pr_err("unexpected sleep required on crtc %d at rsc client destroy\n",
+ wait_vblank_crtc_id);
+ SDE_EVT32(client->id, state, rsc->current_state,
+ client->crtc_id, wait_vblank_crtc_id,
+ SDE_EVTLOG_ERROR);
+ msleep(PRIMARY_VBLANK_WORST_CASE_MS);
+ }
+ }
mutex_lock(&rsc->client_lock);
list_del_init(&client->list);
mutex_unlock(&rsc->client_lock);
@@ -395,7 +404,13 @@
/* mode 2 is infinite */
rsc->timer_config.rsc_time_slot_2_ns = 0xFFFFFFFF;
- if (rsc->hw_ops.init) {
+ /* timer update should be called with client call */
+ if (cmd_config && rsc->hw_ops.timer_update) {
+ ret = rsc->hw_ops.timer_update(rsc);
+ if (ret)
+ pr_err("sde rsc: hw timer update failed ret:%d\n", ret);
+ /* rsc init should be called during rsc probe - one time only */
+ } else if (rsc->hw_ops.init) {
ret = rsc->hw_ops.init(rsc);
if (ret)
pr_err("sde rsc: hw init failed ret:%d\n", ret);
@@ -449,7 +464,8 @@
static int sde_rsc_switch_to_cmd(struct sde_rsc_priv *rsc,
struct sde_rsc_cmd_config *config,
- struct sde_rsc_client *caller_client)
+ struct sde_rsc_client *caller_client,
+ int *wait_vblank_crtc_id)
{
struct sde_rsc_client *client;
int rc = STATE_UPDATE_NOT_ALLOWED;
@@ -469,9 +485,19 @@
if (config)
sde_rsc_timer_calculate(rsc, config);
+ /**
+ * rsc clients can still send config at any time. If a config is
+ * received during cmd_state then vsync_wait will execute with the logic
+ * below. If a config is received when rsc is in AMC mode; A mode
+ * switch will do the vsync wait. updated checks still support all cases
+ * for dynamic mode switch and inline rotation.
+ */
if (rsc->current_state == SDE_RSC_CMD_STATE) {
rc = 0;
- goto vsync_wait;
+ if (config)
+ goto vsync_wait;
+ else
+ goto end;
}
/* any one client in video state blocks the cmd state switch */
@@ -486,15 +512,29 @@
}
vsync_wait:
- /* wait for vsync for vid to cmd state switch and config update */
+ /* indicate wait for vsync for vid to cmd state switch & cfg update */
if (!rc && (rsc->current_state == SDE_RSC_VID_STATE ||
- rsc->current_state == SDE_RSC_CMD_STATE))
- usleep_range(PRIMARY_VBLANK_MIN_US, PRIMARY_VBLANK_MAX_US);
+ rsc->current_state == SDE_RSC_CMD_STATE)) {
+ /* clear VSYNC timestamp for indication when update completes */
+ if (rsc->hw_ops.hw_vsync)
+ rsc->hw_ops.hw_vsync(rsc, VSYNC_ENABLE, NULL, 0, 0);
+ if (!wait_vblank_crtc_id) {
+ pr_err("invalid crtc id wait pointer, client %d\n",
+ caller_client->id);
+ SDE_EVT32(caller_client->id, rsc->current_state,
+ caller_client->crtc_id,
+ wait_vblank_crtc_id, SDE_EVTLOG_ERROR);
+ msleep(PRIMARY_VBLANK_WORST_CASE_MS);
+ } else {
+ *wait_vblank_crtc_id = rsc->primary_client->crtc_id;
+ }
+ }
end:
return rc;
}
-static int sde_rsc_switch_to_clk(struct sde_rsc_priv *rsc)
+static int sde_rsc_switch_to_clk(struct sde_rsc_priv *rsc,
+ int *wait_vblank_crtc_id)
{
struct sde_rsc_client *client;
int rc = STATE_UPDATE_NOT_ALLOWED;
@@ -510,17 +550,27 @@
rpmh_mode_solver_set(rsc->disp_rsc, false);
}
- /* wait for vsync for cmd to clk state switch */
+ /* indicate wait for vsync for cmd to clk state switch */
if (!rc && rsc->primary_client &&
- (rsc->current_state == SDE_RSC_CMD_STATE))
- usleep_range(PRIMARY_VBLANK_MIN_US, PRIMARY_VBLANK_MAX_US);
+ (rsc->current_state == SDE_RSC_CMD_STATE)) {
+ /* clear VSYNC timestamp for indication when update completes */
+ if (rsc->hw_ops.hw_vsync)
+ rsc->hw_ops.hw_vsync(rsc, VSYNC_ENABLE, NULL, 0, 0);
+ if (!wait_vblank_crtc_id) {
+ pr_err("invalid crtc id wait pointer provided\n");
+ msleep(PRIMARY_VBLANK_WORST_CASE_MS);
+ } else {
+ *wait_vblank_crtc_id = rsc->primary_client->crtc_id;
+ }
+ }
end:
return rc;
}
static int sde_rsc_switch_to_vid(struct sde_rsc_priv *rsc,
struct sde_rsc_cmd_config *config,
- struct sde_rsc_client *caller_client)
+ struct sde_rsc_client *caller_client,
+ int *wait_vblank_crtc_id)
{
int rc = 0;
@@ -539,16 +589,62 @@
rpmh_mode_solver_set(rsc->disp_rsc, false);
}
- /* wait for vsync for cmd to vid state switch */
+ /* indicate wait for vsync for cmd to vid state switch */
if (!rc && rsc->primary_client &&
- (rsc->current_state == SDE_RSC_CMD_STATE))
- usleep_range(PRIMARY_VBLANK_MIN_US, PRIMARY_VBLANK_MAX_US);
+ (rsc->current_state == SDE_RSC_CMD_STATE)) {
+ /* clear VSYNC timestamp for indication when update completes */
+ if (rsc->hw_ops.hw_vsync)
+ rsc->hw_ops.hw_vsync(rsc, VSYNC_ENABLE, NULL, 0, 0);
+ if (!wait_vblank_crtc_id) {
+ pr_err("invalid crtc id wait pointer provided\n");
+ msleep(PRIMARY_VBLANK_WORST_CASE_MS);
+ } else {
+ *wait_vblank_crtc_id = rsc->primary_client->crtc_id;
+ }
+ }
end:
return rc;
}
/**
+ * sde_rsc_client_is_state_update_complete() - check if state update is complete
+ * RSC state transition is not complete until HW receives VBLANK signal. This
+ * function checks RSC HW to determine whether that signal has been received.
+ * @client: Client pointer provided by sde_rsc_client_create().
+ *
+ * Return: true if the state update has completed.
+ */
+bool sde_rsc_client_is_state_update_complete(
+ struct sde_rsc_client *caller_client)
+{
+ struct sde_rsc_priv *rsc;
+ u32 vsync_timestamp0 = 0;
+
+ if (!caller_client) {
+ pr_err("invalid client for rsc state update\n");
+ return false;
+ } else if (caller_client->rsc_index >= MAX_RSC_COUNT) {
+ pr_err("invalid rsc index\n");
+ return false;
+ }
+
+ rsc = rsc_prv_list[caller_client->rsc_index];
+ if (!rsc)
+ return false;
+
+ /**
+ * state updates clear VSYNC timestamp, check if a new one arrived.
+ * use VSYNC mode 0 (CMD TE) always for this, per HW recommendation.
+ */
+ if (rsc->hw_ops.hw_vsync)
+ vsync_timestamp0 = rsc->hw_ops.hw_vsync(rsc, VSYNC_READ_VSYNC0,
+ NULL, 0, 0);
+
+ return vsync_timestamp0 != 0;
+}
+
+/**
* sde_rsc_client_state_update() - rsc client state update
* Video mode, cmd mode and clk state are suppoed as modes. A client need to
* set this property during panel config time. A switching client can set the
@@ -559,12 +655,18 @@
* @config: fps, vtotal, porches, etc configuration for command mode
* panel
* @crtc_id: current client's crtc id
+ * @wait_vblank_crtc_id: Output parameter. If set to non-zero, rsc hw
+ * state update requires a wait for one vblank on
+ * the primary crtc. In that case, this output
+ * param will be set to the crtc on which to wait.
+ * If SDE_RSC_INVALID_CRTC_ID, no wait necessary
*
* Return: error code.
*/
int sde_rsc_client_state_update(struct sde_rsc_client *caller_client,
enum sde_rsc_state state,
- struct sde_rsc_cmd_config *config, int crtc_id)
+ struct sde_rsc_cmd_config *config, int crtc_id,
+ int *wait_vblank_crtc_id)
{
int rc = 0;
struct sde_rsc_priv *rsc;
@@ -581,8 +683,11 @@
if (!rsc)
return -EINVAL;
+ if (wait_vblank_crtc_id)
+ *wait_vblank_crtc_id = SDE_RSC_INVALID_CRTC_ID;
+
mutex_lock(&rsc->client_lock);
- SDE_EVT32(caller_client->id, caller_client->current_state,
+ SDE_EVT32_VERBOSE(caller_client->id, caller_client->current_state,
state, rsc->current_state, SDE_EVTLOG_FUNC_ENTRY);
caller_client->crtc_id = crtc_id;
caller_client->current_state = state;
@@ -610,28 +715,31 @@
/* video state client might be exiting; try cmd state switch */
if (rc == TRY_CMD_MODE_SWITCH) {
rc = sde_rsc_switch_to_cmd(rsc, NULL,
- rsc->primary_client);
+ rsc->primary_client,
+ wait_vblank_crtc_id);
if (!rc)
state = SDE_RSC_CMD_STATE;
/* cmd state client might be exiting; try clk state switch */
} else if (rc == TRY_CLK_MODE_SWITCH) {
- rc = sde_rsc_switch_to_clk(rsc);
+ rc = sde_rsc_switch_to_clk(rsc, wait_vblank_crtc_id);
if (!rc)
state = SDE_RSC_CLK_STATE;
}
break;
case SDE_RSC_CMD_STATE:
- rc = sde_rsc_switch_to_cmd(rsc, config, caller_client);
+ rc = sde_rsc_switch_to_cmd(rsc, config, caller_client,
+ wait_vblank_crtc_id);
break;
case SDE_RSC_VID_STATE:
- rc = sde_rsc_switch_to_vid(rsc, config, caller_client);
+ rc = sde_rsc_switch_to_vid(rsc, config, caller_client,
+ wait_vblank_crtc_id);
break;
case SDE_RSC_CLK_STATE:
- rc = sde_rsc_switch_to_clk(rsc);
+ rc = sde_rsc_switch_to_clk(rsc, wait_vblank_crtc_id);
break;
default:
@@ -815,7 +923,7 @@
end:
mutex_unlock(&rsc->client_lock);
- if (blen < 0)
+ if (blen <= 0)
return 0;
if (copy_to_user(buf, buffer, blen))
@@ -907,7 +1015,7 @@
end:
mutex_unlock(&rsc->client_lock);
- if (blen < 0)
+ if (blen <= 0)
return 0;
if (copy_to_user(buf, buffer, blen))
diff --git a/drivers/gpu/drm/msm/sde_rsc_hw.c b/drivers/gpu/drm/msm/sde_rsc_hw.c
index 26a3154..b474d21 100644
--- a/drivers/gpu/drm/msm/sde_rsc_hw.c
+++ b/drivers/gpu/drm/msm/sde_rsc_hw.c
@@ -296,6 +296,47 @@
return 0;
}
+static int rsc_hw_timer_update(struct sde_rsc_priv *rsc)
+{
+ if (!rsc) {
+ pr_debug("invalid input param\n");
+ return -EINVAL;
+ }
+
+ pr_debug("rsc hw timer update\n");
+
+ dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_TIME_SLOT_TABLE_1_DRV0,
+ rsc->timer_config.rsc_time_slot_0_ns, rsc->debug_mode);
+ dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_TIME_SLOT_TABLE_2_DRV0,
+ rsc->timer_config.rsc_time_slot_1_ns, rsc->debug_mode);
+ dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_TIME_SLOT_TABLE_3_DRV0,
+ rsc->timer_config.rsc_time_slot_2_ns, rsc->debug_mode);
+
+ dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM2_DRV0_MODE0,
+ rsc->timer_config.rsc_backoff_time_ns, rsc->debug_mode);
+ dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM3_DRV0_MODE0,
+ rsc->timer_config.pdc_backoff_time_ns, rsc->debug_mode);
+
+ dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM2_DRV0_MODE1,
+ rsc->timer_config.rsc_backoff_time_ns, rsc->debug_mode);
+ dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM3_DRV0_MODE1,
+ rsc->timer_config.pdc_backoff_time_ns, rsc->debug_mode);
+
+ dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM3_DRV0_MODE2,
+ rsc->timer_config.pdc_backoff_time_ns, rsc->debug_mode);
+
+ dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_STATIC_WAKEUP_0,
+ rsc->timer_config.static_wakeup_time_ns, rsc->debug_mode);
+
+ dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_RSCC_MODE_THRESHOLD,
+ rsc->timer_config.rsc_mode_threshold_time_ns, rsc->debug_mode);
+
+ /* make sure that hw timers are updated */
+ wmb();
+
+ return 0;
+}
+
static int sde_rsc_mode2_exit(struct sde_rsc_priv *rsc,
enum sde_rsc_state state)
{
@@ -345,7 +386,7 @@
if (!test_bit(POWER_CTRL_BIT_12, &power_status)) {
reg = dss_reg_r(&rsc->drv_io,
SDE_RSCC_SEQ_PROGRAM_COUNTER, rsc->debug_mode);
- SDE_EVT32(count, reg, power_status);
+ SDE_EVT32_VERBOSE(count, reg, power_status);
rc = 0;
break;
}
@@ -428,6 +469,7 @@
if (rc) {
pr_err("mdss gdsc power down failed rc:%d\n", rc);
+ SDE_EVT32(rc, SDE_EVTLOG_ERROR);
goto end;
}
@@ -675,10 +717,24 @@
rsc->debug_mode));
break;
+ case VSYNC_READ_VSYNC0:
+ return dss_reg_r(&rsc->wrapper_io,
+ SDE_RSCC_WRAPPER_VSYNC_TIMESTAMP0,
+ rsc->debug_mode);
+
case VSYNC_ENABLE:
- reg = BIT(8) | ((mode & 0x7) < 10);
+ /* clear the current VSYNC value */
+ reg = BIT(9) | ((mode & 0x7) << 10);
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_DEBUG_BUS,
reg, rsc->debug_mode);
+
+ /* enable the VSYNC logging */
+ reg = BIT(8) | ((mode & 0x7) << 10);
+ dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_DEBUG_BUS,
+ reg, rsc->debug_mode);
+
+ /* ensure vsync config has been written before waiting on it */
+ wmb();
break;
case VSYNC_DISABLE:
@@ -740,6 +796,7 @@
pr_debug("rsc hardware register\n");
rsc->hw_ops.init = rsc_hw_init;
+ rsc->hw_ops.timer_update = rsc_hw_timer_update;
rsc->hw_ops.tcs_wait = rsc_hw_tcs_wait;
rsc->hw_ops.tcs_use_ok = rsc_hw_tcs_use_ok;
diff --git a/drivers/gpu/drm/msm/sde_rsc_priv.h b/drivers/gpu/drm/msm/sde_rsc_priv.h
index b90b0ac..c96ce75 100644
--- a/drivers/gpu/drm/msm/sde_rsc_priv.h
+++ b/drivers/gpu/drm/msm/sde_rsc_priv.h
@@ -51,11 +51,13 @@
/**
* rsc_vsync_req: sde rsc vsync request information
* VSYNC_READ: read vsync status
+ * VSYNC_READ_VSYNC0: read value vsync0 timestamp (cast to int from u32)
* VSYNC_ENABLE: enable rsc wrapper vsync status
* VSYNC_DISABLE: disable rsc wrapper vsync status
*/
enum rsc_vsync_req {
VSYNC_READ,
+ VSYNC_READ_VSYNC0,
VSYNC_ENABLE,
VSYNC_DISABLE,
};
@@ -64,6 +66,8 @@
* struct sde_rsc_hw_ops - sde resource state coordinator hardware ops
* @init: Initialize the sequencer, solver, qtimer,
etc. hardware blocks on RSC.
+ * @timer_update: update the static wrapper time and pdc/rsc
+ backoff time.
* @tcs_wait: Waits for TCS block OK to allow sending a
* TCS command.
* @hw_vsync: Enables the vsync on RSC block.
@@ -77,6 +81,7 @@
struct sde_rsc_hw_ops {
int (*init)(struct sde_rsc_priv *rsc);
+ int (*timer_update)(struct sde_rsc_priv *rsc);
int (*tcs_wait)(struct sde_rsc_priv *rsc);
int (*hw_vsync)(struct sde_rsc_priv *rsc, enum rsc_vsync_req request,
char *buffer, int buffer_size, u32 mode);
diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c
index 56bb758..7bb1e53 100644
--- a/drivers/gpu/drm/radeon/atombios_encoders.c
+++ b/drivers/gpu/drm/radeon/atombios_encoders.c
@@ -30,6 +30,7 @@
#include "radeon_audio.h"
#include "atom.h"
#include <linux/backlight.h>
+#include <linux/dmi.h>
extern int atom_debug;
@@ -2183,9 +2184,17 @@
goto assigned;
}
- /* on DCE32 and encoder can driver any block so just crtc id */
+ /*
+ * On DCE32 any encoder can drive any block so usually just use crtc id,
+ * but Apple thinks different at least on iMac10,1, so there use linkb,
+ * otherwise the internal eDP panel will stay dark.
+ */
if (ASIC_IS_DCE32(rdev)) {
- enc_idx = radeon_crtc->crtc_id;
+ if (dmi_match(DMI_PRODUCT_NAME, "iMac10,1"))
+ enc_idx = (dig->linkb) ? 1 : 0;
+ else
+ enc_idx = radeon_crtc->crtc_id;
+
goto assigned;
}
diff --git a/drivers/gpu/drm/radeon/ci_dpm.c b/drivers/gpu/drm/radeon/ci_dpm.c
index ea36dc4..2481049 100644
--- a/drivers/gpu/drm/radeon/ci_dpm.c
+++ b/drivers/gpu/drm/radeon/ci_dpm.c
@@ -782,6 +782,12 @@
if (r600_dpm_get_vrefresh(rdev) > 120)
return true;
+ /* disable mclk switching if the refresh is >120Hz, even if the
+ * blanking period would allow it
+ */
+ if (r600_dpm_get_vrefresh(rdev) > 120)
+ return true;
+
if (vblank_time < switch_limit)
return true;
else
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index c18fc31..94983e8 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -1343,7 +1343,6 @@
mem_type);
return ret;
}
- fence_put(man->move);
man->use_type = false;
man->has_type = false;
@@ -1355,6 +1354,9 @@
ret = (*man->func->takedown)(man);
}
+ fence_put(man->move);
+ man->move = NULL;
+
return ret;
}
EXPORT_SYMBOL(ttm_bo_clean_mm);
diff --git a/drivers/gpu/msm/a6xx_reg.h b/drivers/gpu/msm/a6xx_reg.h
index 32ebe0c..e112fd1 100644
--- a/drivers/gpu/msm/a6xx_reg.h
+++ b/drivers/gpu/msm/a6xx_reg.h
@@ -117,6 +117,7 @@
#define A6XX_CP_ALWAYS_ON_COUNTER_HI 0x981
#define A6XX_CP_AHB_CNTL 0x98D
#define A6XX_CP_APERTURE_CNTL_HOST 0xA00
+#define A6XX_CP_APERTURE_CNTL_CD 0xA03
#define A6XX_VSC_ADDR_MODE_CNTL 0xC01
/* RBBM registers */
@@ -599,6 +600,8 @@
#define A6XX_RB_PERFCTR_CMP_SEL_1 0x8E2D
#define A6XX_RB_PERFCTR_CMP_SEL_2 0x8E2E
#define A6XX_RB_PERFCTR_CMP_SEL_3 0x8E2F
+#define A6XX_RB_RB_SUB_BLOCK_SEL_CNTL_HOST 0x8E3B
+#define A6XX_RB_RB_SUB_BLOCK_SEL_CNTL_CD 0x8E3D
#define A6XX_RB_CONTEXT_SWITCH_GMEM_SAVE_RESTORE 0x8E50
/* PC registers */
@@ -720,10 +723,25 @@
/* VBIF registers */
#define A6XX_VBIF_VERSION 0x3000
+#define A6XX_VBIF_CLKON 0x3001
+#define A6XX_VBIF_CLKON_FORCE_ON_TESTBUS_MASK 0x1
+#define A6XX_VBIF_CLKON_FORCE_ON_TESTBUS_SHIFT 0x1
#define A6XX_VBIF_GATE_OFF_WRREQ_EN 0x302A
#define A6XX_VBIF_XIN_HALT_CTRL0 0x3080
#define A6XX_VBIF_XIN_HALT_CTRL0_MASK 0xF
#define A6XX_VBIF_XIN_HALT_CTRL1 0x3081
+#define A6XX_VBIF_TEST_BUS_OUT_CTRL 0x3084
+#define A6XX_VBIF_TEST_BUS_OUT_CTRL_EN_MASK 0x1
+#define A6XX_VBIF_TEST_BUS_OUT_CTRL_EN_SHIFT 0x0
+#define A6XX_VBIF_TEST_BUS1_CTRL0 0x3085
+#define A6XX_VBIF_TEST_BUS1_CTRL1 0x3086
+#define A6XX_VBIF_TEST_BUS1_CTRL1_DATA_SEL_MASK 0xF
+#define A6XX_VBIF_TEST_BUS1_CTRL1_DATA_SEL_SHIFT 0x0
+#define A6XX_VBIF_TEST_BUS2_CTRL0 0x3087
+#define A6XX_VBIF_TEST_BUS2_CTRL1 0x3088
+#define A6XX_VBIF_TEST_BUS2_CTRL1_DATA_SEL_MASK 0x1FF
+#define A6XX_VBIF_TEST_BUS2_CTRL1_DATA_SEL_SHIFT 0x0
+#define A6XX_VBIF_TEST_BUS_OUT 0x308C
#define A6XX_VBIF_PERF_CNT_SEL0 0x30d0
#define A6XX_VBIF_PERF_CNT_SEL1 0x30d1
#define A6XX_VBIF_PERF_CNT_SEL2 0x30d2
@@ -801,6 +819,7 @@
#define A6XX_GMU_DCVS_PERF_SETTING 0x1CBFD
#define A6XX_GMU_DCVS_BW_SETTING 0x1CBFE
#define A6XX_GMU_DCVS_RETURN 0x1CBFF
+#define A6XX_GMU_SYS_BUS_CONFIG 0x1F40F
#define A6XX_GMU_CM3_SYSRESET 0x1F800
#define A6XX_GMU_CM3_BOOT_CONFIG 0x1F801
#define A6XX_GMU_CM3_FW_BUSY 0x1F81A
@@ -859,11 +878,46 @@
#define A6XX_GMU_HOST2GMU_INTR_INFO_1 0x1F99C
#define A6XX_GMU_HOST2GMU_INTR_INFO_2 0x1F99D
#define A6XX_GMU_HOST2GMU_INTR_INFO_3 0x1F99E
+#define A6XX_GMU_GENERAL_1 0x1F9C6
#define A6XX_GMU_GENERAL_7 0x1F9CC
/* ISENSE registers */
#define A6XX_GMU_ISENSE_CTRL 0x1F95D
#define A6XX_GPU_CS_ENABLE_REG 0x23120
+#define A6XX_GPU_GMU_CX_GMU_ISENSE_CTRL 0x1f95d
+#define A6XX_GPU_CS_AMP_CALIBRATION_CONTROL3 0x22d78
+#define A6XX_GPU_CS_AMP_CALIBRATION_CONTROL2 0x22d58
+#define A6XX_GPU_CS_A_SENSOR_CTRL_0 0x22d80
+#define A6XX_GPU_CS_A_SENSOR_CTRL_2 0x422da
+#define A6XX_GPU_CS_SENSOR_GENERAL_STATUS 0x2301a
+#define A6XX_GPU_CS_AMP_CALIBRATION_CONTROL1 0x23157
+#define A6XX_GPU_CS_SENSOR_GENERAL_STATUS 0x2301a
+#define A6XX_GPU_CS_AMP_CALIBRATION_STATUS1_0 0x2301d
+#define A6XX_GPU_CS_AMP_CALIBRATION_STATUS1_2 0x2301f
+#define A6XX_GPU_CS_AMP_CALIBRATION_STATUS1_4 0x23021
+#define A6XX_GPU_CS_AMP_CALIBRATION_DONE 0x23165
+#define A6XX_GPU_CS_AMP_PERIOD_CTRL 0x2316d
+#define A6XX_GPU_CS_AMP_CALIBRATION_DONE 0x23165
+
+#define CS_PWR_ON_STATUS (10)
+#define AMP_SW_WRM_TRIM_START (24)
+#define AMP_TRIM_TIMER (6)
+#define AMP_SW_TRIM_START (0)
+#define SS_AMPTRIM_DONE (11)
+#define AMP_OFFSET_CHECK_MIN_ERR (1)
+#define AMP_OFFSET_CHECK_MAX_ERR (2)
+#define AMP_OUT_OF_RANGE_ERR (4)
+#define TRIM_CNT_VALUE (1)
+#define RUNTIME_CNT_VALUE (16)
+#define TRIM_ENABLE (0)
+
+#define AMP_ERR (BIT(AMP_OFFSET_CHECK_MIN_ERR) || \
+ BIT(AMP_OFFSET_CHECK_MAX_ERR) || \
+ BIT(AMP_OUT_OF_RANGE_ERR))
+
+/* LM registers */
+#define A6XX_GPU_GMU_CX_GMU_PWR_THRESHOLD 0x1F94D
+
#define A6XX_GMU_AO_INTERRUPT_EN 0x23B03
#define A6XX_GMU_AO_HOST_INTERRUPT_CLR 0x23B04
@@ -890,6 +944,7 @@
/* GPUCC registers */
#define A6XX_GPU_CC_GX_GDSCR 0x24403
+#define A6XX_GPU_CC_GX_DOMAIN_MISC 0x24542
/* GPU RSC sequencer registers */
#define A6XX_RSCC_PDC_SEQ_START_ADDR 0x23408
diff --git a/drivers/gpu/msm/adreno-gpulist.h b/drivers/gpu/msm/adreno-gpulist.h
index f8bf780..7dda62a 100644
--- a/drivers/gpu/msm/adreno-gpulist.h
+++ b/drivers/gpu/msm/adreno-gpulist.h
@@ -327,7 +327,7 @@
.minor = 0,
.patchid = ANY_ID,
.features = ADRENO_64BIT | ADRENO_RPMH |
- ADRENO_GPMU | ADRENO_CONTENT_PROTECTION,
+ ADRENO_GPMU | ADRENO_CONTENT_PROTECTION | ADRENO_LM,
.sqefw_name = "a630_sqe.fw",
.zap_name = "a630_zap",
.gpudev = &adreno_a6xx_gpudev,
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 6f465aa..6426363 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -2342,6 +2342,11 @@
return ret;
}
+ /* Clear the busy_data stats - we're starting over from scratch */
+ adreno_dev->busy_data.gpu_busy = 0;
+ adreno_dev->busy_data.vbif_ram_cycles = 0;
+ adreno_dev->busy_data.vbif_starved_ram = 0;
+
/* Set the page table back to the default page table */
adreno_ringbuffer_set_global(adreno_dev, 0);
kgsl_mmu_set_pt(&device->mmu, device->mmu.defaultpagetable);
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 4900b3a..01b877f 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -642,6 +642,8 @@
ADRENO_REG_GMU_HOST2GMU_INTR_SET,
ADRENO_REG_GMU_HOST2GMU_INTR_CLR,
ADRENO_REG_GMU_HOST2GMU_INTR_RAW_INFO,
+ ADRENO_REG_GMU_NMI_CONTROL_STATUS,
+ ADRENO_REG_GMU_CM3_CFG,
ADRENO_REG_GPMU_POWER_COUNTER_ENABLE,
ADRENO_REG_REGISTER_MAX,
};
diff --git a/drivers/gpu/msm/adreno_a5xx.h b/drivers/gpu/msm/adreno_a5xx.h
index 08fd16a..3d89d73 100644
--- a/drivers/gpu/msm/adreno_a5xx.h
+++ b/drivers/gpu/msm/adreno_a5xx.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. 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 and
@@ -151,24 +151,6 @@
#define GPMU_ISENSE_STATUS GENMASK(3, 0)
#define GPMU_ISENSE_END_POINT_CAL_ERR BIT(0)
-/* A5XX_GPU_CS_AMP_CALIBRATION_CONTROL1 */
-#define AMP_SW_TRIM_START BIT(0)
-
-/* A5XX_GPU_CS_SENSOR_GENERAL_STATUS */
-#define SS_AMPTRIM_DONE BIT(11)
-#define CS_PWR_ON_STATUS BIT(10)
-
-/* A5XX_GPU_CS_AMP_CALIBRATION_STATUS*_* */
-#define AMP_OUT_OF_RANGE_ERR BIT(4)
-#define AMP_OFFSET_CHECK_MAX_ERR BIT(2)
-#define AMP_OFFSET_CHECK_MIN_ERR BIT(1)
-
-/* A5XX_GPU_CS_AMP_CALIBRATION_DONE */
-#define SW_OPAMP_CAL_DONE BIT(0)
-
-#define AMP_CALIBRATION_ERR (AMP_OFFSET_CHECK_MIN_ERR | \
- AMP_OFFSET_CHECK_MAX_ERR | AMP_OUT_OF_RANGE_ERR)
-
#define AMP_CALIBRATION_RETRY_CNT 3
#define AMP_CALIBRATION_TIMEOUT 6
diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c
index c1d2407..a6cc94b 100644
--- a/drivers/gpu/msm/adreno_a6xx.c
+++ b/drivers/gpu/msm/adreno_a6xx.c
@@ -357,7 +357,22 @@
/* enable top level HWCG */
kgsl_regwrite(device, A6XX_RBBM_CLOCK_CNTL, on ? 0x8AA8AA02 : 0);
- kgsl_regwrite(device, A5XX_RBBM_ISDB_CNT, on ? 0x00000182 : 0x00000180);
+}
+
+#define LM_DEFAULT_LIMIT 6000
+
+static uint32_t lm_limit(struct adreno_device *adreno_dev)
+{
+ struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+
+ if (adreno_dev->lm_limit)
+ return adreno_dev->lm_limit;
+
+ if (of_property_read_u32(device->pdev->dev.of_node, "qcom,lm-limit",
+ &adreno_dev->lm_limit))
+ adreno_dev->lm_limit = LM_DEFAULT_LIMIT;
+
+ return adreno_dev->lm_limit;
}
/*
@@ -379,6 +394,9 @@
/* enable hardware clockgating */
a6xx_hwcg_set(adreno_dev, true);
+ if (ADRENO_FEATURE(adreno_dev, ADRENO_LM))
+ adreno_dev->lm_threshold_count = A6XX_GMU_GENERAL_1;
+
adreno_vbif_start(adreno_dev, a6xx_vbif_platforms,
ARRAY_SIZE(a6xx_vbif_platforms));
@@ -544,11 +562,20 @@
/* Ucode workaround masks */
#define CP_INIT_UCODE_WORKAROUND_MASK BIT(5)
+/*
+ * Operation mode mask
+ *
+ * This ordinal provides the option to disable the
+ * save/restore of performance counters across preemption.
+ */
+#define CP_INIT_OPERATION_MODE_MASK BIT(6)
+
#define CP_INIT_MASK (CP_INIT_MAX_CONTEXT | \
CP_INIT_ERROR_DETECTION_CONTROL | \
CP_INIT_HEADER_DUMP | \
CP_INIT_DEFAULT_RESET_STATE | \
- CP_INIT_UCODE_WORKAROUND_MASK)
+ CP_INIT_UCODE_WORKAROUND_MASK | \
+ CP_INIT_OPERATION_MODE_MASK)
static void _set_ordinals(struct adreno_device *adreno_dev,
unsigned int *cmds, unsigned int count)
@@ -581,6 +608,9 @@
if (CP_INIT_MASK & CP_INIT_UCODE_WORKAROUND_MASK)
*cmds++ = 0x00000000;
+ if (CP_INIT_MASK & CP_INIT_OPERATION_MODE_MASK)
+ *cmds++ = 0x00000002;
+
/* Pad rest of the cmds with 0's */
while ((unsigned int)(cmds - start) < count)
*cmds++ = 0x0;
@@ -904,6 +934,9 @@
/* Configure registers for idle setting. The setting is cumulative */
+ /* Disable GMU WB/RB buffer */
+ kgsl_gmu_regwrite(device, A6XX_GMU_SYS_BUS_CONFIG, 0x1);
+
kgsl_gmu_regwrite(device,
A6XX_GMU_PWR_COL_INTER_FRAME_CTRL, 0x9C40400);
@@ -935,7 +968,8 @@
}
/* ACD feature enablement */
- if (ADRENO_FEATURE(adreno_dev, ADRENO_LM))
+ if (ADRENO_FEATURE(adreno_dev, ADRENO_LM) &&
+ test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag))
kgsl_gmu_regrmw(device, A6XX_GMU_BOOT_KMD_LM_HANDSHAKE, 0,
BIT(10));
@@ -943,9 +977,6 @@
if (ADRENO_FEATURE(adreno_dev, ADRENO_RPMH))
kgsl_gmu_regrmw(device, A6XX_GMU_RPMH_CTRL, 0,
RPMH_ENABLE_MASK);
-
- /* Disable reference bandgap voltage */
- kgsl_gmu_regwrite(device, A6XX_GMU_AO_SPARE_CNTL, 1);
}
/*
@@ -1132,62 +1163,6 @@
dev_err(&gmu->pdev->dev, "power off SPTPRAC fail\n");
}
-/*
- * a6xx_hm_enable() - Power on HM and turn on clock
- * @adreno_dev: Pointer to Adreno device
- */
-static int a6xx_hm_enable(struct adreno_device *adreno_dev)
-{
- int ret;
- struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
- struct kgsl_pwrctrl *pwr = &device->pwrctrl;
- struct gmu_device *gmu = &device->gmu;
-
- if (regulator_is_enabled(gmu->gx_gdsc))
- return 0;
-
- ret = regulator_enable(gmu->gx_gdsc);
- if (ret) {
- dev_err(&gmu->pdev->dev,
- "Failed to turn on GPU HM HS\n");
- return ret;
- }
-
- ret = clk_set_rate(pwr->grp_clks[0],
- pwr->pwrlevels[pwr->default_pwrlevel].
- gpu_freq);
- if (ret)
- return ret;
-
- return clk_prepare_enable(pwr->grp_clks[0]);
-}
-
-/*
- * a6xx_hm_disable() - Turn off HM clock and power off
- * @adreno_dev: Pointer to Adreno device
- */
-static int a6xx_hm_disable(struct adreno_device *adreno_dev)
-{
- struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
- struct kgsl_pwrctrl *pwr = &device->pwrctrl;
- struct gmu_device *gmu = &device->gmu;
-
- if (!regulator_is_enabled(gmu->gx_gdsc))
- return 0;
-
- /* Ensure that retention is on */
- kgsl_gmu_regrmw(device, A6XX_GPU_CC_GX_GDSCR, 0,
- A6XX_RETAIN_FF_ENABLE_ENABLE_MASK);
-
- clk_disable_unprepare(pwr->grp_clks[0]);
-
- clk_set_rate(pwr->grp_clks[0],
- pwr->pwrlevels[pwr->num_pwrlevels - 1].
- gpu_freq);
-
- return regulator_disable(gmu->gx_gdsc);
-}
-
#define SPTPRAC_POWER_OFF BIT(2)
#define SP_CLK_OFF BIT(4)
#define GX_GDSC_POWER_OFF BIT(6)
@@ -1239,62 +1214,6 @@
}
/*
- * a6xx_hm_sptprac_enable() - Turn on HM and SPTPRAC
- * @device: Pointer to KGSL device
- */
-static int a6xx_hm_sptprac_enable(struct kgsl_device *device)
-{
- int ret = 0;
- struct gmu_device *gmu = &device->gmu;
-
- /* If GMU does not control HM we must */
- if (gmu->idle_level < GPU_HW_IFPC) {
-
- ret = a6xx_hm_enable(ADRENO_DEVICE(device));
- if (ret) {
- dev_err(&gmu->pdev->dev, "Failed to power on GPU HM\n");
- return ret;
- }
-
-
- }
-
- /* If GMU does not control SPTPRAC we must */
- if (gmu->idle_level < GPU_HW_SPTP_PC) {
- ret = a6xx_sptprac_enable(ADRENO_DEVICE(device));
- if (ret) {
- a6xx_hm_disable(ADRENO_DEVICE(device));
- return ret;
- }
- }
-
- return ret;
-}
-
-/*
- * a6xx_hm_sptprac_disable() - Turn off SPTPRAC and HM
- * @device: Pointer to KGSL device
- */
-static int a6xx_hm_sptprac_disable(struct kgsl_device *device)
-{
- int ret = 0;
- struct gmu_device *gmu = &device->gmu;
-
- /* If GMU does not control SPTPRAC we must */
- if (gmu->idle_level < GPU_HW_SPTP_PC)
- a6xx_sptprac_disable(ADRENO_DEVICE(device));
-
- /* If GMU does not control HM we must */
- if (gmu->idle_level < GPU_HW_IFPC) {
- ret = a6xx_hm_disable(ADRENO_DEVICE(device));
- if (ret)
- dev_err(&gmu->pdev->dev, "Failed to power off GPU HM\n");
- }
-
- return ret;
-}
-
-/*
* a6xx_gfx_rail_on() - request GMU to power GPU at given OPP.
* @device: Pointer to KGSL device
*
@@ -1344,6 +1263,9 @@
/* Disable the power counter so that the GMU is not busy */
kgsl_gmu_regwrite(device, A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE, 0);
+ /* Turn off SPTPRAC before GMU turns off GX */
+ a6xx_sptprac_disable(adreno_dev);
+
if (!ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) {
ret = hfi_notify_slumber(gmu, perf_idx, bus_level);
return ret;
@@ -1379,7 +1301,10 @@
{
struct gmu_device *gmu = &device->gmu;
struct device *dev = &gmu->pdev->dev;
- int ret = 0;
+ int val;
+
+ kgsl_gmu_regread(device, A6XX_GPU_CC_GX_DOMAIN_MISC, &val);
+ WARN_ON(!(val & 0x1));
/* RSC wake sequence */
kgsl_gmu_regwrite(device, A6XX_GMU_RSCC_CONTROL_REQ, BIT(1));
@@ -1405,25 +1330,20 @@
kgsl_gmu_regwrite(device, A6XX_GMU_RSCC_CONTROL_REQ, 0);
- /* Turn on the HM and SPTP head switches */
- ret = a6xx_hm_sptprac_enable(device);
-
/* Enable the power counter because it was disabled before slumber */
kgsl_gmu_regwrite(device, A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE, 1);
- return ret;
+ return 0;
error_rsc:
dev_err(dev, "GPU RSC sequence stuck in waking up GPU\n");
- return -EINVAL;
+ return -EINVAL;
}
static int a6xx_rpmh_power_off_gpu(struct kgsl_device *device)
{
struct gmu_device *gmu = &device->gmu;
- int val, ret = 0;
-
- /* Turn off the SPTP and HM head switches */
- ret = a6xx_hm_sptprac_disable(device);
+ const struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ int val;
/* RSC sleep sequence */
kgsl_gmu_regwrite(device, A6XX_RSCC_TIMESTAMP_UNIT1_EN_DRV0, 1);
@@ -1446,13 +1366,87 @@
&val);
kgsl_gmu_regwrite(device, A6XX_GMU_RSCC_CONTROL_REQ, 0);
- kgsl_gmu_regwrite(device, A6XX_GMU_AO_SPARE_CNTL, 0);
+ if (ADRENO_FEATURE(adreno_dev, ADRENO_LM) &&
+ test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag))
+ kgsl_gmu_regwrite(device, A6XX_GMU_AO_SPARE_CNTL, 0);
/* FIXME: v2 has different procedure to trigger sequence */
- return ret;
+ return 0;
}
+#define KMASK(start, n) (GENMASK((start + n), (start)))
+
+static void isense_cold_trimm(struct kgsl_device *device)
+{
+ unsigned int reg;
+ struct gmu_device *gmu = &device->gmu;
+
+ kgsl_gmu_regwrite(device, A6XX_GMU_AO_SPARE_CNTL, 1);
+ kgsl_gmu_regwrite(device, A6XX_GPU_CS_AMP_CALIBRATION_DONE, 0);
+
+ kgsl_gmu_regwrite(device, A6XX_GPU_GMU_CX_GMU_ISENSE_CTRL, 0x1);
+ kgsl_gmu_regwrite(device, A6XX_GPU_CS_AMP_CALIBRATION_CONTROL3,
+ 0x00000F8F);
+ kgsl_gmu_regwrite(device, A6XX_GPU_CS_AMP_CALIBRATION_CONTROL2,
+ 0x00705161);
+ udelay(10);
+ kgsl_gmu_regwrite(device, A6XX_GPU_CS_ENABLE_REG, 0x3);
+ kgsl_gmu_regwrite(device, A6XX_GPU_CS_A_SENSOR_CTRL_0, 0x10040a);
+ kgsl_gmu_regwrite(device, A6XX_GPU_CS_A_SENSOR_CTRL_2, 0x10040a);
+
+ kgsl_gmu_regread(device, A6XX_GPU_CS_SENSOR_GENERAL_STATUS, ®);
+ if ((reg & BIT(CS_PWR_ON_STATUS)) != (1 << CS_PWR_ON_STATUS)) {
+ dev_err(&gmu->pdev->dev, "ERROR - ISENSE power-up\n");
+ return;
+ }
+
+ kgsl_gmu_regrmw(device, A6XX_GPU_CS_AMP_CALIBRATION_CONTROL1,
+ KMASK(AMP_TRIM_TIMER, 15), 70 << AMP_TRIM_TIMER);
+ kgsl_gmu_regrmw(device, A6XX_GPU_CS_AMP_CALIBRATION_CONTROL1,
+ KMASK(AMP_SW_TRIM_START, 1), 0 << AMP_SW_TRIM_START);
+ kgsl_gmu_regrmw(device, A6XX_GPU_CS_AMP_CALIBRATION_CONTROL1,
+ KMASK(AMP_SW_TRIM_START, 1), 1 << AMP_SW_TRIM_START);
+
+ if (timed_poll_check(device, A6XX_GPU_CS_SENSOR_GENERAL_STATUS,
+ BIT(SS_AMPTRIM_DONE), GMU_START_TIMEOUT,
+ BIT(SS_AMPTRIM_DONE))) {
+ dev_err(&gmu->pdev->dev, "ISENSE SS_AMPTRIM failure\n");
+ return;
+ }
+
+ kgsl_gmu_regread(device, A6XX_GPU_CS_AMP_CALIBRATION_STATUS1_0, ®);
+ if (reg & AMP_ERR) {
+ kgsl_gmu_regread(device, A6XX_GPU_CS_AMP_CALIBRATION_STATUS1_0,
+ ®);
+ dev_err(&gmu->pdev->dev,
+ "ISENSE ERROR:trimming GX 0x%08x\n", reg);
+ return;
+ }
+
+ kgsl_gmu_regread(device, A6XX_GPU_CS_AMP_CALIBRATION_STATUS1_2, ®);
+ if (reg & AMP_ERR) {
+ kgsl_gmu_regread(device, A6XX_GPU_CS_AMP_CALIBRATION_STATUS1_2,
+ ®);
+ dev_err(&gmu->pdev->dev,
+ "ISENSE ERROR:trimming SPTPRAC 0x%08x\n", reg);
+ return;
+ }
+
+ kgsl_gmu_regwrite(device, A6XX_GPU_CS_AMP_CALIBRATION_DONE, 1);
+ kgsl_gmu_regrmw(device, A6XX_GPU_CS_AMP_PERIOD_CTRL,
+ KMASK(TRIM_CNT_VALUE, 13), 20 << TRIM_CNT_VALUE);
+ kgsl_gmu_regrmw(device, A6XX_GPU_CS_AMP_PERIOD_CTRL,
+ KMASK(RUNTIME_CNT_VALUE, 9), 50 << RUNTIME_CNT_VALUE);
+
+ kgsl_gmu_regrmw(device, A6XX_GPU_CS_AMP_PERIOD_CTRL,
+ KMASK(TRIM_ENABLE, 1), 1 << TRIM_ENABLE);
+ udelay(4);
+ kgsl_gmu_regrmw(device, A6XX_GPU_CS_AMP_PERIOD_CTRL,
+ KMASK(TRIM_ENABLE, 1), 0 << TRIM_ENABLE);
+ kgsl_gmu_regwrite(device, A6XX_GPU_CS_AMP_CALIBRATION_DONE, 1);
+
+}
/*
* a6xx_gmu_fw_start() - set up GMU and start FW
* @device: Pointer to KGSL device
@@ -1465,30 +1459,18 @@
struct gmu_device *gmu = &device->gmu;
struct gmu_memdesc *mem_addr = gmu->hfi_mem;
int ret, i;
+ unsigned int chipid = 0;
switch (boot_state) {
case GMU_RESET:
/* fall through */
case GMU_COLD_BOOT:
- /* Turn on the HM and SPTP head switches */
- ret = a6xx_hm_sptprac_enable(device);
- if (ret)
- return ret;
-
/* Turn on TCM retention */
kgsl_gmu_regwrite(device, A6XX_GMU_GENERAL_7, 1);
- if (!test_and_set_bit(GMU_BOOT_INIT_DONE, &gmu->flags)) {
+ if (!test_and_set_bit(GMU_BOOT_INIT_DONE, &gmu->flags))
_load_gmu_rpmh_ucode(device);
- /* Turn on the HM and SPTP head switches */
- ret = a6xx_hm_sptprac_enable(device);
- if (ret)
- return ret;
- } else if (boot_state == GMU_RESET) {
- ret = a6xx_hm_sptprac_enable(device);
- if (ret)
- return ret;
- } else {
+ else if (boot_state != GMU_RESET) {
ret = a6xx_rpmh_power_on_gpu(device);
if (ret)
return ret;
@@ -1530,6 +1512,28 @@
kgsl_gmu_regwrite(device, A6XX_GMU_AHB_FENCE_RANGE_0,
FENCE_RANGE_MASK);
+ /* Pass chipid to GMU FW, must happen before starting GMU */
+
+ /* Keep Core and Major bitfields unchanged */
+ chipid = adreno_dev->chipid & 0xFFFF0000;
+
+ /*
+ * Compress minor and patch version into 8 bits
+ * Bit 15-12: minor version
+ * Bit 11-8: patch version
+ */
+ chipid = chipid | (ADRENO_CHIPID_MINOR(adreno_dev->chipid) << 12)
+ | (ADRENO_CHIPID_PATCH(adreno_dev->chipid) << 8);
+
+ kgsl_gmu_regwrite(device, A6XX_GMU_HFI_SFR_ADDR, chipid);
+
+ if (ADRENO_FEATURE(adreno_dev, ADRENO_LM) &&
+ test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag)) {
+ kgsl_gmu_regwrite(device, A6XX_GPU_GMU_CX_GMU_PWR_THRESHOLD,
+ lm_limit(adreno_dev));
+ isense_cold_trimm(device);
+ }
+
/* Configure power control and bring the GMU out of reset */
a6xx_gmu_power_config(device);
ret = a6xx_gmu_start(device);
@@ -1545,6 +1549,12 @@
}
}
+ if (gmu->idle_level < GPU_HW_SPTP_PC) {
+ ret = a6xx_sptprac_enable(adreno_dev);
+ if (ret)
+ return ret;
+ }
+
ret = a6xx_gmu_hfi_start(device);
if (ret)
return ret;
@@ -1759,7 +1769,8 @@
unsigned int val;
const struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
- if (!ADRENO_FEATURE(adreno_dev, ADRENO_LM))
+ if (!ADRENO_FEATURE(adreno_dev, ADRENO_LM) ||
+ !test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag))
return;
kgsl_gmu_regread(device, A6XX_GPU_CS_ENABLE_REG, &val);
@@ -1775,7 +1786,8 @@
const struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct gmu_device *gmu = &device->gmu;
- if (!ADRENO_FEATURE(adreno_dev, ADRENO_LM))
+ if (!ADRENO_FEATURE(adreno_dev, ADRENO_LM) ||
+ !test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag))
return 0;
kgsl_gmu_regread(device, A6XX_GMU_LLM_GLM_SLEEP_CTRL, &val);
@@ -1794,6 +1806,19 @@
return 0;
}
+
+static void a6xx_count_throttles(struct adreno_device *adreno_dev,
+ uint64_t adj)
+{
+ if (!ADRENO_FEATURE(adreno_dev, ADRENO_LM) ||
+ !test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag))
+ return;
+
+ kgsl_gmu_regread(KGSL_DEVICE(adreno_dev),
+ adreno_dev->lm_threshold_count,
+ &adreno_dev->lm_threshold_cross);
+}
+
static int a6xx_complete_rpmh_votes(struct kgsl_device *device)
{
int ret = 0;
@@ -1837,13 +1862,7 @@
/* Check no outstanding RPMh voting */
a6xx_complete_rpmh_votes(device);
- if (gmu->idle_level < GPU_HW_IFPC) {
- /* HM GDSC is controlled by KGSL */
- ret = a6xx_hm_disable(ADRENO_DEVICE(device));
- if (ret)
- dev_err(&gmu->pdev->dev,
- "suspend: fail: power off GPU HM\n");
- } else if (gmu->gx_gdsc) {
+ if (gmu->gx_gdsc) {
if (regulator_is_enabled(gmu->gx_gdsc)) {
/* Switch gx gdsc control from GMU to CPU
* force non-zero reference count in clk driver
@@ -2184,6 +2203,16 @@
return uche_client[uche_client_id & A6XX_UCHE_CLIENT_PF_CLIENT_ID_MASK];
}
+static void a6xx_cp_callback(struct adreno_device *adreno_dev, int bit)
+{
+ struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+
+ if (adreno_is_preemption_enabled(adreno_dev))
+ a6xx_preemption_trigger(adreno_dev);
+
+ adreno_dispatcher_schedule(device);
+}
+
#define A6XX_INT_MASK \
((1 << A6XX_INT_CP_AHB_ERROR) | \
(1 << A6XX_INT_ATB_ASYNCFIFO_OVERFLOW) | \
@@ -2221,7 +2250,7 @@
ADRENO_IRQ_CALLBACK(NULL), /* 17 - CP_RB_DONE_TS */
ADRENO_IRQ_CALLBACK(NULL), /* 18 - CP_WT_DONE_TS */
ADRENO_IRQ_CALLBACK(NULL), /* 19 - UNUSED */
- ADRENO_IRQ_CALLBACK(adreno_cp_callback), /* 20 - CP_CACHE_FLUSH_TS */
+ ADRENO_IRQ_CALLBACK(a6xx_cp_callback), /* 20 - CP_CACHE_FLUSH_TS */
ADRENO_IRQ_CALLBACK(NULL), /* 21 - UNUSED */
ADRENO_IRQ_CALLBACK(a6xx_err_callback), /* 22 - RBBM_ATB_BUS_OVERFLOW */
/* 23 - MISC_HANG_DETECT */
@@ -2672,9 +2701,9 @@
if (!device->gmu.pdev)
return -ENODEV;
- kgsl_regwrite(device, A6XX_GPU_GMU_AO_GPU_CX_BUSY_MASK, 0);
+ kgsl_regwrite(device, A6XX_GPU_GMU_AO_GPU_CX_BUSY_MASK, 0xFF000000);
kgsl_regrmw(device,
- A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_0, 0xFF, 0x20);
+ A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_0, 0xFF, 0x20);
kgsl_regwrite(device, A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE, 0x1);
return 0;
@@ -2775,6 +2804,10 @@
A6XX_GMU_HOST2GMU_INTR_CLR),
ADRENO_REG_DEFINE(ADRENO_REG_GMU_HOST2GMU_INTR_RAW_INFO,
A6XX_GMU_HOST2GMU_INTR_RAW_INFO),
+ ADRENO_REG_DEFINE(ADRENO_REG_GMU_NMI_CONTROL_STATUS,
+ A6XX_GMU_NMI_CONTROL_STATUS),
+ ADRENO_REG_DEFINE(ADRENO_REG_GMU_CM3_CFG,
+ A6XX_GMU_CM3_CFG),
ADRENO_REG_DEFINE(ADRENO_REG_RBBM_SECVID_TRUST_CONTROL,
A6XX_RBBM_SECVID_TRUST_CNTL),
ADRENO_REG_DEFINE(ADRENO_REG_RBBM_SECVID_TSB_TRUSTED_BASE,
@@ -2807,6 +2840,7 @@
.regulator_disable = a6xx_sptprac_disable,
.perfcounters = &a6xx_perfcounters,
.enable_pwr_counters = a6xx_enable_pwr_counters,
+ .count_throttles = a6xx_count_throttles,
.microcode_read = a6xx_microcode_read,
.enable_64bit = a6xx_enable_64bit,
.llc_configure_gpu_scid = a6xx_llc_configure_gpu_scid,
diff --git a/drivers/gpu/msm/adreno_a6xx.h b/drivers/gpu/msm/adreno_a6xx.h
index ddf89d6..02748a6 100644
--- a/drivers/gpu/msm/adreno_a6xx.h
+++ b/drivers/gpu/msm/adreno_a6xx.h
@@ -73,7 +73,7 @@
uint32_t context_idr;
};
-#define A6XX_CP_SMMU_INFO_MAGIC_REF 0x3618CDA3UL
+#define A6XX_CP_SMMU_INFO_MAGIC_REF 0x241350D5UL
#define A6XX_CP_CTXRECORD_MAGIC_REF 0xAE399D6EUL
/* Size of each CP preemption record */
diff --git a/drivers/gpu/msm/adreno_a6xx_snapshot.c b/drivers/gpu/msm/adreno_a6xx_snapshot.c
index 1f97888..6264574 100644
--- a/drivers/gpu/msm/adreno_a6xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a6xx_snapshot.c
@@ -21,6 +21,9 @@
#include "kgsl_gmu.h"
#define A6XX_NUM_CTXTS 2
+#define A6XX_NUM_AXI_ARB_BLOCKS 2
+#define A6XX_NUM_XIN_AXI_BLOCKS 5
+#define A6XX_NUM_XIN_CORE_BLOCKS 4
static const unsigned int a6xx_gras_cluster[] = {
0x8000, 0x8006, 0x8010, 0x8092, 0x8094, 0x809D, 0x80A0, 0x80A6,
@@ -28,12 +31,20 @@
0x8400, 0x840B,
};
-static const unsigned int a6xx_ps_cluster[] = {
+static const unsigned int a6xx_ps_cluster_rac[] = {
0x8800, 0x8806, 0x8809, 0x8811, 0x8818, 0x881E, 0x8820, 0x8865,
0x8870, 0x8879, 0x8880, 0x8889, 0x8890, 0x8891, 0x8898, 0x8898,
- 0x88C0, 0x88c1, 0x88D0, 0x88E3, 0x88F0, 0x88F3, 0x8900, 0x891A,
- 0x8927, 0x8928, 0x8C00, 0x8C01, 0x8C17, 0x8C33, 0x9200, 0x9216,
- 0x9218, 0x9236, 0x9300, 0x9306,
+ 0x88C0, 0x88C1, 0x88D0, 0x88E3, 0x8900, 0x890C, 0x890F, 0x891A,
+ 0x8C00, 0x8C01, 0x8C08, 0x8C10, 0x8C17, 0x8C1F, 0x8C26, 0x8C33,
+};
+
+static const unsigned int a6xx_ps_cluster_rbp[] = {
+ 0x88F0, 0x88F3, 0x890D, 0x890E, 0x8927, 0x8928, 0x8BF0, 0x8BF1,
+ 0x8C02, 0x8C07, 0x8C11, 0x8C16, 0x8C20, 0x8C25,
+};
+
+static const unsigned int a6xx_ps_cluster[] = {
+ 0x9200, 0x9216, 0x9218, 0x9236, 0x9300, 0x9306,
};
static const unsigned int a6xx_fe_cluster[] = {
@@ -45,18 +56,41 @@
0x9100, 0x9108, 0x9300, 0x9306, 0x9980, 0x9981, 0x9B00, 0x9B07,
};
+static const struct sel_reg {
+ unsigned int host_reg;
+ unsigned int cd_reg;
+ unsigned int val;
+} _a6xx_rb_rac_aperture = {
+ .host_reg = A6XX_RB_RB_SUB_BLOCK_SEL_CNTL_HOST,
+ .cd_reg = A6XX_RB_RB_SUB_BLOCK_SEL_CNTL_CD,
+ .val = 0x0,
+},
+_a6xx_rb_rbp_aperture = {
+ .host_reg = A6XX_RB_RB_SUB_BLOCK_SEL_CNTL_HOST,
+ .cd_reg = A6XX_RB_RB_SUB_BLOCK_SEL_CNTL_CD,
+ .val = 0x9,
+};
+
static struct a6xx_cluster_registers {
unsigned int id;
const unsigned int *regs;
unsigned int num_sets;
+ const struct sel_reg *sel;
unsigned int offset0;
unsigned int offset1;
} a6xx_clusters[] = {
- { CP_CLUSTER_GRAS, a6xx_gras_cluster, ARRAY_SIZE(a6xx_gras_cluster)/2 },
- { CP_CLUSTER_PS, a6xx_ps_cluster, ARRAY_SIZE(a6xx_ps_cluster)/2 },
- { CP_CLUSTER_FE, a6xx_fe_cluster, ARRAY_SIZE(a6xx_fe_cluster)/2 },
+ { CP_CLUSTER_GRAS, a6xx_gras_cluster, ARRAY_SIZE(a6xx_gras_cluster)/2,
+ NULL },
+ { CP_CLUSTER_PS, a6xx_ps_cluster_rac, ARRAY_SIZE(a6xx_ps_cluster_rac)/2,
+ &_a6xx_rb_rac_aperture },
+ { CP_CLUSTER_PS, a6xx_ps_cluster_rbp, ARRAY_SIZE(a6xx_ps_cluster_rbp)/2,
+ &_a6xx_rb_rbp_aperture },
+ { CP_CLUSTER_PS, a6xx_ps_cluster, ARRAY_SIZE(a6xx_ps_cluster)/2,
+ NULL },
+ { CP_CLUSTER_FE, a6xx_fe_cluster, ARRAY_SIZE(a6xx_fe_cluster)/2,
+ NULL },
{ CP_CLUSTER_PC_VS, a6xx_pc_vs_cluster,
- ARRAY_SIZE(a6xx_pc_vs_cluster)/2 },
+ ARRAY_SIZE(a6xx_pc_vs_cluster)/2, NULL },
};
struct a6xx_cluster_regs_info {
@@ -228,9 +262,9 @@
0x1F980, 0x1F986, 0x1F990, 0x1F99E, 0x1F9C0, 0x1F9C0, 0x1F9C5, 0x1F9CC,
0x1F9E0, 0x1F9E2, 0x1F9F0, 0x1F9F0, 0x1FA00, 0x1FA03,
/* GPU RSCC */
- 0x23740, 0x23742, 0x23744, 0x23747, 0x2374C, 0x23787, 0x237EC, 0x237EF,
- 0x237F4, 0x2382F, 0x23894, 0x23897, 0x2389C, 0x238D7, 0x2393C, 0x2393F,
- 0x23944, 0x2397F,
+ 0x2348C, 0x2348C, 0x23501, 0x23502, 0x23740, 0x23742, 0x23744, 0x23747,
+ 0x2374C, 0x23787, 0x237EC, 0x237EF, 0x237F4, 0x2382F, 0x23894, 0x23897,
+ 0x2389C, 0x238D7, 0x2393C, 0x2393F, 0x23944, 0x2397F,
/* GMU AO */
0x23B00, 0x23B16, 0x23C00, 0x23C00,
/* GPU CC */
@@ -243,6 +277,16 @@
0x26400, 0x26416, 0x26420, 0x26427,
};
+static const unsigned int a6xx_rb_rac_registers[] = {
+ 0x8E04, 0x8E05, 0x8E07, 0x8E08, 0x8E10, 0x8E1C, 0x8E20, 0x8E25,
+ 0x8E28, 0x8E28, 0x8E2C, 0x8E2F, 0x8E50, 0x8E52,
+};
+
+static const unsigned int a6xx_rb_rbp_registers[] = {
+ 0x8E01, 0x8E01, 0x8E0C, 0x8E0C, 0x8E3B, 0x8E3E, 0x8E40, 0x8E43,
+ 0x8E53, 0x8E5F, 0x8E70, 0x8E77,
+};
+
static const struct adreno_vbif_snapshot_registers
a6xx_vbif_snapshot_registers[] = {
{ 0x20040000, 0xFF000000, a6xx_vbif_ver_20xxxxxx_registers,
@@ -279,10 +323,6 @@
/* GRAS */
0x8600, 0x8601, 0x8610, 0x861B, 0x8620, 0x8620, 0x8628, 0x862B,
0x8630, 0x8637,
- /* RB */
- 0x8E01, 0x8E01, 0x8E04, 0x8E05, 0x8E07, 0x8E08, 0x8E0C, 0x8E0C,
- 0x8E10, 0x8E1C, 0x8E20, 0x8E25, 0x8E28, 0x8E28, 0x8E2C, 0x8E2F,
- 0x8E3B, 0x8E3E, 0x8E40, 0x8E43, 0x8E50, 0x8E5E, 0x8E70, 0x8E77,
/* VPC */
0x9600, 0x9604, 0x9624, 0x9637,
/* PC */
@@ -393,9 +433,12 @@
{ A6XX_DBGBUS_TPL1_3, 0x100, },
};
+static const struct adreno_debugbus_block a6xx_vbif_debugbus_blocks = {
+ A6XX_DBGBUS_VBIF, 0x100,
+};
+
static void __iomem *a6xx_cx_dbgc;
static const struct adreno_debugbus_block a6xx_cx_dbgc_debugbus_blocks[] = {
- { A6XX_DBGBUS_VBIF, 0x100, },
{ A6XX_DBGBUS_GMU_CX, 0x100, },
{ A6XX_DBGBUS_CX, 0x100, },
};
@@ -510,27 +553,43 @@
static struct kgsl_memdesc a6xx_crashdump_registers;
static bool crash_dump_valid;
-static size_t a6xx_legacy_snapshot_registers(struct kgsl_device *device,
- u8 *buf, size_t remain)
-{
- struct kgsl_snapshot_registers regs = {
- .regs = a6xx_registers,
- .count = ARRAY_SIZE(a6xx_registers) / 2,
- };
-
- return kgsl_snapshot_dump_registers(device, buf, remain, ®s);
-}
-
-static struct cdregs {
+static struct reg_list {
const unsigned int *regs;
- unsigned int size;
-} _a6xx_cd_registers[] = {
- { a6xx_registers, ARRAY_SIZE(a6xx_registers) },
+ unsigned int count;
+ const struct sel_reg *sel;
+} a6xx_reg_list[] = {
+ { a6xx_registers, ARRAY_SIZE(a6xx_registers) / 2, NULL },
+ { a6xx_rb_rac_registers, ARRAY_SIZE(a6xx_rb_rac_registers) / 2,
+ &_a6xx_rb_rac_aperture },
+ { a6xx_rb_rbp_registers, ARRAY_SIZE(a6xx_rb_rbp_registers) / 2,
+ &_a6xx_rb_rbp_aperture },
};
#define REG_PAIR_COUNT(_a, _i) \
(((_a)[(2 * (_i)) + 1] - (_a)[2 * (_i)]) + 1)
+static size_t a6xx_legacy_snapshot_registers(struct kgsl_device *device,
+ u8 *buf, size_t remain)
+{
+ unsigned int i;
+ size_t used = 0;
+
+ for (i = 0; i < ARRAY_SIZE(a6xx_reg_list); i++) {
+ struct reg_list *regs = &a6xx_reg_list[i];
+ struct kgsl_snapshot_registers snapshot_regs = {
+ .regs = regs->regs,
+ .count = regs->count,
+ };
+
+ if (regs->sel)
+ kgsl_regwrite(device, regs->sel->host_reg,
+ regs->sel->val);
+ used += kgsl_snapshot_dump_registers(device, buf + used,
+ remain - used, &snapshot_regs);
+ }
+ return used;
+}
+
static size_t a6xx_snapshot_registers(struct kgsl_device *device, u8 *buf,
size_t remain, void *priv)
{
@@ -550,10 +609,10 @@
remain -= sizeof(*header);
- for (i = 0; i < ARRAY_SIZE(_a6xx_cd_registers); i++) {
- struct cdregs *regs = &_a6xx_cd_registers[i];
+ for (i = 0; i < ARRAY_SIZE(a6xx_reg_list); i++) {
+ struct reg_list *regs = &a6xx_reg_list[i];
- for (j = 0; j < regs->size / 2; j++) {
+ for (j = 0; j < regs->count; j++) {
unsigned int start = regs->regs[2 * j];
unsigned int end = regs->regs[(2 * j) + 1];
@@ -953,6 +1012,10 @@
aperture_cntl = ((cur_cluster->id & 0x7) << 8) | (ctxt << 4) | ctxt;
kgsl_regwrite(device, A6XX_CP_APERTURE_CNTL_HOST, aperture_cntl);
+ if (cur_cluster->sel)
+ kgsl_regwrite(device, cur_cluster->sel->host_reg,
+ cur_cluster->sel->val);
+
for (i = 0; i < cur_cluster->num_sets; i++) {
start = cur_cluster->regs[2 * i];
end = cur_cluster->regs[2 * i + 1];
@@ -1076,7 +1139,7 @@
kgsl_regread(device, A6XX_DBGC_CFG_DBGBUS_TRACE_BUF1, val);
}
-/* a6xx_snapshot_cbgc_debugbus_block() - Capture debug data for a gpu block */
+/* a6xx_snapshot_dbgc_debugbus_block() - Capture debug data for a gpu block */
static size_t a6xx_snapshot_dbgc_debugbus_block(struct kgsl_device *device,
u8 *buf, size_t remain, void *priv)
{
@@ -1115,6 +1178,89 @@
return size;
}
+/* a6xx_snapshot_vbif_debugbus_block() - Capture debug data for VBIF block */
+static size_t a6xx_snapshot_vbif_debugbus_block(struct kgsl_device *device,
+ u8 *buf, size_t remain, void *priv)
+{
+ struct kgsl_snapshot_debugbus *header =
+ (struct kgsl_snapshot_debugbus *)buf;
+ struct adreno_debugbus_block *block = priv;
+ int i, j;
+ /*
+ * Total number of VBIF data words considering 3 sections:
+ * 2 arbiter blocks of 16 words
+ * 5 AXI XIN blocks of 18 dwords each
+ * 4 core clock side XIN blocks of 12 dwords each
+ */
+ unsigned int dwords = (16 * A6XX_NUM_AXI_ARB_BLOCKS) +
+ (18 * A6XX_NUM_XIN_AXI_BLOCKS) +
+ (12 * A6XX_NUM_XIN_CORE_BLOCKS);
+ unsigned int *data = (unsigned int *)(buf + sizeof(*header));
+ size_t size;
+ unsigned int reg_clk;
+
+ size = (dwords * sizeof(unsigned int)) + sizeof(*header);
+
+ if (remain < size) {
+ SNAPSHOT_ERR_NOMEM(device, "DEBUGBUS");
+ return 0;
+ }
+ header->id = block->block_id;
+ header->count = dwords;
+
+ kgsl_regread(device, A6XX_VBIF_CLKON, ®_clk);
+ kgsl_regwrite(device, A6XX_VBIF_CLKON, reg_clk |
+ (A6XX_VBIF_CLKON_FORCE_ON_TESTBUS_MASK <<
+ A6XX_VBIF_CLKON_FORCE_ON_TESTBUS_SHIFT));
+ kgsl_regwrite(device, A6XX_VBIF_TEST_BUS1_CTRL0, 0);
+ kgsl_regwrite(device, A6XX_VBIF_TEST_BUS_OUT_CTRL,
+ (A6XX_VBIF_TEST_BUS_OUT_CTRL_EN_MASK <<
+ A6XX_VBIF_TEST_BUS_OUT_CTRL_EN_SHIFT));
+
+ for (i = 0; i < A6XX_NUM_AXI_ARB_BLOCKS; i++) {
+ kgsl_regwrite(device, A6XX_VBIF_TEST_BUS2_CTRL0,
+ (1 << (i + 16)));
+ for (j = 0; j < 16; j++) {
+ kgsl_regwrite(device, A6XX_VBIF_TEST_BUS2_CTRL1,
+ ((j & A6XX_VBIF_TEST_BUS2_CTRL1_DATA_SEL_MASK)
+ << A6XX_VBIF_TEST_BUS2_CTRL1_DATA_SEL_SHIFT));
+ kgsl_regread(device, A6XX_VBIF_TEST_BUS_OUT,
+ data);
+ data++;
+ }
+ }
+
+ /* XIN blocks AXI side */
+ for (i = 0; i < A6XX_NUM_XIN_AXI_BLOCKS; i++) {
+ kgsl_regwrite(device, A6XX_VBIF_TEST_BUS2_CTRL0, 1 << i);
+ for (j = 0; j < 18; j++) {
+ kgsl_regwrite(device, A6XX_VBIF_TEST_BUS2_CTRL1,
+ ((j & A6XX_VBIF_TEST_BUS2_CTRL1_DATA_SEL_MASK)
+ << A6XX_VBIF_TEST_BUS2_CTRL1_DATA_SEL_SHIFT));
+ kgsl_regread(device, A6XX_VBIF_TEST_BUS_OUT,
+ data);
+ data++;
+ }
+ }
+ kgsl_regwrite(device, A6XX_VBIF_TEST_BUS2_CTRL0, 0);
+
+ /* XIN blocks core clock side */
+ for (i = 0; i < A6XX_NUM_XIN_CORE_BLOCKS; i++) {
+ kgsl_regwrite(device, A6XX_VBIF_TEST_BUS1_CTRL0, 1 << i);
+ for (j = 0; j < 12; j++) {
+ kgsl_regwrite(device, A6XX_VBIF_TEST_BUS1_CTRL1,
+ ((j & A6XX_VBIF_TEST_BUS1_CTRL1_DATA_SEL_MASK)
+ << A6XX_VBIF_TEST_BUS1_CTRL1_DATA_SEL_SHIFT));
+ kgsl_regread(device, A6XX_VBIF_TEST_BUS_OUT,
+ data);
+ data++;
+ }
+ }
+ /* restore the clock of VBIF */
+ kgsl_regwrite(device, A6XX_VBIF_CLKON, reg_clk);
+ return size;
+}
+
static void _cx_dbgc_regread(unsigned int offsetwords, unsigned int *value)
{
void __iomem *reg;
@@ -1310,6 +1456,10 @@
(void *) &a6xx_dbgc_debugbus_blocks[i]);
}
+ kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_DEBUGBUS,
+ snapshot, a6xx_snapshot_vbif_debugbus_block,
+ (void *) &a6xx_vbif_debugbus_blocks);
+
if (a6xx_cx_dbgc) {
for (i = 0; i < ARRAY_SIZE(a6xx_cx_dbgc_debugbus_blocks); i++) {
kgsl_snapshot_add_section(device,
@@ -1499,6 +1649,12 @@
for (i = 0; i < ARRAY_SIZE(a6xx_clusters); i++) {
struct a6xx_cluster_registers *cluster = &a6xx_clusters[i];
+ if (cluster->sel) {
+ ptr[qwords++] = cluster->sel->val;
+ ptr[qwords++] = ((uint64_t)cluster->sel->cd_reg << 44) |
+ (1 << 21) | 1;
+ }
+
cluster->offset0 = *offset;
for (j = 0; j < A6XX_NUM_CTXTS; j++) {
@@ -1507,7 +1663,7 @@
ptr[qwords++] = (cluster->id << 8) | (j << 4) | j;
ptr[qwords++] =
- ((uint64_t)A6XX_CP_APERTURE_CNTL_HOST << 44) |
+ ((uint64_t)A6XX_CP_APERTURE_CNTL_CD << 44) |
(1 << 21) | 1;
for (k = 0; k < cluster->num_sets; k++) {
@@ -1654,14 +1810,18 @@
* To save the registers, we need 16 bytes per register pair for the
* script and a dword for each register in the data
*/
- for (i = 0; i < ARRAY_SIZE(_a6xx_cd_registers); i++) {
- struct cdregs *regs = &_a6xx_cd_registers[i];
+ for (i = 0; i < ARRAY_SIZE(a6xx_reg_list); i++) {
+ struct reg_list *regs = &a6xx_reg_list[i];
+
+ /* 16 bytes for programming the aperture */
+ if (regs->sel)
+ script_size += 16;
/* Each pair needs 16 bytes (2 qwords) */
- script_size += (regs->size / 2) * 16;
+ script_size += regs->count * 16;
/* Each register needs a dword in the data */
- for (j = 0; j < regs->size / 2; j++)
+ for (j = 0; j < regs->count; j++)
data_size += REG_PAIR_COUNT(regs->regs, j) *
sizeof(unsigned int);
@@ -1757,10 +1917,17 @@
ptr = (uint64_t *)a6xx_capturescript.hostptr;
/* For the registers, program a read command for each pair */
- for (i = 0; i < ARRAY_SIZE(_a6xx_cd_registers); i++) {
- struct cdregs *regs = &_a6xx_cd_registers[i];
+ for (i = 0; i < ARRAY_SIZE(a6xx_reg_list); i++) {
+ struct reg_list *regs = &a6xx_reg_list[i];
- for (j = 0; j < regs->size / 2; j++) {
+ /* Program the SEL_CNTL_CD register appropriately */
+ if (regs->sel) {
+ *ptr++ = regs->sel->val;
+ *ptr++ = (((uint64_t)regs->sel->cd_reg << 44)) |
+ (1 << 21) | 1;
+ }
+
+ for (j = 0; j < regs->count; j++) {
unsigned int r = REG_PAIR_COUNT(regs->regs, j);
*ptr++ = a6xx_crashdump_registers.gpuaddr + offset;
*ptr++ = (((uint64_t) regs->regs[2 * j]) << 44) | r;
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
index 422c434..0a45d27 100644
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ b/drivers/gpu/msm/adreno_dispatch.c
@@ -983,6 +983,13 @@
spin_unlock(&dispatcher->plist_lock);
}
+static inline void _decrement_submit_now(struct kgsl_device *device)
+{
+ spin_lock(&device->submit_lock);
+ device->submit_now--;
+ spin_unlock(&device->submit_lock);
+}
+
/**
* adreno_dispatcher_issuecmds() - Issue commmands from pending contexts
* @adreno_dev: Pointer to the adreno device struct
@@ -992,15 +999,29 @@
static void adreno_dispatcher_issuecmds(struct adreno_device *adreno_dev)
{
struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
+ struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+
+ spin_lock(&device->submit_lock);
+ /* If state transition to SLUMBER, schedule the work for later */
+ if (device->slumber == true) {
+ spin_unlock(&device->submit_lock);
+ goto done;
+ }
+ device->submit_now++;
+ spin_unlock(&device->submit_lock);
/* If the dispatcher is busy then schedule the work for later */
if (!mutex_trylock(&dispatcher->mutex)) {
- adreno_dispatcher_schedule(KGSL_DEVICE(adreno_dev));
- return;
+ _decrement_submit_now(device);
+ goto done;
}
_adreno_dispatcher_issuecmds(adreno_dev);
mutex_unlock(&dispatcher->mutex);
+ _decrement_submit_now(device);
+ return;
+done:
+ adreno_dispatcher_schedule(device);
}
/**
@@ -2452,7 +2473,7 @@
mutex_unlock(&device->mutex);
}
-static void adreno_dispatcher_work(struct work_struct *work)
+static void adreno_dispatcher_work(struct kthread_work *work)
{
struct adreno_dispatcher *dispatcher =
container_of(work, struct adreno_dispatcher, work);
@@ -2512,7 +2533,7 @@
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
- kgsl_schedule_work(&dispatcher->work);
+ kthread_queue_work(&kgsl_driver.worker, &dispatcher->work);
}
/**
@@ -2808,7 +2829,7 @@
setup_timer(&dispatcher->fault_timer, adreno_dispatcher_fault_timer,
(unsigned long) adreno_dev);
- INIT_WORK(&dispatcher->work, adreno_dispatcher_work);
+ kthread_init_work(&dispatcher->work, adreno_dispatcher_work);
init_completion(&dispatcher->idle_gate);
complete_all(&dispatcher->idle_gate);
diff --git a/drivers/gpu/msm/adreno_dispatch.h b/drivers/gpu/msm/adreno_dispatch.h
index 72545db..48f0cdc 100644
--- a/drivers/gpu/msm/adreno_dispatch.h
+++ b/drivers/gpu/msm/adreno_dispatch.h
@@ -91,7 +91,7 @@
atomic_t fault;
struct plist_head pending;
spinlock_t plist_lock;
- struct work_struct work;
+ struct kthread_work work;
struct kobject kobj;
struct completion idle_gate;
unsigned int disp_preempt_fair_sched;
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index c6df7bb..0882447 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -548,6 +548,8 @@
mutex_unlock(&device->mutex);
+ debugfs_remove_recursive(drawctxt->debug_root);
+
/* wake threads waiting to submit commands from this context */
wake_up_all(&drawctxt->waiting);
wake_up_all(&drawctxt->wq);
@@ -569,7 +571,6 @@
gpudev->preemption_context_destroy(context);
drawctxt = ADRENO_CONTEXT(context);
- debugfs_remove_recursive(drawctxt->debug_root);
kfree(drawctxt);
}
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 129e99c..9968d8c 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -989,7 +989,6 @@
*/
kgsl_process_uninit_sysfs(private);
- debugfs_remove_recursive(private->debug_root);
process_release_sync_sources(private);
@@ -1001,12 +1000,14 @@
list_del(&private->list);
/*
- * Unlock the mutex before releasing the memory - this prevents a
- * deadlock with the IOMMU mutex if a page fault occurs
+ * Unlock the mutex before releasing the memory and the debugfs
+ * nodes - this prevents deadlocks with the IOMMU and debugfs
+ * locks.
*/
mutex_unlock(&kgsl_driver.process_mutex);
process_release_memory(private);
+ debugfs_remove_recursive(private->debug_root);
kgsl_process_private_put(private);
}
@@ -1925,12 +1926,13 @@
return ret;
}
-static void gpuobj_free_fence_func(void *priv)
+static bool gpuobj_free_fence_func(void *priv)
{
struct kgsl_mem_entry *entry = priv;
INIT_WORK(&entry->work, _deferred_put);
queue_work(kgsl_driver.mem_workqueue, &entry->work);
+ return true;
}
static long gpuobj_free_on_fence(struct kgsl_device_private *dev_priv,
@@ -4645,6 +4647,7 @@
device->id, device->reg_phys, device->reg_len);
rwlock_init(&device->context_lock);
+ spin_lock_init(&device->submit_lock);
setup_timer(&device->idle_timer, kgsl_timer, (unsigned long) device);
@@ -4788,6 +4791,8 @@
static int __init kgsl_core_init(void)
{
int result = 0;
+ struct sched_param param = { .sched_priority = 2 };
+
/* alloc major and minor device numbers */
result = alloc_chrdev_region(&kgsl_driver.major, 0, KGSL_DEVICE_MAX,
"kgsl");
@@ -4854,6 +4859,18 @@
kgsl_driver.mem_workqueue = alloc_workqueue("kgsl-mementry",
WQ_UNBOUND | WQ_MEM_RECLAIM, 0);
+ kthread_init_worker(&kgsl_driver.worker);
+
+ kgsl_driver.worker_thread = kthread_run(kthread_worker_fn,
+ &kgsl_driver.worker, "kgsl_worker_thread");
+
+ if (IS_ERR(kgsl_driver.worker_thread)) {
+ pr_err("unable to start kgsl thread\n");
+ goto err;
+ }
+
+ sched_setscheduler(kgsl_driver.worker_thread, SCHED_FIFO, ¶m);
+
kgsl_events_init();
result = kgsl_drawobjs_cache_init();
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index c54e51e..f80da79 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -25,6 +25,7 @@
#include <linux/regulator/consumer.h>
#include <linux/mm.h>
#include <linux/uaccess.h>
+#include <linux/kthread.h>
#include <asm/cacheflush.h>
/*
@@ -151,6 +152,8 @@
unsigned int full_cache_threshold;
struct workqueue_struct *workqueue;
struct workqueue_struct *mem_workqueue;
+ struct kthread_worker worker;
+ struct task_struct *worker_thread;
};
extern struct kgsl_driver kgsl_driver;
@@ -300,7 +303,7 @@
void *priv;
struct list_head node;
unsigned int created;
- struct work_struct work;
+ struct kthread_work work;
int result;
struct kgsl_event_group *group;
};
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index b621ada..2cc1869 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -85,7 +85,12 @@
{ KGSL_CONTEXT_NO_FAULT_TOLERANCE, "NO_FT" }, \
{ KGSL_CONTEXT_INVALIDATE_ON_FAULT, "INVALIDATE_ON_FAULT" }, \
{ KGSL_CONTEXT_PWR_CONSTRAINT, "PWR" }, \
- { KGSL_CONTEXT_SAVE_GMEM, "SAVE_GMEM" }
+ { KGSL_CONTEXT_SAVE_GMEM, "SAVE_GMEM" }, \
+ { KGSL_CONTEXT_IFH_NOP, "IFH_NOP" }, \
+ { KGSL_CONTEXT_SECURE, "SECURE" }, \
+ { KGSL_CONTEXT_NO_SNAPSHOT, "NO_SNAPSHOT" }, \
+ { KGSL_CONTEXT_SPARSE, "SPARSE" }
+
#define KGSL_CONTEXT_TYPES \
{ KGSL_CONTEXT_TYPE_ANY, "ANY" }, \
@@ -269,6 +274,11 @@
struct kgsl_pwrctrl pwrctrl;
int open_count;
+ /* For GPU inline submission */
+ uint32_t submit_now;
+ spinlock_t submit_lock;
+ bool slumber;
+
struct mutex mutex;
uint32_t state;
uint32_t requested_state;
@@ -664,9 +674,14 @@
static inline int kgsl_state_is_awake(struct kgsl_device *device)
{
+ struct gmu_device *gmu = &device->gmu;
+
if (device->state == KGSL_STATE_ACTIVE ||
device->state == KGSL_STATE_AWARE)
return true;
+ else if (kgsl_gmu_isenabled(device) &&
+ test_bit(GMU_CLK_ON, &gmu->flags))
+ return true;
else
return false;
}
diff --git a/drivers/gpu/msm/kgsl_drawobj.c b/drivers/gpu/msm/kgsl_drawobj.c
index bca3d57..3dbaea4 100644
--- a/drivers/gpu/msm/kgsl_drawobj.c
+++ b/drivers/gpu/msm/kgsl_drawobj.c
@@ -158,10 +158,13 @@
}
/*
- * a generic function to retire a pending sync event and (possibly)
- * kick the dispatcher
+ * a generic function to retire a pending sync event and (possibly) kick the
+ * dispatcher.
+ * Returns false if the event was already marked for cancellation in another
+ * thread. This function should return true if this thread is responsible for
+ * freeing up the memory, and the event will not be cancelled.
*/
-static void drawobj_sync_expire(struct kgsl_device *device,
+static bool drawobj_sync_expire(struct kgsl_device *device,
struct kgsl_drawobj_sync_event *event)
{
struct kgsl_drawobj_sync *syncobj = event->syncobj;
@@ -170,7 +173,7 @@
* leave without doing anything useful
*/
if (!test_and_clear_bit(event->id, &syncobj->pending))
- return;
+ return false;
/*
* If no more pending events, delete the timer and schedule the command
@@ -183,6 +186,7 @@
device->ftbl->drawctxt_sched(device,
event->syncobj->base.context);
}
+ return true;
}
/*
@@ -228,18 +232,23 @@
static void drawobj_destroy_sync(struct kgsl_drawobj *drawobj)
{
struct kgsl_drawobj_sync *syncobj = SYNCOBJ(drawobj);
- unsigned long pending;
+ unsigned long pending = 0;
unsigned int i;
/* Zap the canary timer */
del_timer_sync(&syncobj->timer);
/*
- * Copy off the pending list and clear all pending events - this will
- * render any subsequent asynchronous callback harmless
+ * Copy off the pending list and clear each pending event atomically -
+ * this will render any subsequent asynchronous callback harmless.
+ * This marks each event for deletion. If any pending fence callbacks
+ * run between now and the actual cancel, the associated structures
+ * are kfreed only in the cancel call.
*/
- bitmap_copy(&pending, &syncobj->pending, KGSL_MAX_SYNCPOINTS);
- bitmap_zero(&syncobj->pending, KGSL_MAX_SYNCPOINTS);
+ for_each_set_bit(i, &syncobj->pending, KGSL_MAX_SYNCPOINTS) {
+ if (test_and_clear_bit(i, &syncobj->pending))
+ __set_bit(i, &pending);
+ }
/*
* Clear all pending events - this will render any subsequent async
@@ -259,8 +268,8 @@
drawobj_sync_func, event);
break;
case KGSL_CMD_SYNCPOINT_TYPE_FENCE:
- if (kgsl_sync_fence_async_cancel(event->handle))
- kgsl_drawobj_put(drawobj);
+ kgsl_sync_fence_async_cancel(event->handle);
+ kgsl_drawobj_put(drawobj);
break;
}
}
@@ -320,15 +329,21 @@
}
EXPORT_SYMBOL(kgsl_drawobj_destroy);
-static void drawobj_sync_fence_func(void *priv)
+static bool drawobj_sync_fence_func(void *priv)
{
struct kgsl_drawobj_sync_event *event = priv;
trace_syncpoint_fence_expire(event->syncobj, event->fence_name);
- drawobj_sync_expire(event->device, event);
-
- kgsl_drawobj_put(&event->syncobj->base);
+ /*
+ * Only call kgsl_drawobj_put() if it's not marked for cancellation
+ * in another thread.
+ */
+ if (drawobj_sync_expire(event->device, event)) {
+ kgsl_drawobj_put(&event->syncobj->base);
+ return true;
+ }
+ return false;
}
/* drawobj_add_sync_fence() - Add a new sync fence syncpoint
diff --git a/drivers/gpu/msm/kgsl_events.c b/drivers/gpu/msm/kgsl_events.c
index d042f05..759a966 100644
--- a/drivers/gpu/msm/kgsl_events.c
+++ b/drivers/gpu/msm/kgsl_events.c
@@ -32,7 +32,7 @@
{
list_del(&event->node);
event->result = result;
- queue_work(device->events_wq, &event->work);
+ kthread_queue_work(&kgsl_driver.worker, &event->work);
}
/**
@@ -42,7 +42,7 @@
* Each event callback has its own work struct and is run on a event specific
* workqeuue. This is the worker that queues up the event callback function.
*/
-static void _kgsl_event_worker(struct work_struct *work)
+static void _kgsl_event_worker(struct kthread_work *work)
{
struct kgsl_event *event = container_of(work, struct kgsl_event, work);
int id = KGSL_CONTEXT_ID(event->context);
@@ -286,7 +286,7 @@
event->created = jiffies;
event->group = group;
- INIT_WORK(&event->work, _kgsl_event_worker);
+ kthread_init_work(&event->work, _kgsl_event_worker);
trace_kgsl_register_event(KGSL_CONTEXT_ID(context), timestamp, func);
@@ -301,7 +301,7 @@
if (timestamp_cmp(retired, timestamp) >= 0) {
event->result = KGSL_EVENT_RETIRED;
- queue_work(device->events_wq, &event->work);
+ kthread_queue_work(&kgsl_driver.worker, &event->work);
spin_unlock(&group->lock);
return 0;
}
diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c
index dff46d2..8060672 100644
--- a/drivers/gpu/msm/kgsl_gmu.c
+++ b/drivers/gpu/msm/kgsl_gmu.c
@@ -51,6 +51,8 @@
unsigned int image_start;
};
+static void gmu_snapshot(struct kgsl_device *device);
+
struct gmu_iommu_context {
const char *name;
struct device *dev;
@@ -436,27 +438,34 @@
struct kgsl_device *device = container_of(gmu, struct kgsl_device, gmu);
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
- struct kgsl_pwrctrl *pwr = &device->pwrctrl;
int perf_idx = INVALID_DCVS_IDX, bw_idx = INVALID_DCVS_IDX;
+ int ret;
- if (gpu_pwrlevel < gmu->num_gpupwrlevels)
+ if (gpu_pwrlevel < gmu->num_gpupwrlevels - 1)
perf_idx = gmu->num_gpupwrlevels - gpu_pwrlevel - 1;
- if (bus_level < gmu->num_bwlevels)
+ if (bus_level < gmu->num_bwlevels && bus_level > 0)
bw_idx = bus_level;
if ((perf_idx == INVALID_DCVS_IDX) &&
(bw_idx == INVALID_DCVS_IDX))
return -EINVAL;
- if (bw_idx == INVALID_DCVS_IDX)
- /* Use default BW, algorithm changes on V2 */
- bw_idx = pwr->pwrlevels[gpu_pwrlevel].bus_freq;
-
- if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG))
- return gpudev->rpmh_gpu_pwrctrl(adreno_dev,
+ if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) {
+ ret = gpudev->rpmh_gpu_pwrctrl(adreno_dev,
GMU_DCVS_NOHFI, perf_idx, bw_idx);
+ if (ret) {
+ dev_err(&gmu->pdev->dev,
+ "Failed to set GPU perf idx %d, bw idx %d\n",
+ perf_idx, bw_idx);
+
+ gmu_snapshot(device);
+ }
+
+ return ret;
+ }
+
return hfi_send_dcvs_vote(gmu, perf_idx, bw_idx, ACK_NONBLOCK);
}
@@ -505,7 +514,11 @@
}
cmd_db_get_aux_data(res_id, (uint8_t *)arc->val, len);
- arc->num = len >> 1;
+ for (arc->num = 1; arc->num <= MAX_GX_LEVELS; arc->num++) {
+ if (arc->num == MAX_GX_LEVELS ||
+ arc->val[arc->num - 1] >= arc->val[arc->num])
+ break;
+ }
return 0;
}
@@ -528,35 +541,42 @@
{
int i, j, k;
uint16_t cur_vlvl;
+ bool found_match;
/* i tracks current KGSL GPU frequency table entry
* j tracks second rail voltage table entry
* k tracks primary rail voltage table entry
*/
- for (i = 0, k = 0; i < num_entries; k++) {
- if (pri_rail->val[k] != vlvl[i]) {
- if (k >= pri_rail->num)
- return -EINVAL;
- continue;
- }
- votes[i].pri_idx = k;
- votes[i].vlvl = vlvl[i];
- cur_vlvl = vlvl[i];
+ for (i = 0; i < num_entries; i++) {
+ found_match = false;
- /* find index of second rail vlvl array element that
- * its vlvl >= current vlvl of primary rail
- */
- for (j = 0; j < sec_rail->num; j++) {
- if (sec_rail->val[j] >= cur_vlvl) {
- votes[i].sec_idx = j;
+ /* Look for a primary rail voltage that matches a VLVL level */
+ for (k = 0; k < pri_rail->num; k++) {
+ if (pri_rail->val[k] == vlvl[i]) {
+ votes[i].pri_idx = k;
+ votes[i].vlvl = vlvl[i];
+ cur_vlvl = vlvl[i];
+ found_match = true;
break;
}
}
- if (j == sec_rail->num)
- votes[i].sec_idx = j;
+ /* If we did not find a matching VLVL level then abort */
+ if (!found_match)
+ return -EINVAL;
- i++;
+ /*
+ * Look for a secondary rail index whose VLVL value
+ * is greater than or equal to the VLVL value of the
+ * corresponding index of the primary rail
+ */
+ for (j = 0; j < sec_rail->num; j++) {
+ if (sec_rail->val[j] >= cur_vlvl ||
+ j + 1 == sec_rail->num) {
+ votes[i].sec_idx = j;
+ break;
+ }
+ }
}
return 0;
}
@@ -575,26 +595,25 @@
struct rpmh_arc_vals *sec_rail,
unsigned int type)
{
+ struct device *dev;
+ struct kgsl_device *device = container_of(gmu, struct kgsl_device, gmu);
unsigned int num_freqs;
struct arc_vote_desc *votes;
unsigned int vlvl_tbl[MAX_GX_LEVELS];
unsigned int *freq_tbl;
int i, ret;
- /*
- * FIXME: remove below two arrays after OPP VLVL query API ready
- * struct dev_pm_opp *opp;
- */
- uint16_t gpu_vlvl[] = {0, 128, 256, 384};
- uint16_t cx_vlvl[] = {0, 48, 256};
+ struct dev_pm_opp *opp;
if (type == GPU_ARC_VOTE) {
num_freqs = gmu->num_gpupwrlevels;
votes = gmu->rpmh_votes.gx_votes;
- freq_tbl = gmu->gmu_freqs;
+ freq_tbl = gmu->gpu_freqs;
+ dev = &device->pdev->dev;
} else if (type == GMU_ARC_VOTE) {
num_freqs = gmu->num_gmupwrlevels;
votes = gmu->rpmh_votes.cx_votes;
- freq_tbl = gmu->gpu_freqs;
+ freq_tbl = gmu->gmu_freqs;
+ dev = &gmu->pdev->dev;
} else {
return -EINVAL;
}
@@ -606,26 +625,25 @@
return -EINVAL;
}
- /*
- * FIXME: Find a core's voltage VLVL value based on its frequency
- * using OPP framework, waiting for David Colin, ETA Jan.
- */
+ memset(vlvl_tbl, 0, sizeof(vlvl_tbl));
for (i = 0; i < num_freqs; i++) {
- /*
- * opp = dev_pm_opp_find_freq_exact(&gmu->pdev->dev,
- * freq_tbl[i], true);
- * if (IS_ERR(opp)) {
- * dev_err(&gmu->pdev->dev,
- * "Failed to find opp freq %d of %s\n",
- * freq_tbl[i], debug_strs[type]);
- * return PTR_ERR(opp);
- * }
- * vlvl_tbl[i] = dev_pm_opp_get_voltage(opp);
- */
- if (type == GPU_ARC_VOTE)
- vlvl_tbl[i] = gpu_vlvl[i];
- else
- vlvl_tbl[i] = cx_vlvl[i];
+ /* Hardcode VLVL for 0 because it is not registered in OPP */
+ if (freq_tbl[i] == 0) {
+ vlvl_tbl[i] = 0;
+ continue;
+ }
+
+ /* Otherwise get the value from the OPP API */
+ opp = dev_pm_opp_find_freq_exact(dev, freq_tbl[i], true);
+ if (IS_ERR(opp)) {
+ dev_err(&gmu->pdev->dev,
+ "Failed to find opp freq %d of %s\n",
+ freq_tbl[i], debug_strs[type]);
+ return PTR_ERR(opp);
+ }
+
+ /* Values from OPP framework are offset by 1 */
+ vlvl_tbl[i] = dev_pm_opp_get_voltage(opp) - 1;
}
ret = setup_volt_dependency_tbl(votes,
@@ -1130,6 +1148,7 @@
goto error;
gmu->num_gpupwrlevels = pwr->num_pwrlevels;
+ gmu->wakeup_pwrlevel = pwr->default_pwrlevel;
for (i = 0; i < gmu->num_gpupwrlevels; i++) {
int j = gmu->num_gpupwrlevels - 1 - i;
@@ -1166,6 +1185,8 @@
else
gmu->idle_level = GPU_HW_ACTIVE;
+ /* disable LM during boot time */
+ clear_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag);
return 0;
error:
@@ -1206,20 +1227,11 @@
static int gmu_disable_clks(struct gmu_device *gmu)
{
- int ret, j = 0;
- unsigned int gmu_freq;
+ int j = 0;
if (IS_ERR_OR_NULL(gmu->clks[0]))
return 0;
- gmu_freq = gmu->gmu_freqs[gmu->num_gmupwrlevels - 1];
- ret = clk_set_rate(gmu->clks[0], gmu_freq);
- if (ret) {
- dev_err(&gmu->pdev->dev, "fail to reset GMU clk freq %d\n",
- gmu_freq);
- return ret;
- }
-
while ((j < MAX_GMU_CLKS) && gmu->clks[j]) {
clk_disable_unprepare(gmu->clks[j]);
j++;
@@ -1332,15 +1344,44 @@
return 0;
}
+static void gmu_snapshot(struct kgsl_device *device)
+{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct gmu_device *gmu = &device->gmu;
+
+ if (!test_and_set_bit(GMU_FAULT, &gmu->flags)) {
+ /* Mask so there's no interrupt caused by NMI */
+ adreno_write_gmureg(adreno_dev,
+ ADRENO_REG_GMU_GMU2HOST_INTR_MASK, 0xFFFFFFFF);
+
+ /* Make sure the interrupt is masked before causing it */
+ wmb();
+ adreno_write_gmureg(adreno_dev,
+ ADRENO_REG_GMU_NMI_CONTROL_STATUS, 0);
+ adreno_write_gmureg(adreno_dev,
+ ADRENO_REG_GMU_CM3_CFG, (1 << 9));
+
+ /* Wait for the NMI to be handled */
+ wmb();
+ udelay(100);
+ kgsl_device_snapshot(device, NULL);
+
+ adreno_write_gmureg(adreno_dev,
+ ADRENO_REG_GMU_GMU2HOST_INTR_CLR, 0xFFFFFFFF);
+ adreno_write_gmureg(adreno_dev,
+ ADRENO_REG_GMU_GMU2HOST_INTR_MASK,
+ (unsigned int) ~HFI_IRQ_MASK);
+ }
+}
+
/* To be called to power on both GPU and GMU */
int gmu_start(struct kgsl_device *device)
{
- int ret = 0, perf_idx;
+ int ret = 0;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
struct gmu_device *gmu = &device->gmu;
- int bus_level = pwr->pwrlevels[pwr->default_pwrlevel].bus_freq;
switch (device->state) {
case KGSL_STATE_INIT:
@@ -1349,13 +1390,9 @@
gmu_enable_gdsc(gmu);
gmu_enable_clks(gmu);
- /* Convert to RPMh frequency index */
- perf_idx = gmu->num_gpupwrlevels -
- pwr->default_pwrlevel - 1;
-
/* Vote for 300MHz DDR for GMU to init */
ret = msm_bus_scale_client_update_request(gmu->pcl,
- bus_level);
+ pwr->pwrlevels[pwr->default_pwrlevel].bus_freq);
if (ret) {
dev_err(&gmu->pdev->dev,
"Failed to allocate gmu b/w\n");
@@ -1374,7 +1411,8 @@
goto error_gpu;
/* Send default DCVS level */
- ret = gmu_dcvs_set(gmu, perf_idx, bus_level);
+ ret = gmu_dcvs_set(gmu, pwr->default_pwrlevel,
+ pwr->pwrlevels[pwr->default_pwrlevel].bus_freq);
if (ret)
goto error_gpu;
@@ -1386,8 +1424,6 @@
gmu_enable_gdsc(gmu);
gmu_enable_clks(gmu);
- perf_idx = gmu->num_gpupwrlevels - gmu->wakeup_pwrlevel - 1;
-
ret = gpudev->rpmh_gpu_pwrctrl(adreno_dev, GMU_FW_START,
GMU_WARM_BOOT, 0);
if (ret)
@@ -1399,12 +1435,12 @@
if (ret)
goto error_gpu;
- if (gmu->wakeup_pwrlevel != pwr->default_pwrlevel) {
- ret = gmu_dcvs_set(gmu, perf_idx, bus_level);
- if (ret)
- goto error_gpu;
- gmu->wakeup_pwrlevel = pwr->default_pwrlevel;
- }
+ ret = gmu_dcvs_set(gmu, gmu->wakeup_pwrlevel,
+ pwr->pwrlevels[gmu->wakeup_pwrlevel].bus_freq);
+ if (ret)
+ goto error_gpu;
+
+ gmu->wakeup_pwrlevel = pwr->default_pwrlevel;
break;
case KGSL_STATE_RESET:
@@ -1413,11 +1449,6 @@
gmu_enable_gdsc(gmu);
gmu_enable_clks(gmu);
- perf_idx = gmu->num_gpupwrlevels -
- pwr->active_pwrlevel - 1;
-
- bus_level =
- pwr->pwrlevels[pwr->active_pwrlevel].bus_freq;
ret = gpudev->rpmh_gpu_pwrctrl(
adreno_dev, GMU_FW_START, GMU_RESET, 0);
if (ret)
@@ -1430,7 +1461,9 @@
goto error_gpu;
/* Send DCVS level prior to reset*/
- ret = gmu_dcvs_set(gmu, perf_idx, bus_level);
+ ret = gmu_dcvs_set(gmu, pwr->active_pwrlevel,
+ pwr->pwrlevels[pwr->active_pwrlevel]
+ .bus_freq);
if (ret)
goto error_gpu;
@@ -1439,19 +1472,13 @@
OOB_CPINIT_CHECK_MASK,
OOB_CPINIT_CLEAR_MASK);
- } else {
+ } else
gmu_fast_boot(device);
- }
break;
default:
break;
}
- /*
- * OOB to enable power management of GMU.
- * In v2, this function call shall move ahead
- * of hfi_start() to save power.
- */
if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG))
gpudev->oob_clear(adreno_dev,
OOB_BOOT_SLUMBER_CLEAR_MASK);
@@ -1459,15 +1486,17 @@
return ret;
error_gpu:
+ gmu_snapshot(device);
hfi_stop(gmu);
gmu_irq_disable(device);
- if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG))
- gpudev->oob_clear(adreno_dev,
- OOB_BOOT_SLUMBER_CLEAR_MASK);
+ if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG))
+ gpudev->oob_clear(adreno_dev,
+ OOB_BOOT_SLUMBER_CLEAR_MASK);
gpudev->rpmh_gpu_pwrctrl(adreno_dev, GMU_FW_STOP, 0, 0);
error_bus:
- msm_bus_scale_client_update_request(gmu->pcl, 0);
+ msm_bus_scale_client_update_request(gmu->pcl, 0);
error_clks:
+ gmu_snapshot(device);
gmu_disable_clks(gmu);
gmu_disable_gdsc(gmu);
return ret;
diff --git a/drivers/gpu/msm/kgsl_gmu.h b/drivers/gpu/msm/kgsl_gmu.h
index a741beb..63ca028 100644
--- a/drivers/gpu/msm/kgsl_gmu.h
+++ b/drivers/gpu/msm/kgsl_gmu.h
@@ -82,6 +82,7 @@
GMU_BOOT_INIT_DONE = 0,
GMU_CLK_ON = 1,
GMU_HFI_ON = 2,
+ GMU_FAULT = 3
};
/**
diff --git a/drivers/gpu/msm/kgsl_hfi.c b/drivers/gpu/msm/kgsl_hfi.c
index cc878aa..68e0f3a 100644
--- a/drivers/gpu/msm/kgsl_hfi.c
+++ b/drivers/gpu/msm/kgsl_hfi.c
@@ -602,15 +602,23 @@
if (result)
return result;
- /*
- * FW is not ready for LM configuration
- * without powering on GPU.
- */
- /*
- * result = hfi_send_lmconfig(gmu);
- * if (result)
- * return result;
- */
+ if (ADRENO_FEATURE(adreno_dev, ADRENO_LM) &&
+ test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag)) {
+ gmu->lm_config.lm_type = 1;
+ gmu->lm_config.lm_sensor_type = 1;
+ gmu->lm_config.throttle_config = 1;
+ gmu->lm_config.idle_throttle_en = 0;
+ gmu->lm_config.acd_en = 0;
+ gmu->bcl_config = 0;
+ gmu->lm_dcvs_level = 0;
+
+ result = hfi_send_lmconfig(gmu);
+ if (result) {
+ dev_err(dev, "Failire enabling limits management (%d)\n",
+ result);
+ return result;
+ }
+ }
set_bit(GMU_HFI_ON, &gmu->flags);
return 0;
diff --git a/drivers/gpu/msm/kgsl_pool.c b/drivers/gpu/msm/kgsl_pool.c
index c31a85b..685ce3e 100644
--- a/drivers/gpu/msm/kgsl_pool.c
+++ b/drivers/gpu/msm/kgsl_pool.c
@@ -65,26 +65,19 @@
/* Map the page into kernel and zero it out */
static void
-_kgsl_pool_zero_page(struct page *p, unsigned int pool_order)
+_kgsl_pool_zero_page(struct page *p)
{
- int i;
+ void *addr = kmap_atomic(p);
- for (i = 0; i < (1 << pool_order); i++) {
- struct page *page = nth_page(p, i);
- void *addr = kmap_atomic(page);
-
- memset(addr, 0, PAGE_SIZE);
- dmac_flush_range(addr, addr + PAGE_SIZE);
- kunmap_atomic(addr);
- }
+ memset(addr, 0, PAGE_SIZE);
+ dmac_flush_range(addr, addr + PAGE_SIZE);
+ kunmap_atomic(addr);
}
/* Add a page to specified pool */
static void
_kgsl_pool_add_page(struct kgsl_page_pool *pool, struct page *p)
{
- _kgsl_pool_zero_page(p, pool->pool_order);
-
spin_lock(&pool->list_lock);
list_add_tail(&p->lru, &pool->page_list);
pool->page_count++;
@@ -329,7 +322,6 @@
} else
return -ENOMEM;
}
- _kgsl_pool_zero_page(page, order);
goto done;
}
@@ -349,7 +341,6 @@
page = alloc_pages(gfp_mask, order);
if (page == NULL)
return -ENOMEM;
- _kgsl_pool_zero_page(page, order);
goto done;
}
}
@@ -379,13 +370,12 @@
} else
return -ENOMEM;
}
-
- _kgsl_pool_zero_page(page, order);
}
done:
for (j = 0; j < (*page_size >> PAGE_SHIFT); j++) {
p = nth_page(page, j);
+ _kgsl_pool_zero_page(p);
pages[pcount] = p;
pcount++;
}
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 5c53a05c..2999fb2 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -68,8 +68,7 @@
"rbcpr_clk",
"iref_clk",
"gmu_clk",
- "ahb_clk",
- "cxo_clk"
+ "ahb_clk"
};
static unsigned int ib_votes[KGSL_MAX_BUSLEVELS];
@@ -224,15 +223,16 @@
{
struct gmu_device *gmu = &device->gmu;
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
- int ret;
+ int ret = 0;
/* GMU scales BW */
if (kgsl_gmu_isenabled(device)) {
- if (!(gmu->flags & GMU_HFI_ON))
+ if (!(gmu->flags & GMU_HFI_ON) || !buslevel)
+ /* Zero bus level is invalid for GMU to vote */
return 0;
ret = gmu_dcvs_set(gmu, INVALID_DCVS_IDX, buslevel);
- } else {
+ } else if (pwr->pcl) {
/* Linux bus driver scales BW */
ret = msm_bus_scale_client_update_request(pwr->pcl, buslevel);
}
@@ -253,23 +253,30 @@
{
struct gmu_device *gmu = &device->gmu;
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+ struct kgsl_pwrlevel *pl = &pwr->pwrlevels[pwrlevel];
int ret = 0;
/* GMU scales GPU freq */
if (kgsl_gmu_isenabled(device)) {
/* If GMU has not been started, save it */
if (!(gmu->flags & GMU_HFI_ON)) {
+ /* In slumber the clock is off so we are done */
+ if (pwrlevel == (gmu->num_gpupwrlevels - 1))
+ return 0;
+
gmu->wakeup_pwrlevel = pwrlevel;
return 0;
}
+ /* If the GMU is on we cannot vote for the lowest level */
+ if (pwrlevel == (gmu->num_gpupwrlevels - 1)) {
+ WARN(1, "Cannot set 0 GPU frequency with GMU\n");
+ return -EINVAL;
+ }
ret = gmu_dcvs_set(gmu, pwrlevel, INVALID_DCVS_IDX);
- } else {
+ } else
/* Linux clock driver scales GPU freq */
- struct kgsl_pwrlevel *Pl = &pwr->pwrlevels[pwrlevel];
-
- ret = clk_set_rate(pwr->grp_clks[0], Pl->gpu_freq);
- }
+ ret = clk_set_rate(pwr->grp_clks[0], pl->gpu_freq);
if (ret)
KGSL_PWR_ERR(device, "GPU clk freq set failure\n");
@@ -291,7 +298,8 @@
unsigned long ab;
/* the bus should be ON to update the active frequency */
- if (on && !(test_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->power_flags)))
+ if (!(kgsl_gmu_isenabled(device)) && on &&
+ !(test_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->power_flags)))
return;
/*
* If the bus should remain on calculate our request and submit it,
@@ -321,9 +329,7 @@
msm_bus_scale_client_update_request(pwr->ocmem_pcl,
on ? pwr->active_pwrlevel : pwr->num_pwrlevels - 1);
- /* vote for bus if gpubw-dev support is not enabled */
- if (pwr->pcl)
- kgsl_bus_scale_request(device, buslevel);
+ kgsl_bus_scale_request(device, buslevel);
kgsl_pwrctrl_vbif_update(ab);
}
@@ -1049,6 +1055,8 @@
if (on) {
switch (flag) {
case KGSL_PWRFLAGS_CLK_ON:
+ /* make sure pwrrail is ON before enabling clocks */
+ kgsl_pwrctrl_pwrrail(device, KGSL_PWRFLAGS_ON);
kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_ON,
KGSL_STATE_ACTIVE);
break;
@@ -1784,8 +1792,6 @@
{
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
- if (kgsl_gmu_isenabled(device))
- return;
if (test_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->ctrl_flags))
return;
@@ -1854,7 +1860,12 @@
if (kgsl_gmu_isenabled(device))
return 0;
- if (test_bit(KGSL_PWRFLAGS_POWER_ON, &pwr->ctrl_flags))
+ /*
+ * Disabling the regulator means also disabling dependent clocks.
+ * Hence don't disable it if force clock ON is set.
+ */
+ if (test_bit(KGSL_PWRFLAGS_POWER_ON, &pwr->ctrl_flags) ||
+ test_bit(KGSL_PWRFLAGS_CLK_ON, &pwr->ctrl_flags))
return 0;
if (state == KGSL_PWRFLAGS_OFF) {
@@ -2362,9 +2373,24 @@
|| device->state == KGSL_STATE_NAP) {
if (!atomic_read(&device->active_cnt)) {
+ spin_lock(&device->submit_lock);
+ if (device->submit_now) {
+ spin_unlock(&device->submit_lock);
+ goto done;
+ }
+ /* Don't allow GPU inline submission in SLUMBER */
+ if (requested_state == KGSL_STATE_SLUMBER)
+ device->slumber = true;
+ spin_unlock(&device->submit_lock);
+
ret = kgsl_pwrctrl_change_state(device,
device->requested_state);
if (ret == -EBUSY) {
+ if (requested_state == KGSL_STATE_SLUMBER) {
+ spin_lock(&device->submit_lock);
+ device->slumber = false;
+ spin_unlock(&device->submit_lock);
+ }
/*
* If the GPU is currently busy, restore
* the requested state and reschedule
@@ -2375,7 +2401,7 @@
kgsl_schedule_work(&device->idle_check_ws);
}
}
-
+done:
if (!ret)
kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
@@ -2449,8 +2475,13 @@
kgsl_pwrctrl_pwrlevel_change(device, level);
- if (kgsl_gmu_isenabled(device))
- return gmu_start(device);
+ if (kgsl_gmu_isenabled(device)) {
+ int ret = gmu_start(device);
+
+ if (!ret)
+ kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_ON);
+ return ret;
+ }
/* Order pwrrail/clk sequence based upon platform */
status = kgsl_pwrctrl_pwrrail(device, KGSL_PWRFLAGS_ON);
@@ -2463,8 +2494,10 @@
static void kgsl_pwrctrl_disable(struct kgsl_device *device)
{
- if (kgsl_gmu_isenabled(device))
+ if (kgsl_gmu_isenabled(device)) {
+ kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_OFF);
return gmu_stop(device);
+ }
/* Order pwrrail/clk sequence based upon platform */
device->ftbl->regulator_disable(device);
@@ -2835,6 +2868,13 @@
trace_kgsl_pwr_set_state(device, state);
device->state = state;
device->requested_state = KGSL_STATE_NONE;
+
+ spin_lock(&device->submit_lock);
+ if (state == KGSL_STATE_SLUMBER || state == KGSL_STATE_SUSPEND)
+ device->slumber = true;
+ else
+ device->slumber = false;
+ spin_unlock(&device->submit_lock);
}
static void kgsl_pwrctrl_request_state(struct kgsl_device *device,
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index 6b22fd4..65e047d 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.h
+++ b/drivers/gpu/msm/kgsl_pwrctrl.h
@@ -25,7 +25,7 @@
#define KGSL_PWR_ON 0xFFFF
-#define KGSL_MAX_CLKS 17
+#define KGSL_MAX_CLKS 16
#define KGSL_MAX_REGULATORS 2
#define KGSL_MAX_PWRLEVELS 10
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index f0f202b..5061f6a 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -741,6 +741,8 @@
*/
memdesc->pages = kgsl_malloc(len_alloc * sizeof(struct page *));
+ memdesc->page_count = 0;
+ memdesc->size = 0;
if (memdesc->pages == NULL) {
ret = -ENOMEM;
diff --git a/drivers/gpu/msm/kgsl_sync.c b/drivers/gpu/msm/kgsl_sync.c
index 817a6b1..015d07f 100644
--- a/drivers/gpu/msm/kgsl_sync.c
+++ b/drivers/gpu/msm/kgsl_sync.c
@@ -370,7 +370,8 @@
unsigned long flags;
struct kgsl_sync_fence *kfence, *next;
- kref_get(&ktimeline->kref);
+ if (!kref_get_unless_zero(&ktimeline->kref))
+ return;
spin_lock_irqsave(&ktimeline->lock, flags);
if (timestamp_cmp(timestamp, ktimeline->last_timestamp) > 0)
@@ -427,9 +428,14 @@
{
struct kgsl_sync_fence_cb *kcb = (struct kgsl_sync_fence_cb *)cb;
- kcb->func(kcb->priv);
- fence_put(kcb->fence);
- kfree(kcb);
+ /*
+ * If the callback is marked for cancellation in a separate thread,
+ * let the other thread do the cleanup.
+ */
+ if (kcb->func(kcb->priv)) {
+ fence_put(kcb->fence);
+ kfree(kcb);
+ }
}
static void kgsl_get_fence_name(struct fence *fence,
@@ -452,7 +458,7 @@
}
struct kgsl_sync_fence_cb *kgsl_sync_fence_async_wait(int fd,
- void (*func)(void *priv), void *priv, char *fence_name, int name_len)
+ bool (*func)(void *priv), void *priv, char *fence_name, int name_len)
{
struct kgsl_sync_fence_cb *kcb;
struct fence *fence;
@@ -492,17 +498,24 @@
return kcb;
}
-int kgsl_sync_fence_async_cancel(struct kgsl_sync_fence_cb *kcb)
+/*
+ * Cancel the fence async callback and do the cleanup. The caller must make
+ * sure that the callback (if run before cancelling) returns false, so that
+ * no other thread frees the pointer.
+ */
+void kgsl_sync_fence_async_cancel(struct kgsl_sync_fence_cb *kcb)
{
if (kcb == NULL)
- return 0;
+ return;
- if (fence_remove_callback(kcb->fence, &kcb->fence_cb)) {
- fence_put(kcb->fence);
- kfree(kcb);
- return 1;
- }
- return 0;
+ /*
+ * After fence_remove_callback() returns, the fence callback is
+ * either not called at all, or completed without freeing kcb.
+ * This thread can then put the fence refcount and free kcb.
+ */
+ fence_remove_callback(kcb->fence, &kcb->fence_cb);
+ fence_put(kcb->fence);
+ kfree(kcb);
}
struct kgsl_syncsource {
diff --git a/drivers/gpu/msm/kgsl_sync.h b/drivers/gpu/msm/kgsl_sync.h
index 99fe0e1..d58859d 100644
--- a/drivers/gpu/msm/kgsl_sync.h
+++ b/drivers/gpu/msm/kgsl_sync.h
@@ -68,13 +68,14 @@
* fence_cb: Fence callback struct
* fence: Pointer to the fence for which the callback is done
* priv: Private data for the callback
- * func: Pointer to the kgsl function to call
+ * func: Pointer to the kgsl function to call. This function should return
+ * false if the sync callback is marked for cancellation in a separate thread.
*/
struct kgsl_sync_fence_cb {
struct fence_cb fence_cb;
struct fence *fence;
void *priv;
- void (*func)(void *priv);
+ bool (*func)(void *priv);
};
struct kgsl_syncsource;
@@ -91,10 +92,10 @@
void kgsl_sync_timeline_put(struct kgsl_sync_timeline *ktimeline);
struct kgsl_sync_fence_cb *kgsl_sync_fence_async_wait(int fd,
- void (*func)(void *priv), void *priv,
+ bool (*func)(void *priv), void *priv,
char *fence_name, int name_len);
-int kgsl_sync_fence_async_cancel(struct kgsl_sync_fence_cb *kcb);
+void kgsl_sync_fence_async_cancel(struct kgsl_sync_fence_cb *kcb);
long kgsl_ioctl_syncsource_create(struct kgsl_device_private *dev_priv,
unsigned int cmd, void *data);
@@ -143,10 +144,9 @@
return NULL;
}
-static inline int
+static inline void
kgsl_sync_fence_async_cancel(struct kgsl_sync_fence_cb *kcb)
{
- return 1;
}
static inline long
diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h
index 1767810..c7690a1 100644
--- a/drivers/gpu/msm/kgsl_trace.h
+++ b/drivers/gpu/msm/kgsl_trace.h
@@ -820,14 +820,14 @@
TRACE_EVENT(kgsl_mmu_pagefault,
- TP_PROTO(struct kgsl_device *device, unsigned int page,
+ TP_PROTO(struct kgsl_device *device, unsigned long page,
unsigned int pt, const char *op),
TP_ARGS(device, page, pt, op),
TP_STRUCT__entry(
__string(device_name, device->name)
- __field(unsigned int, page)
+ __field(unsigned long, page)
__field(unsigned int, pt)
__string(op, op)
),
@@ -840,7 +840,7 @@
),
TP_printk(
- "d_name=%s page=0x%08x pt=%u op=%s",
+ "d_name=%s page=0x%lx pt=%u op=%s",
__get_str(device_name), __entry->page, __entry->pt,
__get_str(op)
)
diff --git a/drivers/hwtracing/coresight/coresight-ost.c b/drivers/hwtracing/coresight/coresight-ost.c
index 63fea00..3399c27 100644
--- a/drivers/hwtracing/coresight/coresight-ost.c
+++ b/drivers/hwtracing/coresight/coresight-ost.c
@@ -12,6 +12,7 @@
#include <linux/device.h>
#include <linux/bitmap.h>
+#include <linux/io.h>
#include "coresight-ost.h"
#define STM_USERSPACE_HEADER_SIZE (8)
@@ -54,19 +55,40 @@
return ch;
}
-static int stm_ost_send(void *addr, const void *data, uint32_t count)
+static int stm_ost_send(void __iomem *addr, const void *data, uint32_t size)
{
- struct stm_drvdata *drvdata = stmdrvdata;
- const unsigned char *p = data;
- size_t pos;
- ssize_t sz;
+ uint32_t len = size;
- for (pos = 0, p = data; count > pos; pos += sz, p += sz) {
- sz = min_t(unsigned int, count - pos, drvdata->write_bytes);
- stm_send(addr, p, sz, drvdata->write_bytes);
+ if (((unsigned long)data & 0x1) && (size >= 1)) {
+ writeb_relaxed_no_log(*(uint8_t *)data, addr);
+ data++;
+ size--;
+ }
+ if (((unsigned long)data & 0x2) && (size >= 2)) {
+ writew_relaxed_no_log(*(uint16_t *)data, addr);
+ data += 2;
+ size -= 2;
}
- return count;
+ /* now we are 32bit aligned */
+ while (size >= 4) {
+ writel_relaxed_no_log(*(uint32_t *)data, addr);
+ data += 4;
+ size -= 4;
+ }
+
+ if (size >= 2) {
+ writew_relaxed_no_log(*(uint16_t *)data, addr);
+ data += 2;
+ size -= 2;
+ }
+ if (size >= 1) {
+ writeb_relaxed_no_log(*(uint8_t *)data, addr);
+ data++;
+ size--;
+ }
+
+ return len;
}
static void stm_channel_free(uint32_t ch)
@@ -76,10 +98,10 @@
clear_bit(ch, drvdata->chs.bitmap);
}
-static int stm_trace_ost_header(unsigned long ch_addr, uint32_t flags,
+static int stm_trace_ost_header(void __iomem *ch_addr, uint32_t flags,
uint8_t entity_id, uint8_t proto_id)
{
- void *addr;
+ void __iomem *addr;
uint32_t header;
char *hdr;
@@ -93,12 +115,13 @@
/* header is expected to be D32M type */
flags |= STM_FLAG_MARKED;
flags &= ~STM_FLAG_TIMESTAMPED;
- addr = (void *)(ch_addr | stm_channel_off(STM_PKT_TYPE_DATA, flags));
+ addr = (void __iomem *)(ch_addr +
+ stm_channel_off(STM_PKT_TYPE_DATA, flags));
return stm_ost_send(addr, &header, sizeof(header));
}
-static int stm_trace_data_header(void *addr)
+static int stm_trace_data_header(void __iomem *addr)
{
char hdr[16];
int len = 0;
@@ -114,14 +137,15 @@
return len;
}
-static int stm_trace_data(unsigned long ch_addr, uint32_t flags,
+static int stm_trace_data(void __iomem *ch_addr, uint32_t flags,
const void *data, uint32_t size)
{
- void *addr;
+ void __iomem *addr;
int len = 0;
flags &= ~STM_FLAG_TIMESTAMPED;
- addr = (void *)(ch_addr | stm_channel_off(STM_PKT_TYPE_DATA, flags));
+ addr = (void __iomem *)(ch_addr +
+ stm_channel_off(STM_PKT_TYPE_DATA, flags));
/* send the data header */
len += stm_trace_data_header(addr);
@@ -131,12 +155,13 @@
return len;
}
-static int stm_trace_ost_tail(unsigned long ch_addr, uint32_t flags)
+static int stm_trace_ost_tail(void __iomem *ch_addr, uint32_t flags)
{
- void *addr;
+ void __iomem *addr;
uint32_t tail = 0x0;
- addr = (void *)(ch_addr | stm_channel_off(STM_PKT_TYPE_FLAG, flags));
+ addr = (void __iomem *)(ch_addr +
+ stm_channel_off(STM_PKT_TYPE_FLAG, flags));
return stm_ost_send(addr, &tail, sizeof(tail));
}
@@ -147,7 +172,7 @@
struct stm_drvdata *drvdata = stmdrvdata;
int len = 0;
uint32_t ch;
- unsigned long ch_addr;
+ void __iomem *ch_addr;
/* allocate channel and get the channel address */
ch = stm_channel_alloc();
@@ -159,7 +184,7 @@
return 0;
}
- ch_addr = (unsigned long)stm_channel_addr(drvdata, ch);
+ ch_addr = (void __iomem *)stm_channel_addr(drvdata, ch);
/* send the ost header */
len += stm_trace_ost_header(ch_addr, flags, entity_id,
diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c
index c8f2702e..159512c 100644
--- a/drivers/hwtracing/coresight/coresight-stm.c
+++ b/drivers/hwtracing/coresight/coresight-stm.c
@@ -211,6 +211,7 @@
if (local_read(&drvdata->mode) == CS_MODE_SYSFS) {
spin_lock(&drvdata->spinlock);
stm_disable_hw(drvdata);
+ drvdata->enable = false;
spin_unlock(&drvdata->spinlock);
/* Wait until the engine has completely stopped */
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
index d6941ea..85fe87f 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
@@ -171,8 +171,11 @@
if (!used)
kfree(buf);
- if (!ret)
+ if (!ret) {
+ coresight_cti_map_trigin(drvdata->cti_reset, 2, 0);
+ coresight_cti_map_trigout(drvdata->cti_flush, 1, 0);
dev_info(drvdata->dev, "TMC-ETB/ETF enabled\n");
+ }
return ret;
}
@@ -244,6 +247,9 @@
spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ coresight_cti_unmap_trigin(drvdata->cti_reset, 2, 0);
+ coresight_cti_unmap_trigout(drvdata->cti_flush, 1, 0);
+
dev_info(drvdata->dev, "TMC-ETB/ETF disabled\n");
}
@@ -521,11 +527,13 @@
goto out;
}
- /* There is no point in reading a TMC in HW FIFO mode */
- mode = readl_relaxed(drvdata->base + TMC_MODE);
- if (mode != TMC_MODE_CIRCULAR_BUFFER) {
- ret = -EINVAL;
- goto out;
+ if (drvdata->enable) {
+ /* There is no point in reading a TMC in HW FIFO mode */
+ mode = readl_relaxed(drvdata->base + TMC_MODE);
+ if (mode != TMC_MODE_CIRCULAR_BUFFER) {
+ ret = -EINVAL;
+ goto out;
+ }
}
val = local_read(&drvdata->mode);
@@ -565,11 +573,13 @@
spin_lock_irqsave(&drvdata->spinlock, flags);
- /* There is no point in reading a TMC in HW FIFO mode */
- mode = readl_relaxed(drvdata->base + TMC_MODE);
- if (mode != TMC_MODE_CIRCULAR_BUFFER) {
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
- return -EINVAL;
+ if (drvdata->enable) {
+ /* There is no point in reading a TMC in HW FIFO mode */
+ mode = readl_relaxed(drvdata->base + TMC_MODE);
+ if (mode != TMC_MODE_CIRCULAR_BUFFER) {
+ spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ return -EINVAL;
+ }
}
/* Re-enable the TMC if need be */
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index 9e6f443..eb355f4 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -800,6 +800,8 @@
mutex_unlock(&drvdata->mem_lock);
return ret;
}
+ coresight_cti_map_trigout(drvdata->cti_flush, 3, 0);
+ coresight_cti_map_trigin(drvdata->cti_reset, 2, 0);
} else {
drvdata->usbch = usb_qdss_open("qdss", drvdata,
usb_notifier);
@@ -891,6 +893,7 @@
unsigned long flags;
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+ mutex_lock(&drvdata->mem_lock);
spin_lock_irqsave(&drvdata->spinlock, flags);
if (drvdata->reading) {
spin_unlock_irqrestore(&drvdata->spinlock, flags);
@@ -902,8 +905,10 @@
if (val != CS_MODE_DISABLED) {
if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB) {
__tmc_etr_disable_to_bam(drvdata);
+ spin_unlock_irqrestore(&drvdata->spinlock, flags);
tmc_etr_bam_disable(drvdata);
usb_qdss_close(drvdata->usbch);
+ goto out;
} else {
tmc_etr_disable_hw(drvdata);
}
@@ -911,6 +916,12 @@
spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM) {
+ coresight_cti_unmap_trigin(drvdata->cti_reset, 2, 0);
+ coresight_cti_unmap_trigout(drvdata->cti_flush, 3, 0);
+ }
+out:
+ mutex_unlock(&drvdata->mem_lock);
dev_info(drvdata->dev, "TMC-ETR disabled\n");
}
diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c
index 98fcd01..b97ebb8 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.c
+++ b/drivers/hwtracing/coresight/coresight-tmc.c
@@ -361,6 +361,9 @@
drvdata->out_mode = TMC_ETR_OUT_MODE_MEM;
spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ coresight_cti_map_trigout(drvdata->cti_flush, 3, 0);
+ coresight_cti_map_trigin(drvdata->cti_reset, 2, 0);
+
tmc_etr_bam_disable(drvdata);
usb_qdss_close(drvdata->usbch);
} else if (!strcmp(str, str_tmc_etr_out_mode[TMC_ETR_OUT_MODE_USB])) {
@@ -381,6 +384,9 @@
drvdata->out_mode = TMC_ETR_OUT_MODE_USB;
spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ coresight_cti_unmap_trigout(drvdata->cti_flush, 3, 0);
+ coresight_cti_unmap_trigin(drvdata->cti_reset, 2, 0);
+
drvdata->usbch = usb_qdss_open("qdss", drvdata,
usb_notifier);
if (IS_ERR(drvdata->usbch)) {
@@ -503,6 +509,7 @@
struct resource *res = &adev->res;
struct coresight_desc desc = { 0 };
struct device_node *np = adev->dev.of_node;
+ struct coresight_cti_data *ctidata;
pdata = of_get_coresight_platform_data(dev, np);
if (IS_ERR(pdata)) {
@@ -554,6 +561,19 @@
pm_runtime_put(&adev->dev);
+ ctidata = of_get_coresight_cti_data(dev, adev->dev.of_node);
+ if (IS_ERR(ctidata)) {
+ dev_err(dev, "invalid cti data\n");
+ } else if (ctidata && ctidata->nr_ctis == 2) {
+ drvdata->cti_flush = coresight_cti_get(ctidata->names[0]);
+ if (IS_ERR(drvdata->cti_flush))
+ dev_err(dev, "failed to get flush cti\n");
+
+ drvdata->cti_reset = coresight_cti_get(ctidata->names[1]);
+ if (IS_ERR(drvdata->cti_reset))
+ dev_err(dev, "failed to get reset cti\n");
+ }
+
desc.pdata = pdata;
desc.dev = dev;
if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index a9de0e8..6643adc 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -25,6 +25,7 @@
#include <linux/amba/bus.h>
#include <linux/usb_bam.h>
#include <linux/usb/usb_qdss.h>
+#include <linux/coresight-cti.h>
#define TMC_RSZ 0x004
#define TMC_STS 0x00c
@@ -184,7 +185,8 @@
struct tmc_etr_bam_data *bamdata;
bool enable_to_bam;
bool sticky_enable;
-
+ struct coresight_cti *cti_flush;
+ struct coresight_cti *cti_reset;
};
/* Generic functions */
diff --git a/drivers/hwtracing/coresight/of_coresight.c b/drivers/hwtracing/coresight/of_coresight.c
index 2492f90..81bbd78 100644
--- a/drivers/hwtracing/coresight/of_coresight.c
+++ b/drivers/hwtracing/coresight/of_coresight.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, 2016 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012, 2016-2017, The Linux Foundation. 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 and
@@ -23,7 +23,7 @@
#include <linux/coresight.h>
#include <linux/cpumask.h>
#include <asm/smp_plat.h>
-
+#include <linux/coresight-cti.h>
static int of_dev_node_match(struct device *dev, void *data)
{
@@ -196,3 +196,45 @@
return pdata;
}
EXPORT_SYMBOL_GPL(of_get_coresight_platform_data);
+
+struct coresight_cti_data *of_get_coresight_cti_data(
+ struct device *dev, struct device_node *node)
+{
+ int i, ret;
+ uint32_t ctis_len;
+ struct device_node *child_node;
+ struct coresight_cti_data *ctidata;
+
+ ctidata = devm_kzalloc(dev, sizeof(*ctidata), GFP_KERNEL);
+ if (!ctidata)
+ return ERR_PTR(-ENOMEM);
+
+ if (of_get_property(node, "coresight-ctis", &ctis_len))
+ ctidata->nr_ctis = ctis_len/sizeof(uint32_t);
+ else
+ return ERR_PTR(-EINVAL);
+
+ if (ctidata->nr_ctis) {
+ ctidata->names = devm_kzalloc(dev, ctidata->nr_ctis *
+ sizeof(*ctidata->names),
+ GFP_KERNEL);
+ if (!ctidata->names)
+ return ERR_PTR(-ENOMEM);
+
+ for (i = 0; i < ctidata->nr_ctis; i++) {
+ child_node = of_parse_phandle(node, "coresight-ctis",
+ i);
+ if (!child_node)
+ return ERR_PTR(-EINVAL);
+
+ ret = of_property_read_string(child_node,
+ "coresight-name",
+ &ctidata->names[i]);
+ of_node_put(child_node);
+ if (ret)
+ return ERR_PTR(ret);
+ }
+ }
+ return ctidata;
+}
+EXPORT_SYMBOL(of_get_coresight_cti_data);
diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
index 946e0ba..91e7b0c 100644
--- a/drivers/i2c/busses/i2c-qcom-geni.c
+++ b/drivers/i2c/busses/i2c-qcom-geni.c
@@ -26,6 +26,8 @@
#include <linux/dma-mapping.h>
#include <linux/qcom-geni-se.h>
#include <linux/ipc_logging.h>
+#include <linux/dmaengine.h>
+#include <linux/msm_gpi.h>
#define SE_I2C_TX_TRANS_LEN (0x26C)
#define SE_I2C_RX_TRANS_LEN (0x270)
@@ -54,6 +56,7 @@
#define SLV_ADDR_MSK (GENMASK(15, 9))
#define SLV_ADDR_SHFT (9)
+#define I2C_PACK_EN (BIT(0) | BIT(1))
#define I2C_CORE2X_VOTE (10000)
#define GP_IRQ0 0
#define GP_IRQ1 1
@@ -71,6 +74,12 @@
#define I2C_ARB_LOST GP_IRQ4
#define DM_I2C_RX_ERR ((GP_IRQ1 | GP_IRQ3 | GP_IRQ4) >> 4)
+enum i2c_se_mode {
+ UNINITIALIZED,
+ FIFO_SE_DMA,
+ GSI_ONLY,
+};
+
struct geni_i2c_dev {
struct device *dev;
void __iomem *base;
@@ -86,6 +95,24 @@
struct device *wrapper_dev;
void *ipcl;
int clk_fld_idx;
+ struct dma_chan *tx_c;
+ struct dma_chan *rx_c;
+ struct msm_gpi_tre cfg0_t;
+ struct msm_gpi_tre go_t;
+ struct msm_gpi_tre tx_t;
+ struct msm_gpi_tre rx_t;
+ dma_addr_t tx_ph;
+ dma_addr_t rx_ph;
+ struct msm_gpi_ctrl tx_ev;
+ struct msm_gpi_ctrl rx_ev;
+ struct scatterlist tx_sg[5]; /* lock, cfg0, go, TX, unlock */
+ struct scatterlist rx_sg;
+ int cfg_sent;
+ struct dma_async_tx_descriptor *tx_desc;
+ struct dma_async_tx_descriptor *rx_desc;
+ struct msm_gpi_dma_async_tx_cb_param tx_cb;
+ struct msm_gpi_dma_async_tx_cb_param rx_cb;
+ enum i2c_se_mode se_mode;
};
struct geni_i2c_err_log {
@@ -184,6 +211,9 @@
GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, "%s\n",
gi2c_log[err].msg);
}
+ if (gi2c->se_mode == GSI_ONLY)
+ goto err_out;
+
if (dma) {
rx_st = readl_relaxed(gi2c->base + SE_DMA_RX_IRQ_STAT);
tx_st = readl_relaxed(gi2c->base + SE_DMA_TX_IRQ_STAT);
@@ -194,6 +224,7 @@
GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev,
"DMA:%d tx_stat:0x%x, rx_stat:0x%x, irq-stat:0x%x\n",
dma, tx_st, rx_st, m_stat);
+err_out:
GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev,
"m_cmd:0x%x, geni_status:0x%x, geni_ios:0x%x\n",
m_cmd, geni_s, geni_ios);
@@ -305,6 +336,258 @@
return IRQ_HANDLED;
}
+static void gi2c_ev_cb(struct dma_chan *ch, struct msm_gpi_cb const *cb_str,
+ void *ptr)
+{
+ struct geni_i2c_dev *gi2c = ptr;
+ u32 m_stat = cb_str->status;
+
+ switch (cb_str->cb_event) {
+ case MSM_GPI_QUP_ERROR:
+ case MSM_GPI_QUP_SW_ERROR:
+ case MSM_GPI_QUP_MAX_EVENT:
+ /* fall through to stall impacted channel */
+ case MSM_GPI_QUP_CH_ERROR:
+ case MSM_GPI_QUP_PENDING_EVENT:
+ case MSM_GPI_QUP_EOT_DESC_MISMATCH:
+ break;
+ case MSM_GPI_QUP_NOTIFY:
+ if (m_stat & M_GP_IRQ_1_EN)
+ geni_i2c_err(gi2c, I2C_NACK);
+ if (m_stat & M_GP_IRQ_3_EN)
+ geni_i2c_err(gi2c, I2C_BUS_PROTO);
+ if (m_stat & M_GP_IRQ_4_EN)
+ geni_i2c_err(gi2c, I2C_ARB_LOST);
+ complete(&gi2c->xfer);
+ break;
+ default:
+ break;
+ }
+ if (cb_str->cb_event != MSM_GPI_QUP_NOTIFY)
+ GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
+ "GSI QN err:0x%x, status:0x%x, err:%d\n",
+ cb_str->error_log.error_code,
+ m_stat, cb_str->cb_event);
+}
+
+static void gi2c_gsi_tx_cb(void *ptr)
+{
+ struct msm_gpi_dma_async_tx_cb_param *tx_cb = ptr;
+ struct geni_i2c_dev *gi2c = tx_cb->userdata;
+
+ if (!(gi2c->cur->flags & I2C_M_RD))
+ complete(&gi2c->xfer);
+}
+
+static void gi2c_gsi_rx_cb(void *ptr)
+{
+ struct msm_gpi_dma_async_tx_cb_param *rx_cb = ptr;
+ struct geni_i2c_dev *gi2c = rx_cb->userdata;
+
+ if (gi2c->cur->flags & I2C_M_RD) {
+ if (rx_cb->status & DM_I2C_RX_ERR) {
+ GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev,
+ "RX TCE Unexpected Err, stat:0x%x\n",
+ rx_cb->status);
+ if (rx_cb->status & GP_IRQ1)
+ geni_i2c_err(gi2c, I2C_NACK);
+ if (rx_cb->status & GP_IRQ3)
+ geni_i2c_err(gi2c, I2C_BUS_PROTO);
+ if (rx_cb->status & GP_IRQ4)
+ geni_i2c_err(gi2c, I2C_ARB_LOST);
+ }
+ complete(&gi2c->xfer);
+ }
+}
+
+static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
+ int num)
+{
+ struct geni_i2c_dev *gi2c = i2c_get_adapdata(adap);
+ int i, ret = 0, timeout = 0;
+
+ if (!gi2c->tx_c) {
+ gi2c->tx_c = dma_request_slave_channel(gi2c->dev, "tx");
+ if (!gi2c->tx_c) {
+ GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
+ "tx dma req slv chan ret :%d\n", ret);
+ return -EIO;
+ }
+ gi2c->tx_ev.init.callback = gi2c_ev_cb;
+ gi2c->tx_ev.init.cb_param = gi2c;
+ gi2c->tx_ev.cmd = MSM_GPI_INIT;
+ gi2c->tx_c->private = &gi2c->tx_ev;
+ ret = dmaengine_slave_config(gi2c->tx_c, NULL);
+ if (ret) {
+ GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
+ "tx dma slave config ret :%d\n", ret);
+ return ret;
+ }
+ }
+ if (!gi2c->rx_c) {
+ gi2c->rx_c = dma_request_slave_channel(gi2c->dev, "rx");
+ if (!gi2c->rx_c) {
+ GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
+ "rx dma req slv chan ret :%d\n", ret);
+ return -EIO;
+ }
+ gi2c->rx_ev.init.cb_param = gi2c;
+ gi2c->rx_ev.init.callback = gi2c_ev_cb;
+ gi2c->rx_ev.cmd = MSM_GPI_INIT;
+ gi2c->rx_c->private = &gi2c->rx_ev;
+ ret = dmaengine_slave_config(gi2c->rx_c, NULL);
+ if (ret) {
+ GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
+ "rx dma slave config ret :%d\n", ret);
+ return ret;
+ }
+ }
+
+ if (!gi2c->cfg_sent) {
+ struct geni_i2c_clk_fld *itr = geni_i2c_clk_map +
+ gi2c->clk_fld_idx;
+ struct msm_gpi_tre *cfg0 = &gi2c->cfg0_t;
+
+ /* config0 */
+ cfg0->dword[0] = MSM_GPI_I2C_CONFIG0_TRE_DWORD0(I2C_PACK_EN,
+ itr->t_cycle,
+ itr->t_high,
+ itr->t_low);
+ cfg0->dword[1] = MSM_GPI_I2C_CONFIG0_TRE_DWORD1(0, 0);
+ cfg0->dword[2] = MSM_GPI_I2C_CONFIG0_TRE_DWORD2(0,
+ itr->clk_div);
+ cfg0->dword[3] = MSM_GPI_I2C_CONFIG0_TRE_DWORD3(0, 0, 0, 1);
+
+ gi2c->tx_cb.userdata = gi2c;
+ gi2c->rx_cb.userdata = gi2c;
+ }
+
+ for (i = 0; i < num; i++) {
+ u8 op = (msgs[i].flags & I2C_M_RD) ? 2 : 1;
+ int segs = 3 - op;
+ int index = 0;
+ int stretch = (i < (num - 1));
+ dma_cookie_t tx_cookie, rx_cookie;
+ struct msm_gpi_tre *go_t = &gi2c->go_t;
+ struct device *rx_dev = gi2c->rx_c->device->dev;
+ struct device *tx_dev = gi2c->tx_c->device->dev;
+
+ gi2c->cur = &msgs[i];
+ if (!gi2c->cfg_sent) {
+ segs++;
+ sg_init_table(gi2c->tx_sg, segs);
+ sg_set_buf(gi2c->tx_sg, &gi2c->cfg0_t,
+ sizeof(gi2c->cfg0_t));
+ gi2c->cfg_sent = 1;
+ index++;
+ } else {
+ sg_init_table(gi2c->tx_sg, segs);
+ }
+
+ go_t->dword[0] = MSM_GPI_I2C_GO_TRE_DWORD0((stretch << 2),
+ msgs[i].addr, op);
+ go_t->dword[1] = MSM_GPI_I2C_GO_TRE_DWORD1;
+
+ if (msgs[i].flags & I2C_M_RD) {
+ go_t->dword[2] = MSM_GPI_I2C_GO_TRE_DWORD2(msgs[i].len);
+ go_t->dword[3] = MSM_GPI_I2C_GO_TRE_DWORD3(0, 0, 1, 0);
+ } else {
+ go_t->dword[2] = MSM_GPI_I2C_GO_TRE_DWORD2(0);
+ go_t->dword[3] = MSM_GPI_I2C_GO_TRE_DWORD3(0, 0, 0, 1);
+ }
+
+ sg_set_buf(&gi2c->tx_sg[index++], &gi2c->go_t,
+ sizeof(gi2c->go_t));
+
+ if (msgs[i].flags & I2C_M_RD) {
+ sg_init_table(&gi2c->rx_sg, 1);
+ gi2c->rx_ph = dma_map_single(rx_dev, msgs[i].buf,
+ msgs[i].len,
+ DMA_FROM_DEVICE);
+ gi2c->rx_t.dword[0] =
+ MSM_GPI_DMA_W_BUFFER_TRE_DWORD0(gi2c->rx_ph);
+ gi2c->rx_t.dword[1] =
+ MSM_GPI_DMA_W_BUFFER_TRE_DWORD1(gi2c->rx_ph);
+ gi2c->rx_t.dword[2] =
+ MSM_GPI_DMA_W_BUFFER_TRE_DWORD2(msgs[i].len);
+ gi2c->rx_t.dword[3] =
+ MSM_GPI_DMA_W_BUFFER_TRE_DWORD3(0, 1, 0, 0);
+
+ sg_set_buf(&gi2c->rx_sg, &gi2c->rx_t,
+ sizeof(gi2c->rx_t));
+ gi2c->rx_desc = dmaengine_prep_slave_sg(gi2c->rx_c,
+ &gi2c->rx_sg, 1,
+ DMA_DEV_TO_MEM,
+ (DMA_PREP_INTERRUPT |
+ DMA_CTRL_ACK));
+ if (!gi2c->rx_desc) {
+ GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
+ "prep_slave_sg for rx failed\n");
+ gi2c->err = -ENOMEM;
+ return gi2c->err;
+ }
+ gi2c->rx_desc->callback = gi2c_gsi_rx_cb;
+ gi2c->rx_desc->callback_param = &gi2c->rx_cb;
+
+ /* Issue RX */
+ rx_cookie = dmaengine_submit(gi2c->rx_desc);
+ dma_async_issue_pending(gi2c->rx_c);
+ } else {
+ gi2c->tx_ph = dma_map_single(tx_dev, msgs[i].buf,
+ msgs[i].len,
+ DMA_TO_DEVICE);
+ gi2c->tx_t.dword[0] =
+ MSM_GPI_DMA_W_BUFFER_TRE_DWORD0(gi2c->tx_ph);
+ gi2c->tx_t.dword[1] =
+ MSM_GPI_DMA_W_BUFFER_TRE_DWORD1(gi2c->tx_ph);
+ gi2c->tx_t.dword[2] =
+ MSM_GPI_DMA_W_BUFFER_TRE_DWORD2(msgs[i].len);
+ gi2c->tx_t.dword[3] =
+ MSM_GPI_DMA_W_BUFFER_TRE_DWORD3(0, 1, 0, 0);
+
+ sg_set_buf(&gi2c->tx_sg[index++], &gi2c->tx_t,
+ sizeof(gi2c->tx_t));
+ }
+
+ gi2c->tx_desc = dmaengine_prep_slave_sg(gi2c->tx_c, gi2c->tx_sg,
+ segs, DMA_MEM_TO_DEV,
+ (DMA_PREP_INTERRUPT |
+ DMA_CTRL_ACK));
+ if (!gi2c->tx_desc) {
+ GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
+ "prep_slave_sg for tx failed\n");
+ gi2c->err = -ENOMEM;
+ return gi2c->err;
+ }
+ gi2c->tx_desc->callback = gi2c_gsi_tx_cb;
+ gi2c->tx_desc->callback_param = &gi2c->tx_cb;
+
+ /* Issue TX */
+ tx_cookie = dmaengine_submit(gi2c->tx_desc);
+ dma_async_issue_pending(gi2c->tx_c);
+
+ timeout = wait_for_completion_timeout(&gi2c->xfer, HZ);
+ if (msgs[i].flags & I2C_M_RD)
+ dma_unmap_single(rx_dev, gi2c->rx_ph, msgs[i].len,
+ DMA_FROM_DEVICE);
+ else
+ dma_unmap_single(tx_dev, gi2c->tx_ph, msgs[i].len,
+ DMA_TO_DEVICE);
+
+ if (!timeout) {
+ GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
+ "GSI Txn timed out\n");
+ gi2c->err = -ETIMEDOUT;
+ }
+ if (gi2c->err) {
+ dmaengine_terminate_all(gi2c->tx_c);
+ gi2c->cfg_sent = 0;
+ return gi2c->err;
+ }
+ }
+ return gi2c->err;
+}
+
static int geni_i2c_xfer(struct i2c_adapter *adap,
struct i2c_msg msgs[],
int num)
@@ -324,6 +607,11 @@
pm_runtime_set_suspended(gi2c->dev);
return ret;
}
+ if (gi2c->se_mode == GSI_ONLY) {
+ ret = geni_i2c_gsi_xfer(adap, msgs, num);
+ goto geni_i2c_txn_ret;
+ }
+
qcom_geni_i2c_conf(gi2c, 0);
dev_dbg(gi2c->dev, "i2c xfer:num:%d, msgs:len:%d,flg:%d\n",
num, msgs[0].len, msgs[0].flags);
@@ -418,8 +706,9 @@
break;
}
}
+geni_i2c_txn_ret:
if (ret == 0)
- ret = i;
+ ret = num;
pm_runtime_put_sync(gi2c->dev);
gi2c->cur = NULL;
gi2c->err = 0;
@@ -592,7 +881,9 @@
{
struct geni_i2c_dev *gi2c = dev_get_drvdata(dev);
- disable_irq(gi2c->irq);
+ if (gi2c->se_mode == FIFO_SE_DMA)
+ disable_irq(gi2c->irq);
+
se_geni_resources_off(&gi2c->i2c_rsc);
return 0;
}
@@ -612,16 +903,31 @@
if (ret)
return ret;
- if (unlikely(!gi2c->tx_wm)) {
- int gi2c_tx_depth = get_tx_fifo_depth(gi2c->base);
+ if (gi2c->se_mode == UNINITIALIZED) {
+ u32 se_mode = readl_relaxed(gi2c->base +
+ GENI_IF_FIFO_DISABLE_RO);
- gi2c->tx_wm = gi2c_tx_depth - 1;
- geni_se_init(gi2c->base, gi2c->tx_wm, gi2c_tx_depth);
- se_config_packing(gi2c->base, 8, 4, true);
- GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev,
- "i2c fifo depth:%d\n", gi2c_tx_depth);
+ if (se_mode) {
+ gi2c->se_mode = GSI_ONLY;
+ geni_se_select_mode(gi2c->base, GSI_DMA);
+ GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev,
+ "i2c in GSI ONLY mode\n");
+ } else {
+ int gi2c_tx_depth = get_tx_fifo_depth(gi2c->base);
+
+ gi2c->se_mode = FIFO_SE_DMA;
+
+ gi2c->tx_wm = gi2c_tx_depth - 1;
+ geni_se_init(gi2c->base, gi2c->tx_wm, gi2c_tx_depth);
+ se_config_packing(gi2c->base, 8, 4, true);
+ GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev,
+ "i2c fifo/se-dma mode. fifo depth:%d\n",
+ gi2c_tx_depth);
+ }
}
- enable_irq(gi2c->irq);
+ if (gi2c->se_mode == FIFO_SE_DMA)
+ enable_irq(gi2c->irq);
+
return 0;
}
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c
index 8fd108d..63e82f8 100644
--- a/drivers/infiniband/core/addr.c
+++ b/drivers/infiniband/core/addr.c
@@ -518,6 +518,11 @@
struct dst_entry *dst;
int ret;
+ if (!addr->net) {
+ pr_warn_ratelimited("%s: missing namespace\n", __func__);
+ return -EINVAL;
+ }
+
if (src_in->sa_family == AF_INET) {
struct rtable *rt = NULL;
const struct sockaddr_in *dst_in4 =
@@ -555,7 +560,6 @@
}
addr->bound_dev_if = ndev->ifindex;
- addr->net = dev_net(ndev);
dev_put(ndev);
return ret;
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index f2d40c0..809a028 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -976,6 +976,8 @@
} else
ret = iw_cm_init_qp_attr(id_priv->cm_id.iw, qp_attr,
qp_attr_mask);
+ qp_attr->port_num = id_priv->id.port_num;
+ *qp_attr_mask |= IB_QP_PORT;
} else
ret = -ENOSYS;
diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c
index 1fb31a4..0a260a0 100644
--- a/drivers/infiniband/hw/mlx5/mr.c
+++ b/drivers/infiniband/hw/mlx5/mr.c
@@ -1823,7 +1823,7 @@
mr->ndescs = sg_nents;
for_each_sg(sgl, sg, sg_nents, i) {
- if (unlikely(i > mr->max_descs))
+ if (unlikely(i >= mr->max_descs))
break;
klms[i].va = cpu_to_be64(sg_dma_address(sg) + sg_offset);
klms[i].bcount = cpu_to_be32(sg_dma_len(sg) - sg_offset);
diff --git a/drivers/infiniband/sw/rxe/rxe_resp.c b/drivers/infiniband/sw/rxe/rxe_resp.c
index ccf6247..4d2a346 100644
--- a/drivers/infiniband/sw/rxe/rxe_resp.c
+++ b/drivers/infiniband/sw/rxe/rxe_resp.c
@@ -980,7 +980,9 @@
free_rd_atomic_resource(qp, res);
rxe_advance_resp_resource(qp);
- memcpy(SKB_TO_PKT(skb), &ack_pkt, sizeof(skb->cb));
+ memcpy(SKB_TO_PKT(skb), &ack_pkt, sizeof(ack_pkt));
+ memset((unsigned char *)SKB_TO_PKT(skb) + sizeof(ack_pkt), 0,
+ sizeof(skb->cb) - sizeof(ack_pkt));
res->type = RXE_ATOMIC_MASK;
res->atomic.skb = skb;
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
index 140f3f3..e46e2b0 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -83,6 +83,7 @@
static struct iscsi_transport iscsi_iser_transport;
static struct scsi_transport_template *iscsi_iser_scsi_transport;
static struct workqueue_struct *release_wq;
+static DEFINE_MUTEX(unbind_iser_conn_mutex);
struct iser_global ig;
int iser_debug_level = 0;
@@ -550,12 +551,14 @@
*/
if (iser_conn) {
mutex_lock(&iser_conn->state_mutex);
+ mutex_lock(&unbind_iser_conn_mutex);
iser_conn_terminate(iser_conn);
iscsi_conn_stop(cls_conn, flag);
/* unbind */
iser_conn->iscsi_conn = NULL;
conn->dd_data = NULL;
+ mutex_unlock(&unbind_iser_conn_mutex);
complete(&iser_conn->stop_completion);
mutex_unlock(&iser_conn->state_mutex);
@@ -973,13 +976,21 @@
struct iser_conn *iser_conn;
struct ib_device *ib_dev;
+ mutex_lock(&unbind_iser_conn_mutex);
+
session = starget_to_session(scsi_target(sdev))->dd_data;
iser_conn = session->leadconn->dd_data;
+ if (!iser_conn) {
+ mutex_unlock(&unbind_iser_conn_mutex);
+ return -ENOTCONN;
+ }
ib_dev = iser_conn->ib_conn.device->ib_device;
if (!(ib_dev->attrs.device_cap_flags & IB_DEVICE_SG_GAPS_REG))
blk_queue_virt_boundary(sdev->request_queue, ~MASK_4K);
+ mutex_unlock(&unbind_iser_conn_mutex);
+
return 0;
}
diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c
index 6dd43f6..39d2837 100644
--- a/drivers/infiniband/ulp/isert/ib_isert.c
+++ b/drivers/infiniband/ulp/isert/ib_isert.c
@@ -1447,7 +1447,7 @@
isert_login_recv_done(struct ib_cq *cq, struct ib_wc *wc)
{
struct isert_conn *isert_conn = wc->qp->qp_context;
- struct ib_device *ib_dev = isert_conn->cm_id->device;
+ struct ib_device *ib_dev = isert_conn->device->ib_device;
if (unlikely(wc->status != IB_WC_SUCCESS)) {
isert_print_wc(wc, "login recv");
diff --git a/drivers/input/misc/hbtp_input.c b/drivers/input/misc/hbtp_input.c
index 0dea590..7a6f50b 100644
--- a/drivers/input/misc/hbtp_input.c
+++ b/drivers/input/misc/hbtp_input.c
@@ -47,6 +47,8 @@
struct input_dev *input_dev;
s32 count;
struct mutex mutex;
+ struct mutex sensormutex;
+ struct hbtp_sensor_data *sensor_data;
bool touch_status[HBTP_MAX_FINGER];
#if defined(CONFIG_FB)
struct notifier_block fb_notif;
@@ -88,10 +90,14 @@
u32 power_off_delay;
bool manage_pin_ctrl;
struct kobject *sysfs_kobject;
+ s16 ROI[MAX_ROI_SIZE];
+ s16 accelBuffer[MAX_ACCEL_SIZE];
};
static struct hbtp_data *hbtp;
+static struct kobject *sensor_kobject;
+
#if defined(CONFIG_FB)
static int hbtp_fb_suspend(struct hbtp_data *ts);
static int hbtp_fb_early_resume(struct hbtp_data *ts);
@@ -151,6 +157,46 @@
}
#endif
+static ssize_t hbtp_sensor_roi_show(struct file *dev, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf, loff_t pos,
+ size_t size) {
+ mutex_lock(&hbtp->sensormutex);
+ memcpy(buf, hbtp->ROI, size);
+ mutex_unlock(&hbtp->sensormutex);
+
+ return size;
+}
+
+static ssize_t hbtp_sensor_vib_show(struct file *dev, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf, loff_t pos,
+ size_t size) {
+ mutex_lock(&hbtp->sensormutex);
+ memcpy(buf, hbtp->accelBuffer, size);
+ mutex_unlock(&hbtp->sensormutex);
+
+ return size;
+}
+
+static struct bin_attribute capdata_attr = {
+ .attr = {
+ .name = "capdata",
+ .mode = 0444,
+ },
+ .size = 1024,
+ .read = hbtp_sensor_roi_show,
+ .write = NULL,
+};
+
+static struct bin_attribute vibdata_attr = {
+ .attr = {
+ .name = "vib_data",
+ .mode = 0444,
+ },
+ .size = MAX_ACCEL_SIZE*sizeof(int16_t),
+ .read = hbtp_sensor_vib_show,
+ .write = NULL,
+};
+
static int hbtp_input_open(struct inode *inode, struct file *file)
{
mutex_lock(&hbtp->mutex);
@@ -749,6 +795,22 @@
return -EINVAL;
}
break;
+
+ case HBTP_SET_SENSORDATA:
+ if (copy_from_user(hbtp->sensor_data, (void __user *)arg,
+ sizeof(struct hbtp_sensor_data))) {
+ pr_err("%s: Error copying data\n", __func__);
+ return -EFAULT;
+ }
+ mutex_lock(&hbtp->sensormutex);
+ memcpy(hbtp->ROI, hbtp->sensor_data->ROI, sizeof(hbtp->ROI));
+ memcpy(hbtp->accelBuffer, hbtp->sensor_data->accelBuffer,
+ sizeof(hbtp->accelBuffer));
+ mutex_unlock(&hbtp->sensormutex);
+
+ error = 0;
+ break;
+
default:
pr_err("%s: Unsupported ioctl command %u\n", __func__, cmd);
error = -EINVAL;
@@ -1388,13 +1450,19 @@
static int __init hbtp_init(void)
{
- int error;
+ int error = 0;
hbtp = kzalloc(sizeof(struct hbtp_data), GFP_KERNEL);
if (!hbtp)
return -ENOMEM;
+ hbtp->sensor_data = kzalloc(sizeof(struct hbtp_sensor_data),
+ GFP_KERNEL);
+ if (!hbtp->sensor_data)
+ goto err_sensordata;
+
mutex_init(&hbtp->mutex);
+ mutex_init(&hbtp->sensormutex);
error = misc_register(&hbtp_input_misc);
if (error) {
@@ -1412,6 +1480,28 @@
}
#endif
+ sensor_kobject = kobject_create_and_add("hbtpsensor", kernel_kobj);
+ if (!sensor_kobject) {
+ pr_err("%s: Could not create hbtpsensor kobject\n", __func__);
+ goto err_kobject_create;
+ }
+
+ error = sysfs_create_bin_file(sensor_kobject, &capdata_attr);
+ if (error < 0) {
+ pr_err("%s: hbtp capdata sysfs creation failed: %d\n", __func__,
+ error);
+ goto err_sysfs_create_capdata;
+ }
+ pr_debug("capdata sysfs creation success\n");
+
+ error = sysfs_create_bin_file(sensor_kobject, &vibdata_attr);
+ if (error < 0) {
+ pr_err("%s: vibdata sysfs creation failed: %d\n", __func__,
+ error);
+ goto err_sysfs_create_vibdata;
+ }
+ pr_debug("vibdata sysfs creation success\n");
+
error = platform_driver_register(&hbtp_pdev_driver);
if (error) {
pr_err("Failed to register platform driver: %d\n", error);
@@ -1431,12 +1521,20 @@
return 0;
err_platform_drv_reg:
+ sysfs_remove_bin_file(sensor_kobject, &vibdata_attr);
+err_sysfs_create_vibdata:
+ sysfs_remove_bin_file(sensor_kobject, &capdata_attr);
+err_sysfs_create_capdata:
+ kobject_put(sensor_kobject);
+err_kobject_create:
#if defined(CONFIG_FB)
fb_unregister_client(&hbtp->fb_notif);
err_fb_reg:
#endif
misc_deregister(&hbtp_input_misc);
err_misc_reg:
+ kfree(hbtp->sensor_data);
+err_sensordata:
kfree(hbtp);
return error;
@@ -1444,6 +1542,9 @@
static void __exit hbtp_exit(void)
{
+ sysfs_remove_bin_file(sensor_kobject, &vibdata_attr);
+ sysfs_remove_bin_file(sensor_kobject, &capdata_attr);
+ kobject_put(sensor_kobject);
misc_deregister(&hbtp_input_misc);
if (hbtp->input_dev)
input_unregister_device(hbtp->input_dev);
@@ -1454,6 +1555,7 @@
platform_driver_unregister(&hbtp_pdev_driver);
+ kfree(hbtp->sensor_data);
kfree(hbtp);
}
diff --git a/drivers/input/misc/keychord.c b/drivers/input/misc/keychord.c
index a5ea27a..c5ab3dd 100644
--- a/drivers/input/misc/keychord.c
+++ b/drivers/input/misc/keychord.c
@@ -232,9 +232,11 @@
{
struct keychord_device *kdev = file->private_data;
struct input_keychord *keychords = 0;
- struct input_keychord *keychord, *next, *end;
+ struct input_keychord *keychord;
int ret, i, key;
unsigned long flags;
+ size_t resid = count;
+ size_t key_bytes;
if (count < sizeof(struct input_keychord))
return -EINVAL;
@@ -265,15 +267,29 @@
kdev->head = kdev->tail = 0;
keychord = keychords;
- end = (struct input_keychord *)((char *)keychord + count);
- while (keychord < end) {
- next = NEXT_KEYCHORD(keychord);
- if (keychord->count <= 0 || next > end) {
+ while (resid > 0) {
+ /* Is the entire keychord entry header present ? */
+ if (resid < sizeof(struct input_keychord)) {
+ pr_err("keychord: Insufficient bytes present for header %zu\n",
+ resid);
+ goto err_unlock_return;
+ }
+ resid -= sizeof(struct input_keychord);
+ if (keychord->count <= 0) {
pr_err("keychord: invalid keycode count %d\n",
keychord->count);
goto err_unlock_return;
}
+ key_bytes = keychord->count * sizeof(keychord->keycodes[0]);
+ /* Do we have all the expected keycodes ? */
+ if (resid < key_bytes) {
+ pr_err("keychord: Insufficient bytes present for keycount %zu\n",
+ resid);
+ goto err_unlock_return;
+ }
+ resid -= key_bytes;
+
if (keychord->version != KEYCHORD_VERSION) {
pr_err("keychord: unsupported version %d\n",
keychord->version);
@@ -292,7 +308,7 @@
}
kdev->keychord_count++;
- keychord = next;
+ keychord = NEXT_KEYCHORD(keychord);
}
kdev->keychords = keychords;
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index 89abfdb..c84c685 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -434,8 +434,10 @@
{
struct i8042_port *port = serio->port_data;
+ spin_lock_irq(&i8042_lock);
port->exists = true;
- mb();
+ spin_unlock_irq(&i8042_lock);
+
return 0;
}
@@ -448,16 +450,20 @@
{
struct i8042_port *port = serio->port_data;
+ spin_lock_irq(&i8042_lock);
port->exists = false;
+ port->serio = NULL;
+ spin_unlock_irq(&i8042_lock);
/*
+ * We need to make sure that interrupt handler finishes using
+ * our serio port before we return from this function.
* We synchronize with both AUX and KBD IRQs because there is
* a (very unlikely) chance that AUX IRQ is raised for KBD port
* and vice versa.
*/
synchronize_irq(I8042_AUX_IRQ);
synchronize_irq(I8042_KBD_IRQ);
- port->serio = NULL;
}
/*
@@ -574,7 +580,7 @@
spin_unlock_irqrestore(&i8042_lock, flags);
- if (likely(port->exists && !filtered))
+ if (likely(serio && !filtered))
serio_interrupt(serio, data, dfl);
out:
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 142357e..b56a02d 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -332,9 +332,17 @@
u32 value;
};
+/*
+ * attach_count
+ * The SMR and S2CR registers are only programmed when the number of
+ * devices attached to the iommu using these registers is > 0. This
+ * is required for the "SID switch" use case for secure display.
+ * Protected by stream_map_mutex.
+ */
struct arm_smmu_s2cr {
struct iommu_group *group;
int count;
+ int attach_count;
enum arm_smmu_s2cr_type type;
enum arm_smmu_s2cr_privcfg privcfg;
u8 cbndx;
@@ -389,6 +397,7 @@
/* Protects clock_refs_count */
spinlock_t clock_refs_lock;
int clock_refs_count;
+ int regulator_defer;
};
struct arm_smmu_device {
@@ -789,6 +798,57 @@
WARN_ON(msm_bus_scale_client_update_request(pwr->bus_client, 0));
}
+static int arm_smmu_enable_regulators(struct arm_smmu_power_resources *pwr)
+{
+ struct regulator_bulk_data *consumers;
+ int num_consumers, ret;
+ int i;
+
+ num_consumers = pwr->num_gdscs;
+ consumers = pwr->gdscs;
+ for (i = 0; i < num_consumers; i++) {
+ ret = regulator_enable(consumers[i].consumer);
+ if (ret)
+ goto out;
+ }
+ return 0;
+
+out:
+ i -= 1;
+ for (; i >= 0; i--)
+ regulator_disable(consumers[i].consumer);
+ return ret;
+}
+
+static int arm_smmu_disable_regulators(struct arm_smmu_power_resources *pwr)
+{
+ struct regulator_bulk_data *consumers;
+ int i;
+ int num_consumers, ret, r;
+
+ num_consumers = pwr->num_gdscs;
+ consumers = pwr->gdscs;
+ for (i = num_consumers - 1; i >= 0; --i) {
+ ret = regulator_disable_deferred(consumers[i].consumer,
+ pwr->regulator_defer);
+ if (ret != 0)
+ goto err;
+ }
+
+ return 0;
+
+err:
+ pr_err("Failed to disable %s: %d\n", consumers[i].supply, ret);
+ for (++i; i < num_consumers; ++i) {
+ r = regulator_enable(consumers[i].consumer);
+ if (r != 0)
+ pr_err("Failed to reename %s: %d\n",
+ consumers[i].supply, r);
+ }
+
+ return ret;
+}
+
/* Clocks must be prepared before this (arm_smmu_prepare_clocks) */
static int arm_smmu_power_on_atomic(struct arm_smmu_power_resources *pwr)
{
@@ -848,7 +908,7 @@
if (ret)
goto out_unlock;
- ret = regulator_bulk_enable(pwr->num_gdscs, pwr->gdscs);
+ ret = arm_smmu_enable_regulators(pwr);
if (ret)
goto out_disable_bus;
@@ -884,7 +944,7 @@
}
arm_smmu_unprepare_clocks(pwr);
- regulator_bulk_disable(pwr->num_gdscs, pwr->gdscs);
+ arm_smmu_disable_regulators(pwr);
arm_smmu_unrequest_bus(pwr);
pwr->power_count = 0;
mutex_unlock(&pwr->power_lock);
@@ -1958,11 +2018,9 @@
}
iommu_group_put(group);
- /* It worked! Now, poke the actual hardware */
- for_each_cfg_sme(fwspec, i, idx) {
- arm_smmu_write_sme(smmu, idx);
+ /* It worked! Don't poke the actual hardware until we've attached */
+ for_each_cfg_sme(fwspec, i, idx)
smmu->s2crs[idx].group = group;
- }
mutex_unlock(&smmu->stream_map_mutex);
return 0;
@@ -1991,6 +2049,33 @@
mutex_unlock(&smmu->stream_map_mutex);
}
+static void arm_smmu_domain_remove_master(struct arm_smmu_domain *smmu_domain,
+ struct iommu_fwspec *fwspec)
+{
+ struct arm_smmu_device *smmu = smmu_domain->smmu;
+ struct arm_smmu_s2cr *s2cr = smmu->s2crs;
+ int i, idx;
+ const struct iommu_gather_ops *tlb;
+
+ tlb = smmu_domain->pgtbl_cfg.tlb;
+
+ mutex_lock(&smmu->stream_map_mutex);
+ for_each_cfg_sme(fwspec, i, idx) {
+ WARN_ON(s2cr[idx].attach_count == 0);
+ s2cr[idx].attach_count -= 1;
+
+ if (s2cr[idx].attach_count > 0)
+ continue;
+
+ writel_relaxed(0, ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_SMR(idx));
+ writel_relaxed(0, ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_S2CR(idx));
+ }
+ mutex_unlock(&smmu->stream_map_mutex);
+
+ /* Ensure there are no stale mappings for this context bank */
+ tlb->tlb_flush_all(smmu_domain);
+}
+
static int arm_smmu_domain_add_master(struct arm_smmu_domain *smmu_domain,
struct iommu_fwspec *fwspec)
{
@@ -2000,15 +2085,17 @@
u8 cbndx = smmu_domain->cfg.cbndx;
int i, idx;
+ mutex_lock(&smmu->stream_map_mutex);
for_each_cfg_sme(fwspec, i, idx) {
- if (type == s2cr[idx].type && cbndx == s2cr[idx].cbndx)
+ if (s2cr[idx].attach_count++ > 0)
continue;
s2cr[idx].type = type;
s2cr[idx].privcfg = S2CR_PRIVCFG_DEFAULT;
s2cr[idx].cbndx = cbndx;
- arm_smmu_write_s2cr(smmu, idx);
+ arm_smmu_write_sme(smmu, idx);
}
+ mutex_unlock(&smmu->stream_map_mutex);
return 0;
}
@@ -2018,6 +2105,7 @@
{
struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
struct arm_smmu_device *smmu = smmu_domain->smmu;
+ struct iommu_fwspec *fwspec = dev->iommu_fwspec;
int dynamic = smmu_domain->attributes & (1 << DOMAIN_ATTR_DYNAMIC);
int atomic_domain = smmu_domain->attributes & (1 << DOMAIN_ATTR_ATOMIC);
@@ -2029,6 +2117,8 @@
return;
}
+ arm_smmu_domain_remove_master(smmu_domain, fwspec);
+
/* Remove additional vote for atomic power */
if (atomic_domain) {
WARN_ON(arm_smmu_power_on_atomic(smmu->pwr));
@@ -3175,6 +3265,11 @@
u32 sctlr, sctlr_orig, fsr;
void __iomem *cb_base;
+ if (smmu->model == QCOM_SMMUV2) {
+ dev_err(smmu->dev, "ATOS support is disabled\n");
+ return 0;
+ }
+
ret = arm_smmu_power_on(smmu_domain->smmu->pwr);
if (ret)
return ret;
@@ -3534,6 +3629,12 @@
if (!pwr->gdscs)
return -ENOMEM;
+ if (!of_property_read_u32(dev->of_node,
+ "qcom,deferred-regulator-disable-delay",
+ &(pwr->regulator_defer)))
+ dev_info(dev, "regulator defer delay %d\n",
+ pwr->regulator_defer);
+
i = 0;
of_property_for_each_string(dev->of_node, "qcom,regulator-names",
prop, cname)
@@ -4206,36 +4307,6 @@
u32 halt_count;
};
-static int qsmmuv500_tbu_power_on_all(struct arm_smmu_device *smmu)
-{
- struct qsmmuv500_tbu_device *tbu;
- struct qsmmuv500_archdata *data = get_qsmmuv500_archdata(smmu);
- int ret = 0;
-
- list_for_each_entry(tbu, &data->tbus, list) {
- ret = arm_smmu_power_on(tbu->pwr);
- if (ret)
- break;
- }
- if (!ret)
- return 0;
-
- list_for_each_entry_continue_reverse(tbu, &data->tbus, list) {
- arm_smmu_power_off(tbu->pwr);
- }
- return ret;
-}
-
-static void qsmmuv500_tbu_power_off_all(struct arm_smmu_device *smmu)
-{
- struct qsmmuv500_tbu_device *tbu;
- struct qsmmuv500_archdata *data = get_qsmmuv500_archdata(smmu);
-
- list_for_each_entry_reverse(tbu, &data->tbus, list) {
- arm_smmu_power_off(tbu->pwr);
- }
-}
-
static int qsmmuv500_tbu_halt(struct qsmmuv500_tbu_device *tbu)
{
unsigned long flags;
@@ -4294,37 +4365,6 @@
spin_unlock_irqrestore(&tbu->halt_lock, flags);
}
-static int qsmmuv500_halt_all(struct arm_smmu_device *smmu)
-{
- struct qsmmuv500_tbu_device *tbu;
- struct qsmmuv500_archdata *data = get_qsmmuv500_archdata(smmu);
- int ret = 0;
-
- list_for_each_entry(tbu, &data->tbus, list) {
- ret = qsmmuv500_tbu_halt(tbu);
- if (ret)
- break;
- }
-
- if (!ret)
- return 0;
-
- list_for_each_entry_continue_reverse(tbu, &data->tbus, list) {
- qsmmuv500_tbu_resume(tbu);
- }
- return ret;
-}
-
-static void qsmmuv500_resume_all(struct arm_smmu_device *smmu)
-{
- struct qsmmuv500_tbu_device *tbu;
- struct qsmmuv500_archdata *data = get_qsmmuv500_archdata(smmu);
-
- list_for_each_entry(tbu, &data->tbus, list) {
- qsmmuv500_tbu_resume(tbu);
- }
-}
-
static struct qsmmuv500_tbu_device *qsmmuv500_find_tbu(
struct arm_smmu_device *smmu, u32 sid)
{
@@ -4339,24 +4379,6 @@
return NULL;
}
-static void qsmmuv500_device_reset(struct arm_smmu_device *smmu)
-{
- int i, ret;
- struct arm_smmu_impl_def_reg *regs = smmu->impl_def_attach_registers;
-
- ret = qsmmuv500_tbu_power_on_all(smmu);
- if (ret)
- return;
-
- /* Program implementation defined registers */
- qsmmuv500_halt_all(smmu);
- for (i = 0; i < smmu->num_impl_def_attach_registers; ++i)
- writel_relaxed(regs[i].value,
- ARM_SMMU_GR0(smmu) + regs[i].offset);
- qsmmuv500_resume_all(smmu);
- qsmmuv500_tbu_power_off_all(smmu);
-}
-
static int qsmmuv500_ecats_lock(struct arm_smmu_domain *smmu_domain,
struct qsmmuv500_tbu_device *tbu,
unsigned long *flags)
@@ -4594,7 +4616,6 @@
struct arm_smmu_arch_ops qsmmuv500_arch_ops = {
.init = qsmmuv500_arch_init,
- .device_reset = qsmmuv500_device_reset,
.iova_to_phys_hard = qsmmuv500_iova_to_phys_hard,
};
diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c
index 2ef496d..dde2876 100644
--- a/drivers/iommu/io-pgtable-arm.c
+++ b/drivers/iommu/io-pgtable-arm.c
@@ -760,16 +760,7 @@
if (!iopte_tblcnt(*ptep)) {
/* no valid mappings left under this table. free it. */
__arm_lpae_set_pte(ptep, 0, &iop->cfg);
- io_pgtable_tlb_add_flush(iop, iova,
- entries * entry_size,
- ARM_LPAE_GRANULE(data),
- false);
__arm_lpae_free_pgtable(data, lvl + 1, table_base);
- } else {
- io_pgtable_tlb_add_flush(iop, iova,
- entries * entry_size,
- ARM_LPAE_GRANULE(data),
- true);
}
return entries * entry_size;
diff --git a/drivers/iommu/io-pgtable-fast.c b/drivers/iommu/io-pgtable-fast.c
index 2db06b0..04a9d7f 100644
--- a/drivers/iommu/io-pgtable-fast.c
+++ b/drivers/iommu/io-pgtable-fast.c
@@ -255,16 +255,17 @@
__av8l_fast_unmap(ptep, size, true);
}
-/* upper layer must take care of TLB invalidation */
static size_t av8l_fast_unmap(struct io_pgtable_ops *ops, unsigned long iova,
size_t size)
{
struct av8l_fast_io_pgtable *data = iof_pgtable_ops_to_data(ops);
+ struct io_pgtable *iop = &data->iop;
av8l_fast_iopte *ptep = iopte_pmd_offset(data->pmds, iova);
unsigned long nptes = size >> AV8L_FAST_PAGE_SHIFT;
__av8l_fast_unmap(ptep, size, false);
dmac_clean_range(ptep, ptep + nptes);
+ io_pgtable_tlb_flush_all(iop);
return size;
}
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index daccf64..779001e 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -647,6 +647,9 @@
int enabled;
u64 val;
+ if (cpu >= nr_cpu_ids)
+ return -EINVAL;
+
if (gic_irq_in_rdist(d))
return -EINVAL;
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 400839d..785d689 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -668,18 +668,9 @@
LEDs in both PWM and light pattern generator (LPG) modes. For older
PMICs, it also supports WLEDs and flash LEDs.
-config LEDS_QPNP_FLASH
- tristate "Support for QPNP Flash LEDs"
- depends on LEDS_CLASS && SPMI
- help
- This driver supports the flash LED functionality of Qualcomm
- Technologies, Inc. QPNP PMICs. This driver supports PMICs up through
- PM8994. It can configure the flash LED target current for several
- independent channels.
-
config LEDS_QPNP_FLASH_V2
tristate "Support for QPNP V2 Flash LEDs"
- depends on LEDS_CLASS && MFD_SPMI_PMIC && !LEDS_QPNP_FLASH
+ depends on LEDS_CLASS && MFD_SPMI_PMIC
help
This driver supports the flash V2 LED functionality of Qualcomm
Technologies, Inc. QPNP PMICs. This driver supports PMICs starting
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index ba9bb8d..2ff9a7c 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -72,7 +72,6 @@
obj-$(CONFIG_LEDS_PM8058) += leds-pm8058.o
obj-$(CONFIG_LEDS_MLXCPLD) += leds-mlxcpld.o
obj-$(CONFIG_LEDS_QPNP) += leds-qpnp.o
-obj-$(CONFIG_LEDS_QPNP_FLASH) += leds-qpnp-flash.o
obj-$(CONFIG_LEDS_QPNP_FLASH_V2) += leds-qpnp-flash-v2.o
obj-$(CONFIG_LEDS_QPNP_WLED) += leds-qpnp-wled.o
obj-$(CONFIG_LEDS_QPNP_HAPTICS) += leds-qpnp-haptics.o
diff --git a/drivers/leds/leds-qpnp-flash-v2.c b/drivers/leds/leds-qpnp-flash-v2.c
index 2678a00..5bd52e4 100644
--- a/drivers/leds/leds-qpnp-flash-v2.c
+++ b/drivers/leds/leds-qpnp-flash-v2.c
@@ -158,6 +158,11 @@
#define FLASH_LED_DISABLE 0x00
#define FLASH_LED_SAFETY_TMR_DISABLED 0x13
#define FLASH_LED_MAX_TOTAL_CURRENT_MA 3750
+#define FLASH_LED_IRES5P0_MAX_CURR_MA 640
+#define FLASH_LED_IRES7P5_MAX_CURR_MA 960
+#define FLASH_LED_IRES10P0_MAX_CURR_MA 1280
+#define FLASH_LED_IRES12P5_MAX_CURR_MA 1600
+#define MAX_IRES_LEVELS 4
/* notifier call chain for flash-led irqs */
static ATOMIC_NOTIFIER_HEAD(irq_notifier_list);
@@ -196,13 +201,15 @@
struct pinctrl_state *hw_strobe_state_suspend;
int hw_strobe_gpio;
int ires_ua;
+ int default_ires_ua;
int max_current;
int current_ma;
int prev_current_ma;
u8 duration;
u8 id;
u8 type;
- u8 ires;
+ u8 ires_idx;
+ u8 default_ires_idx;
u8 hdrm_val;
u8 current_reg_val;
u8 strobe_ctrl;
@@ -305,6 +312,11 @@
125, 119, 113, 107, 149, 143, 137, 131,
};
+static int max_ires_curr_ma_table[MAX_IRES_LEVELS] = {
+ FLASH_LED_IRES12P5_MAX_CURR_MA, FLASH_LED_IRES10P0_MAX_CURR_MA,
+ FLASH_LED_IRES7P5_MAX_CURR_MA, FLASH_LED_IRES5P0_MAX_CURR_MA
+};
+
static int qpnp_flash_led_read(struct qpnp_flash_led *led, u16 addr, u8 *data)
{
int rc;
@@ -935,6 +947,7 @@
static void qpnp_flash_led_node_set(struct flash_node_data *fnode, int value)
{
+ int i = 0;
int prgm_current_ma = value;
int min_ma = fnode->ires_ua / 1000;
struct qpnp_flash_led *led = dev_get_drvdata(&fnode->pdev->dev);
@@ -944,7 +957,22 @@
else if (value < min_ma)
prgm_current_ma = min_ma;
+ fnode->ires_idx = fnode->default_ires_idx;
+ fnode->ires_ua = fnode->default_ires_ua;
+
prgm_current_ma = min(prgm_current_ma, fnode->max_current);
+ if (prgm_current_ma > max_ires_curr_ma_table[fnode->ires_idx]) {
+ /* find the matching ires */
+ for (i = MAX_IRES_LEVELS - 1; i >= 0; i--) {
+ if (prgm_current_ma <= max_ires_curr_ma_table[i]) {
+ fnode->ires_idx = i;
+ fnode->ires_ua = FLASH_LED_IRES_MIN_UA +
+ (FLASH_LED_IRES_BASE - fnode->ires_idx) *
+ FLASH_LED_IRES_DIVISOR;
+ break;
+ }
+ }
+ }
fnode->current_ma = prgm_current_ma;
fnode->cdev.brightness = prgm_current_ma;
fnode->current_reg_val = CURRENT_MA_TO_REG_VAL(prgm_current_ma,
@@ -1062,7 +1090,7 @@
val = 0;
for (i = 0; i < led->num_fnodes; i++)
if (snode->led_mask & BIT(led->fnode[i].id))
- val |= led->fnode[i].ires << (led->fnode[i].id * 2);
+ val |= led->fnode[i].ires_idx << (led->fnode[i].id * 2);
rc = qpnp_flash_led_masked_write(led, FLASH_LED_REG_IRES(led->base),
FLASH_LED_CURRENT_MASK, val);
@@ -1434,13 +1462,14 @@
return rc;
}
- fnode->ires_ua = FLASH_LED_IRES_DEFAULT_UA;
- fnode->ires = FLASH_LED_IRES_DEFAULT_VAL;
+ fnode->default_ires_ua = fnode->ires_ua = FLASH_LED_IRES_DEFAULT_UA;
+ fnode->default_ires_idx = fnode->ires_idx = FLASH_LED_IRES_DEFAULT_VAL;
rc = of_property_read_u32(node, "qcom,ires-ua", &val);
if (!rc) {
- fnode->ires_ua = val;
- fnode->ires = FLASH_LED_IRES_BASE -
- (val - FLASH_LED_IRES_MIN_UA) / FLASH_LED_IRES_DIVISOR;
+ fnode->default_ires_ua = fnode->ires_ua = val;
+ fnode->default_ires_idx = fnode->ires_idx =
+ FLASH_LED_IRES_BASE - (val - FLASH_LED_IRES_MIN_UA) /
+ FLASH_LED_IRES_DIVISOR;
} else if (rc != -EINVAL) {
pr_err("Unable to read current resolution rc=%d\n", rc);
return rc;
diff --git a/drivers/leds/leds-qpnp-flash.c b/drivers/leds/leds-qpnp-flash.c
deleted file mode 100644
index c27c059..0000000
--- a/drivers/leds/leds-qpnp-flash.c
+++ /dev/null
@@ -1,2649 +0,0 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. 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 and
- * only 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/regmap.h>
-#include <linux/errno.h>
-#include <linux/leds.h>
-#include <linux/slab.h>
-#include <linux/of_device.h>
-#include <linux/spmi.h>
-#include <linux/platform_device.h>
-#include <linux/err.h>
-#include <linux/delay.h>
-#include <linux/of.h>
-#include <linux/regulator/consumer.h>
-#include <linux/workqueue.h>
-#include <linux/power_supply.h>
-#include <linux/leds-qpnp-flash.h>
-#include <linux/qpnp/qpnp-adc.h>
-#include <linux/qpnp/qpnp-revid.h>
-#include <linux/debugfs.h>
-#include <linux/uaccess.h>
-#include "leds.h"
-
-#define FLASH_LED_PERIPHERAL_SUBTYPE(base) (base + 0x05)
-#define FLASH_SAFETY_TIMER(base) (base + 0x40)
-#define FLASH_MAX_CURRENT(base) (base + 0x41)
-#define FLASH_LED0_CURRENT(base) (base + 0x42)
-#define FLASH_LED1_CURRENT(base) (base + 0x43)
-#define FLASH_CLAMP_CURRENT(base) (base + 0x44)
-#define FLASH_MODULE_ENABLE_CTRL(base) (base + 0x46)
-#define FLASH_LED_STROBE_CTRL(base) (base + 0x47)
-#define FLASH_LED_TMR_CTRL(base) (base + 0x48)
-#define FLASH_HEADROOM(base) (base + 0x4A)
-#define FLASH_STARTUP_DELAY(base) (base + 0x4B)
-#define FLASH_MASK_ENABLE(base) (base + 0x4C)
-#define FLASH_VREG_OK_FORCE(base) (base + 0x4F)
-#define FLASH_FAULT_DETECT(base) (base + 0x51)
-#define FLASH_THERMAL_DRATE(base) (base + 0x52)
-#define FLASH_CURRENT_RAMP(base) (base + 0x54)
-#define FLASH_VPH_PWR_DROOP(base) (base + 0x5A)
-#define FLASH_HDRM_SNS_ENABLE_CTRL0(base) (base + 0x5C)
-#define FLASH_HDRM_SNS_ENABLE_CTRL1(base) (base + 0x5D)
-#define FLASH_LED_UNLOCK_SECURE(base) (base + 0xD0)
-#define FLASH_PERPH_RESET_CTRL(base) (base + 0xDA)
-#define FLASH_TORCH(base) (base + 0xE4)
-
-#define FLASH_STATUS_REG_MASK 0xFF
-#define FLASH_LED_FAULT_STATUS(base) (base + 0x08)
-#define INT_LATCHED_STS(base) (base + 0x18)
-#define IN_POLARITY_HIGH(base) (base + 0x12)
-#define INT_SET_TYPE(base) (base + 0x11)
-#define INT_EN_SET(base) (base + 0x15)
-#define INT_LATCHED_CLR(base) (base + 0x14)
-
-#define FLASH_HEADROOM_MASK 0x03
-#define FLASH_STARTUP_DLY_MASK 0x03
-#define FLASH_VREG_OK_FORCE_MASK 0xC0
-#define FLASH_FAULT_DETECT_MASK 0x80
-#define FLASH_THERMAL_DERATE_MASK 0xBF
-#define FLASH_SECURE_MASK 0xFF
-#define FLASH_TORCH_MASK 0x03
-#define FLASH_CURRENT_MASK 0x7F
-#define FLASH_TMR_MASK 0x03
-#define FLASH_TMR_SAFETY 0x00
-#define FLASH_SAFETY_TIMER_MASK 0x7F
-#define FLASH_MODULE_ENABLE_MASK 0xE0
-#define FLASH_STROBE_MASK 0xC0
-#define FLASH_CURRENT_RAMP_MASK 0xBF
-#define FLASH_VPH_PWR_DROOP_MASK 0xF3
-#define FLASH_LED_HDRM_SNS_ENABLE_MASK 0x81
-#define FLASH_MASK_MODULE_CONTRL_MASK 0xE0
-#define FLASH_FOLLOW_OTST2_RB_MASK 0x08
-
-#define FLASH_LED_TRIGGER_DEFAULT "none"
-#define FLASH_LED_HEADROOM_DEFAULT_MV 500
-#define FLASH_LED_STARTUP_DELAY_DEFAULT_US 128
-#define FLASH_LED_CLAMP_CURRENT_DEFAULT_MA 200
-#define FLASH_LED_THERMAL_DERATE_THRESHOLD_DEFAULT_C 80
-#define FLASH_LED_RAMP_UP_STEP_DEFAULT_US 3
-#define FLASH_LED_RAMP_DN_STEP_DEFAULT_US 3
-#define FLASH_LED_VPH_PWR_DROOP_THRESHOLD_DEFAULT_MV 3200
-#define FLASH_LED_VPH_PWR_DROOP_DEBOUNCE_TIME_DEFAULT_US 10
-#define FLASH_LED_THERMAL_DERATE_RATE_DEFAULT_PERCENT 2
-#define FLASH_RAMP_UP_DELAY_US_MIN 1000
-#define FLASH_RAMP_UP_DELAY_US_MAX 1001
-#define FLASH_RAMP_DN_DELAY_US_MIN 2160
-#define FLASH_RAMP_DN_DELAY_US_MAX 2161
-#define FLASH_BOOST_REGULATOR_PROBE_DELAY_MS 2000
-#define FLASH_TORCH_MAX_LEVEL 0x0F
-#define FLASH_MAX_LEVEL 0x4F
-#define FLASH_LED_FLASH_HW_VREG_OK 0x40
-#define FLASH_LED_FLASH_SW_VREG_OK 0x80
-#define FLASH_LED_STROBE_TYPE_HW 0x04
-#define FLASH_DURATION_DIVIDER 10
-#define FLASH_LED_HEADROOM_DIVIDER 100
-#define FLASH_LED_HEADROOM_OFFSET 2
-#define FLASH_LED_MAX_CURRENT_MA 1000
-#define FLASH_LED_THERMAL_THRESHOLD_MIN 95
-#define FLASH_LED_THERMAL_DEVIDER 10
-#define FLASH_LED_VPH_DROOP_THRESHOLD_MIN_MV 2500
-#define FLASH_LED_VPH_DROOP_THRESHOLD_DIVIDER 100
-#define FLASH_LED_HDRM_SNS_ENABLE 0x81
-#define FLASH_LED_HDRM_SNS_DISABLE 0x01
-#define FLASH_LED_UA_PER_MA 1000
-#define FLASH_LED_MASK_MODULE_MASK2_ENABLE 0x20
-#define FLASH_LED_MASK3_ENABLE_SHIFT 7
-#define FLASH_LED_MODULE_CTRL_DEFAULT 0x60
-#define FLASH_LED_CURRENT_READING_DELAY_MIN 5000
-#define FLASH_LED_CURRENT_READING_DELAY_MAX 5001
-#define FLASH_LED_OPEN_FAULT_DETECTED 0xC
-
-#define FLASH_UNLOCK_SECURE 0xA5
-#define FLASH_LED_TORCH_ENABLE 0x00
-#define FLASH_LED_TORCH_DISABLE 0x03
-#define FLASH_MODULE_ENABLE 0x80
-#define FLASH_LED0_TRIGGER 0x80
-#define FLASH_LED1_TRIGGER 0x40
-#define FLASH_LED0_ENABLEMENT 0x40
-#define FLASH_LED1_ENABLEMENT 0x20
-#define FLASH_LED_DISABLE 0x00
-#define FLASH_LED_MIN_CURRENT_MA 13
-#define FLASH_SUBTYPE_DUAL 0x01
-#define FLASH_SUBTYPE_SINGLE 0x02
-
-/*
- * ID represents physical LEDs for individual control purpose.
- */
-enum flash_led_id {
- FLASH_LED_0 = 0,
- FLASH_LED_1,
- FLASH_LED_SWITCH,
-};
-
-enum flash_led_type {
- FLASH = 0,
- TORCH,
- SWITCH,
-};
-
-enum thermal_derate_rate {
- RATE_1_PERCENT = 0,
- RATE_1P25_PERCENT,
- RATE_2_PERCENT,
- RATE_2P5_PERCENT,
- RATE_5_PERCENT,
-};
-
-enum current_ramp_steps {
- RAMP_STEP_0P2_US = 0,
- RAMP_STEP_0P4_US,
- RAMP_STEP_0P8_US,
- RAMP_STEP_1P6_US,
- RAMP_STEP_3P3_US,
- RAMP_STEP_6P7_US,
- RAMP_STEP_13P5_US,
- RAMP_STEP_27US,
-};
-
-struct flash_regulator_data {
- struct regulator *regs;
- const char *reg_name;
- u32 max_volt_uv;
-};
-
-/*
- * Configurations for each individual LED
- */
-struct flash_node_data {
- struct platform_device *pdev;
- struct regmap *regmap;
- struct led_classdev cdev;
- struct work_struct work;
- struct flash_regulator_data *reg_data;
- u16 max_current;
- u16 prgm_current;
- u16 prgm_current2;
- u16 duration;
- u8 id;
- u8 type;
- u8 trigger;
- u8 enable;
- u8 num_regulators;
- bool flash_on;
-};
-
-/*
- * Flash LED configuration read from device tree
- */
-struct flash_led_platform_data {
- unsigned int temp_threshold_num;
- unsigned int temp_derate_curr_num;
- unsigned int *die_temp_derate_curr_ma;
- unsigned int *die_temp_threshold_degc;
- u16 ramp_up_step;
- u16 ramp_dn_step;
- u16 vph_pwr_droop_threshold;
- u16 headroom;
- u16 clamp_current;
- u8 thermal_derate_threshold;
- u8 vph_pwr_droop_debounce_time;
- u8 startup_dly;
- u8 thermal_derate_rate;
- bool pmic_charger_support;
- bool self_check_en;
- bool thermal_derate_en;
- bool current_ramp_en;
- bool vph_pwr_droop_en;
- bool hdrm_sns_ch0_en;
- bool hdrm_sns_ch1_en;
- bool power_detect_en;
- bool mask3_en;
- bool follow_rb_disable;
- bool die_current_derate_en;
-};
-
-struct qpnp_flash_led_buffer {
- size_t rpos;
- size_t wpos;
- size_t len;
- char data[0];
-};
-
-/*
- * Flash LED data structure containing flash LED attributes
- */
-struct qpnp_flash_led {
- struct pmic_revid_data *revid_data;
- struct platform_device *pdev;
- struct regmap *regmap;
- struct flash_led_platform_data *pdata;
- struct pinctrl *pinctrl;
- struct pinctrl_state *gpio_state_active;
- struct pinctrl_state *gpio_state_suspend;
- struct flash_node_data *flash_node;
- struct power_supply *battery_psy;
- struct workqueue_struct *ordered_workq;
- struct qpnp_vadc_chip *vadc_dev;
- struct mutex flash_led_lock;
- struct qpnp_flash_led_buffer *log;
- struct dentry *dbgfs_root;
- int num_leds;
- u32 buffer_cnt;
- u16 base;
- u16 current_addr;
- u16 current2_addr;
- u8 peripheral_type;
- u8 fault_reg;
- bool gpio_enabled;
- bool charging_enabled;
- bool strobe_debug;
- bool dbg_feature_en;
- bool open_fault;
-};
-
-static u8 qpnp_flash_led_ctrl_dbg_regs[] = {
- 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
- 0x4A, 0x4B, 0x4C, 0x4F, 0x51, 0x52, 0x54, 0x55, 0x5A, 0x5C, 0x5D,
-};
-
-static int flash_led_dbgfs_file_open(struct qpnp_flash_led *led,
- struct file *file)
-{
- struct qpnp_flash_led_buffer *log;
- size_t logbufsize = SZ_4K;
-
- log = kzalloc(logbufsize, GFP_KERNEL);
- if (!log)
- return -ENOMEM;
-
- log->rpos = 0;
- log->wpos = 0;
- log->len = logbufsize - sizeof(*log);
- led->log = log;
-
- led->buffer_cnt = 1;
- file->private_data = led;
-
- return 0;
-}
-
-static int flash_led_dfs_open(struct inode *inode, struct file *file)
-{
- struct qpnp_flash_led *led = inode->i_private;
-
- return flash_led_dbgfs_file_open(led, file);
-}
-
-static int flash_led_dfs_close(struct inode *inode, struct file *file)
-{
- struct qpnp_flash_led *led = file->private_data;
-
- if (led && led->log) {
- file->private_data = NULL;
- kfree(led->log);
- }
-
- return 0;
-}
-
-static int print_to_log(struct qpnp_flash_led_buffer *log,
- const char *fmt, ...)
-{
- va_list args;
- int cnt;
- char *log_buf = &log->data[log->wpos];
- size_t size = log->len - log->wpos;
-
- va_start(args, fmt);
- cnt = vscnprintf(log_buf, size, fmt, args);
- va_end(args);
-
- log->wpos += cnt;
- return cnt;
-}
-
-static ssize_t flash_led_dfs_latched_reg_read(struct file *fp, char __user *buf,
- size_t count, loff_t *ppos) {
- struct qpnp_flash_led *led = fp->private_data;
- struct qpnp_flash_led_buffer *log = led->log;
- uint val;
- int rc;
- size_t len;
- size_t ret;
-
- if (log->rpos >= log->wpos && led->buffer_cnt == 0)
- return 0;
-
- rc = regmap_read(led->regmap, INT_LATCHED_STS(led->base), &val);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Unable to read from address %x, rc(%d)\n",
- INT_LATCHED_STS(led->base), rc);
- return -EINVAL;
- }
- led->buffer_cnt--;
-
- rc = print_to_log(log, "0x%05X ", INT_LATCHED_STS(led->base));
- if (rc == 0)
- return rc;
-
- rc = print_to_log(log, "0x%02X ", val);
- if (rc == 0)
- return rc;
-
- if (log->wpos > 0 && log->data[log->wpos - 1] == ' ')
- log->data[log->wpos - 1] = '\n';
-
- len = min(count, log->wpos - log->rpos);
-
- ret = copy_to_user(buf, &log->data[log->rpos], len);
- if (ret) {
- pr_err("error copy register value to user\n");
- return -EFAULT;
- }
-
- len -= ret;
- *ppos += len;
- log->rpos += len;
-
- return len;
-}
-
-static ssize_t flash_led_dfs_fault_reg_read(struct file *fp, char __user *buf,
- size_t count, loff_t *ppos) {
- struct qpnp_flash_led *led = fp->private_data;
- struct qpnp_flash_led_buffer *log = led->log;
- int rc;
- size_t len;
- size_t ret;
-
- if (log->rpos >= log->wpos && led->buffer_cnt == 0)
- return 0;
-
- led->buffer_cnt--;
-
- rc = print_to_log(log, "0x%05X ", FLASH_LED_FAULT_STATUS(led->base));
- if (rc == 0)
- return rc;
-
- rc = print_to_log(log, "0x%02X ", led->fault_reg);
- if (rc == 0)
- return rc;
-
- if (log->wpos > 0 && log->data[log->wpos - 1] == ' ')
- log->data[log->wpos - 1] = '\n';
-
- len = min(count, log->wpos - log->rpos);
-
- ret = copy_to_user(buf, &log->data[log->rpos], len);
- if (ret) {
- pr_err("error copy register value to user\n");
- return -EFAULT;
- }
-
- len -= ret;
- *ppos += len;
- log->rpos += len;
-
- return len;
-}
-
-static ssize_t flash_led_dfs_fault_reg_enable(struct file *file,
- const char __user *buf, size_t count, loff_t *ppos) {
-
- u8 *val;
- int pos = 0;
- int cnt = 0;
- int data;
- size_t ret = 0;
-
- struct qpnp_flash_led *led = file->private_data;
- char *kbuf = kmalloc(count + 1, GFP_KERNEL);
-
- if (!kbuf)
- return -ENOMEM;
-
- ret = copy_from_user(kbuf, buf, count);
- if (!ret) {
- pr_err("failed to copy data from user\n");
- ret = -EFAULT;
- goto free_buf;
- }
-
- count -= ret;
- *ppos += count;
- kbuf[count] = '\0';
- val = kbuf;
- while (sscanf(kbuf + pos, "%i", &data) == 1) {
- pos++;
- val[cnt++] = data & 0xff;
- }
-
- if (!cnt)
- goto free_buf;
-
- ret = count;
- if (*val == 1)
- led->strobe_debug = true;
- else
- led->strobe_debug = false;
-
-free_buf:
- kfree(kbuf);
- return ret;
-}
-
-static ssize_t flash_led_dfs_dbg_enable(struct file *file,
- const char __user *buf, size_t count, loff_t *ppos) {
-
- u8 *val;
- int pos = 0;
- int cnt = 0;
- int data;
- size_t ret = 0;
- struct qpnp_flash_led *led = file->private_data;
- char *kbuf = kmalloc(count + 1, GFP_KERNEL);
-
- if (!kbuf)
- return -ENOMEM;
-
- ret = copy_from_user(kbuf, buf, count);
- if (ret == count) {
- pr_err("failed to copy data from user\n");
- ret = -EFAULT;
- goto free_buf;
- }
- count -= ret;
- *ppos += count;
- kbuf[count] = '\0';
- val = kbuf;
- while (sscanf(kbuf + pos, "%i", &data) == 1) {
- pos++;
- val[cnt++] = data & 0xff;
- }
-
- if (!cnt)
- goto free_buf;
-
- ret = count;
- if (*val == 1)
- led->dbg_feature_en = true;
- else
- led->dbg_feature_en = false;
-
-free_buf:
- kfree(kbuf);
- return ret;
-}
-
-static const struct file_operations flash_led_dfs_latched_reg_fops = {
- .open = flash_led_dfs_open,
- .release = flash_led_dfs_close,
- .read = flash_led_dfs_latched_reg_read,
-};
-
-static const struct file_operations flash_led_dfs_strobe_reg_fops = {
- .open = flash_led_dfs_open,
- .release = flash_led_dfs_close,
- .read = flash_led_dfs_fault_reg_read,
- .write = flash_led_dfs_fault_reg_enable,
-};
-
-static const struct file_operations flash_led_dfs_dbg_feature_fops = {
- .open = flash_led_dfs_open,
- .release = flash_led_dfs_close,
- .write = flash_led_dfs_dbg_enable,
-};
-
-static int
-qpnp_led_masked_write(struct qpnp_flash_led *led, u16 addr, u8 mask, u8 val)
-{
- int rc;
-
- rc = regmap_update_bits(led->regmap, addr, mask, val);
- if (rc)
- dev_err(&led->pdev->dev,
- "Unable to update_bits to addr=%x, rc(%d)\n", addr, rc);
-
- dev_dbg(&led->pdev->dev, "Write 0x%02X to addr 0x%02X\n", val, addr);
-
- return rc;
-}
-
-static int qpnp_flash_led_get_allowed_die_temp_curr(struct qpnp_flash_led *led,
- int64_t die_temp_degc)
-{
- int die_temp_curr_ma;
-
- if (die_temp_degc >= led->pdata->die_temp_threshold_degc[0])
- die_temp_curr_ma = 0;
- else if (die_temp_degc >= led->pdata->die_temp_threshold_degc[1])
- die_temp_curr_ma = led->pdata->die_temp_derate_curr_ma[0];
- else if (die_temp_degc >= led->pdata->die_temp_threshold_degc[2])
- die_temp_curr_ma = led->pdata->die_temp_derate_curr_ma[1];
- else if (die_temp_degc >= led->pdata->die_temp_threshold_degc[3])
- die_temp_curr_ma = led->pdata->die_temp_derate_curr_ma[2];
- else if (die_temp_degc >= led->pdata->die_temp_threshold_degc[4])
- die_temp_curr_ma = led->pdata->die_temp_derate_curr_ma[3];
- else
- die_temp_curr_ma = led->pdata->die_temp_derate_curr_ma[4];
-
- return die_temp_curr_ma;
-}
-
-static int64_t qpnp_flash_led_get_die_temp(struct qpnp_flash_led *led)
-{
- struct qpnp_vadc_result die_temp_result;
- int rc;
-
- rc = qpnp_vadc_read(led->vadc_dev, SPARE2, &die_temp_result);
- if (rc) {
- pr_err("failed to read the die temp\n");
- return -EINVAL;
- }
-
- return die_temp_result.physical;
-}
-
-static int qpnp_get_pmic_revid(struct qpnp_flash_led *led)
-{
- struct device_node *revid_dev_node;
-
- revid_dev_node = of_parse_phandle(led->pdev->dev.of_node,
- "qcom,pmic-revid", 0);
- if (!revid_dev_node) {
- dev_err(&led->pdev->dev,
- "qcom,pmic-revid property missing\n");
- return -EINVAL;
- }
-
- led->revid_data = get_revid_data(revid_dev_node);
- if (IS_ERR(led->revid_data)) {
- pr_err("Couldn't get revid data rc = %ld\n",
- PTR_ERR(led->revid_data));
- return PTR_ERR(led->revid_data);
- }
-
- return 0;
-}
-
-static int
-qpnp_flash_led_get_max_avail_current(struct flash_node_data *flash_node,
- struct qpnp_flash_led *led)
-{
- union power_supply_propval prop;
- int64_t chg_temp_milidegc, die_temp_degc;
- int max_curr_avail_ma = 2000;
- int allowed_die_temp_curr_ma = 2000;
- int rc;
-
- if (led->pdata->power_detect_en) {
- if (!led->battery_psy) {
- dev_err(&led->pdev->dev,
- "Failed to query power supply\n");
- return -EINVAL;
- }
-
- /*
- * When charging is enabled, enforce this new enablement
- * sequence to reduce fuel gauge reading resolution.
- */
- if (led->charging_enabled) {
- rc = qpnp_led_masked_write(led,
- FLASH_MODULE_ENABLE_CTRL(led->base),
- FLASH_MODULE_ENABLE, FLASH_MODULE_ENABLE);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Module enable reg write failed\n");
- return -EINVAL;
- }
-
- usleep_range(FLASH_LED_CURRENT_READING_DELAY_MIN,
- FLASH_LED_CURRENT_READING_DELAY_MAX);
- }
-
- power_supply_get_property(led->battery_psy,
- POWER_SUPPLY_PROP_FLASH_CURRENT_MAX, &prop);
- if (!prop.intval) {
- dev_err(&led->pdev->dev,
- "battery too low for flash\n");
- return -EINVAL;
- }
-
- max_curr_avail_ma = (prop.intval / FLASH_LED_UA_PER_MA);
- }
-
- /*
- * When thermal mitigation is available, this logic will execute to
- * derate current based upon the PMIC die temperature.
- */
- if (led->pdata->die_current_derate_en) {
- chg_temp_milidegc = qpnp_flash_led_get_die_temp(led);
- if (chg_temp_milidegc < 0)
- return -EINVAL;
-
- die_temp_degc = div_s64(chg_temp_milidegc, 1000);
- allowed_die_temp_curr_ma =
- qpnp_flash_led_get_allowed_die_temp_curr(led,
- die_temp_degc);
- if (allowed_die_temp_curr_ma < 0)
- return -EINVAL;
- }
-
- max_curr_avail_ma = (max_curr_avail_ma >= allowed_die_temp_curr_ma)
- ? allowed_die_temp_curr_ma : max_curr_avail_ma;
-
- return max_curr_avail_ma;
-}
-
-static ssize_t qpnp_flash_led_die_temp_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct qpnp_flash_led *led;
- struct flash_node_data *flash_node;
- unsigned long val;
- struct led_classdev *led_cdev = dev_get_drvdata(dev);
- ssize_t ret;
-
- ret = kstrtoul(buf, 10, &val);
- if (ret)
- return ret;
-
- flash_node = container_of(led_cdev, struct flash_node_data, cdev);
- led = dev_get_drvdata(&flash_node->pdev->dev);
-
- /*'0' for disable die_temp feature; non-zero to enable feature*/
- if (val == 0)
- led->pdata->die_current_derate_en = false;
- else
- led->pdata->die_current_derate_en = true;
-
- return count;
-}
-
-static ssize_t qpnp_led_strobe_type_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct flash_node_data *flash_node;
- unsigned long state;
- struct led_classdev *led_cdev = dev_get_drvdata(dev);
- ssize_t ret = -EINVAL;
-
- ret = kstrtoul(buf, 10, &state);
- if (ret)
- return ret;
-
- flash_node = container_of(led_cdev, struct flash_node_data, cdev);
-
- /* '0' for sw strobe; '1' for hw strobe */
- if (state == 1)
- flash_node->trigger |= FLASH_LED_STROBE_TYPE_HW;
- else
- flash_node->trigger &= ~FLASH_LED_STROBE_TYPE_HW;
-
- return count;
-}
-
-static ssize_t qpnp_flash_led_dump_regs_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct qpnp_flash_led *led;
- struct flash_node_data *flash_node;
- struct led_classdev *led_cdev = dev_get_drvdata(dev);
- int rc, i, count = 0;
- u16 addr;
- uint val;
-
- flash_node = container_of(led_cdev, struct flash_node_data, cdev);
- led = dev_get_drvdata(&flash_node->pdev->dev);
- for (i = 0; i < ARRAY_SIZE(qpnp_flash_led_ctrl_dbg_regs); i++) {
- addr = led->base + qpnp_flash_led_ctrl_dbg_regs[i];
- rc = regmap_read(led->regmap, addr, &val);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Unable to read from addr=%x, rc(%d)\n",
- addr, rc);
- return -EINVAL;
- }
-
- count += snprintf(buf + count, PAGE_SIZE - count,
- "REG_0x%x = 0x%02x\n", addr, val);
-
- if (count >= PAGE_SIZE)
- return PAGE_SIZE - 1;
- }
-
- return count;
-}
-
-static ssize_t qpnp_flash_led_current_derate_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct qpnp_flash_led *led;
- struct flash_node_data *flash_node;
- unsigned long val;
- struct led_classdev *led_cdev = dev_get_drvdata(dev);
- ssize_t ret;
-
- ret = kstrtoul(buf, 10, &val);
- if (ret)
- return ret;
-
- flash_node = container_of(led_cdev, struct flash_node_data, cdev);
- led = dev_get_drvdata(&flash_node->pdev->dev);
-
- /*'0' for disable derate feature; non-zero to enable derate feature */
- if (val == 0)
- led->pdata->power_detect_en = false;
- else
- led->pdata->power_detect_en = true;
-
- return count;
-}
-
-static ssize_t qpnp_flash_led_max_current_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct qpnp_flash_led *led;
- struct flash_node_data *flash_node;
- struct led_classdev *led_cdev = dev_get_drvdata(dev);
- int max_curr_avail_ma = 0;
-
- flash_node = container_of(led_cdev, struct flash_node_data, cdev);
- led = dev_get_drvdata(&flash_node->pdev->dev);
-
- if (led->flash_node[0].flash_on)
- max_curr_avail_ma += led->flash_node[0].max_current;
- if (led->flash_node[1].flash_on)
- max_curr_avail_ma += led->flash_node[1].max_current;
-
- if (led->pdata->power_detect_en ||
- led->pdata->die_current_derate_en) {
- max_curr_avail_ma =
- qpnp_flash_led_get_max_avail_current(flash_node, led);
-
- if (max_curr_avail_ma < 0)
- return -EINVAL;
- }
-
- return snprintf(buf, PAGE_SIZE, "%u\n", max_curr_avail_ma);
-}
-
-static struct device_attribute qpnp_flash_led_attrs[] = {
- __ATTR(strobe, 0664, NULL, qpnp_led_strobe_type_store),
- __ATTR(reg_dump, 0664, qpnp_flash_led_dump_regs_show, NULL),
- __ATTR(enable_current_derate, 0664, NULL,
- qpnp_flash_led_current_derate_store),
- __ATTR(max_allowed_current, 0664, qpnp_flash_led_max_current_show,
- NULL),
- __ATTR(enable_die_temp_current_derate, 0664, NULL,
- qpnp_flash_led_die_temp_store),
-};
-
-static int qpnp_flash_led_get_thermal_derate_rate(const char *rate)
-{
- /*
- * return 5% derate as default value if user specifies
- * a value un-supported
- */
- if (strcmp(rate, "1_PERCENT") == 0)
- return RATE_1_PERCENT;
- else if (strcmp(rate, "1P25_PERCENT") == 0)
- return RATE_1P25_PERCENT;
- else if (strcmp(rate, "2_PERCENT") == 0)
- return RATE_2_PERCENT;
- else if (strcmp(rate, "2P5_PERCENT") == 0)
- return RATE_2P5_PERCENT;
- else if (strcmp(rate, "5_PERCENT") == 0)
- return RATE_5_PERCENT;
- else
- return RATE_5_PERCENT;
-}
-
-static int qpnp_flash_led_get_ramp_step(const char *step)
-{
- /*
- * return 27 us as default value if user specifies
- * a value un-supported
- */
- if (strcmp(step, "0P2_US") == 0)
- return RAMP_STEP_0P2_US;
- else if (strcmp(step, "0P4_US") == 0)
- return RAMP_STEP_0P4_US;
- else if (strcmp(step, "0P8_US") == 0)
- return RAMP_STEP_0P8_US;
- else if (strcmp(step, "1P6_US") == 0)
- return RAMP_STEP_1P6_US;
- else if (strcmp(step, "3P3_US") == 0)
- return RAMP_STEP_3P3_US;
- else if (strcmp(step, "6P7_US") == 0)
- return RAMP_STEP_6P7_US;
- else if (strcmp(step, "13P5_US") == 0)
- return RAMP_STEP_13P5_US;
- else
- return RAMP_STEP_27US;
-}
-
-static u8 qpnp_flash_led_get_droop_debounce_time(u8 val)
-{
- /*
- * return 10 us as default value if user specifies
- * a value un-supported
- */
- switch (val) {
- case 0:
- return 0;
- case 10:
- return 1;
- case 32:
- return 2;
- case 64:
- return 3;
- default:
- return 1;
- }
-}
-
-static u8 qpnp_flash_led_get_startup_dly(u8 val)
-{
- /*
- * return 128 us as default value if user specifies
- * a value un-supported
- */
- switch (val) {
- case 10:
- return 0;
- case 32:
- return 1;
- case 64:
- return 2;
- case 128:
- return 3;
- default:
- return 3;
- }
-}
-
-static int
-qpnp_flash_led_get_peripheral_type(struct qpnp_flash_led *led)
-{
- int rc;
- uint val;
-
- rc = regmap_read(led->regmap,
- FLASH_LED_PERIPHERAL_SUBTYPE(led->base), &val);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Unable to read peripheral subtype\n");
- return -EINVAL;
- }
-
- return val;
-}
-
-static int qpnp_flash_led_module_disable(struct qpnp_flash_led *led,
- struct flash_node_data *flash_node)
-{
- union power_supply_propval psy_prop;
- int rc;
- uint val, tmp;
-
- rc = regmap_read(led->regmap, FLASH_LED_STROBE_CTRL(led->base), &val);
- if (rc) {
- dev_err(&led->pdev->dev, "Unable to read strobe reg\n");
- return -EINVAL;
- }
-
- tmp = (~flash_node->trigger) & val;
- if (!tmp) {
- if (flash_node->type == TORCH) {
- rc = qpnp_led_masked_write(led,
- FLASH_LED_UNLOCK_SECURE(led->base),
- FLASH_SECURE_MASK, FLASH_UNLOCK_SECURE);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Secure reg write failed\n");
- return -EINVAL;
- }
-
- rc = qpnp_led_masked_write(led,
- FLASH_TORCH(led->base),
- FLASH_TORCH_MASK, FLASH_LED_TORCH_DISABLE);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Torch reg write failed\n");
- return -EINVAL;
- }
- }
-
- if (led->battery_psy &&
- led->revid_data->pmic_subtype == PMI8996_SUBTYPE &&
- !led->revid_data->rev3) {
- psy_prop.intval = false;
- rc = power_supply_set_property(led->battery_psy,
- POWER_SUPPLY_PROP_FLASH_TRIGGER,
- &psy_prop);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Failed to enble charger i/p current limit\n");
- return -EINVAL;
- }
- }
-
- rc = qpnp_led_masked_write(led,
- FLASH_MODULE_ENABLE_CTRL(led->base),
- FLASH_MODULE_ENABLE_MASK,
- FLASH_LED_MODULE_CTRL_DEFAULT);
- if (rc) {
- dev_err(&led->pdev->dev, "Module disable failed\n");
- return -EINVAL;
- }
-
- if (led->pinctrl) {
- rc = pinctrl_select_state(led->pinctrl,
- led->gpio_state_suspend);
- if (rc) {
- dev_err(&led->pdev->dev,
- "failed to disable GPIO\n");
- return -EINVAL;
- }
- led->gpio_enabled = false;
- }
-
- if (led->battery_psy) {
- psy_prop.intval = false;
- rc = power_supply_set_property(led->battery_psy,
- POWER_SUPPLY_PROP_FLASH_ACTIVE,
- &psy_prop);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Failed to setup OTG pulse skip enable\n");
- return -EINVAL;
- }
- }
- }
-
- if (flash_node->trigger & FLASH_LED0_TRIGGER) {
- rc = qpnp_led_masked_write(led,
- led->current_addr,
- FLASH_CURRENT_MASK, 0x00);
- if (rc) {
- dev_err(&led->pdev->dev,
- "current register write failed\n");
- return -EINVAL;
- }
- }
-
- if (flash_node->trigger & FLASH_LED1_TRIGGER) {
- rc = qpnp_led_masked_write(led,
- led->current2_addr,
- FLASH_CURRENT_MASK, 0x00);
- if (rc) {
- dev_err(&led->pdev->dev,
- "current register write failed\n");
- return -EINVAL;
- }
- }
-
- if (flash_node->id == FLASH_LED_SWITCH)
- flash_node->trigger &= FLASH_LED_STROBE_TYPE_HW;
-
- return 0;
-}
-
-static enum
-led_brightness qpnp_flash_led_brightness_get(struct led_classdev *led_cdev)
-{
- return led_cdev->brightness;
-}
-
-static int flash_regulator_parse_dt(struct qpnp_flash_led *led,
- struct flash_node_data *flash_node) {
-
- int i = 0, rc;
- struct device_node *node = flash_node->cdev.dev->of_node;
- struct device_node *temp = NULL;
- const char *temp_string;
- u32 val;
-
- flash_node->reg_data = devm_kzalloc(&led->pdev->dev,
- sizeof(struct flash_regulator_data *) *
- flash_node->num_regulators,
- GFP_KERNEL);
- if (!flash_node->reg_data) {
- dev_err(&led->pdev->dev,
- "Unable to allocate memory\n");
- return -ENOMEM;
- }
-
- for_each_child_of_node(node, temp) {
- rc = of_property_read_string(temp, "regulator-name",
- &temp_string);
- if (!rc)
- flash_node->reg_data[i].reg_name = temp_string;
- else {
- dev_err(&led->pdev->dev,
- "Unable to read regulator name\n");
- return rc;
- }
-
- rc = of_property_read_u32(temp, "max-voltage", &val);
- if (!rc) {
- flash_node->reg_data[i].max_volt_uv = val;
- } else if (rc != -EINVAL) {
- dev_err(&led->pdev->dev,
- "Unable to read max voltage\n");
- return rc;
- }
-
- i++;
- }
-
- return 0;
-}
-
-static int flash_regulator_setup(struct qpnp_flash_led *led,
- struct flash_node_data *flash_node, bool on)
-{
- int i, rc = 0;
-
- if (on == false) {
- i = flash_node->num_regulators;
- goto error_regulator_setup;
- }
-
- for (i = 0; i < flash_node->num_regulators; i++) {
- flash_node->reg_data[i].regs =
- regulator_get(flash_node->cdev.dev,
- flash_node->reg_data[i].reg_name);
- if (IS_ERR(flash_node->reg_data[i].regs)) {
- rc = PTR_ERR(flash_node->reg_data[i].regs);
- dev_err(&led->pdev->dev,
- "Failed to get regulator\n");
- goto error_regulator_setup;
- }
-
- if (regulator_count_voltages(flash_node->reg_data[i].regs)
- > 0) {
- rc = regulator_set_voltage(flash_node->reg_data[i].regs,
- flash_node->reg_data[i].max_volt_uv,
- flash_node->reg_data[i].max_volt_uv);
- if (rc) {
- dev_err(&led->pdev->dev,
- "regulator set voltage failed\n");
- regulator_put(flash_node->reg_data[i].regs);
- goto error_regulator_setup;
- }
- }
- }
-
- return rc;
-
-error_regulator_setup:
- while (i--) {
- if (regulator_count_voltages(flash_node->reg_data[i].regs)
- > 0) {
- regulator_set_voltage(flash_node->reg_data[i].regs,
- 0, flash_node->reg_data[i].max_volt_uv);
- }
-
- regulator_put(flash_node->reg_data[i].regs);
- }
-
- return rc;
-}
-
-static int flash_regulator_enable(struct qpnp_flash_led *led,
- struct flash_node_data *flash_node, bool on)
-{
- int i, rc = 0;
-
- if (on == false) {
- i = flash_node->num_regulators;
- goto error_regulator_enable;
- }
-
- for (i = 0; i < flash_node->num_regulators; i++) {
- rc = regulator_enable(flash_node->reg_data[i].regs);
- if (rc) {
- dev_err(&led->pdev->dev,
- "regulator enable failed\n");
- goto error_regulator_enable;
- }
- }
-
- return rc;
-
-error_regulator_enable:
- while (i--)
- regulator_disable(flash_node->reg_data[i].regs);
-
- return rc;
-}
-
-int qpnp_flash_led_prepare(struct led_trigger *trig, int options,
- int *max_current)
-{
- struct led_classdev *led_cdev = trigger_to_lcdev(trig);
- struct flash_node_data *flash_node;
- struct qpnp_flash_led *led;
- int rc;
-
- if (!led_cdev) {
- pr_err("Invalid led_trigger provided\n");
- return -EINVAL;
- }
-
- flash_node = container_of(led_cdev, struct flash_node_data, cdev);
- led = dev_get_drvdata(&flash_node->pdev->dev);
-
- if (!(options & FLASH_LED_PREPARE_OPTIONS_MASK)) {
- dev_err(&led->pdev->dev, "Invalid options %d\n", options);
- return -EINVAL;
- }
-
- if (options & ENABLE_REGULATOR) {
- rc = flash_regulator_enable(led, flash_node, true);
- if (rc < 0) {
- dev_err(&led->pdev->dev,
- "enable regulator failed, rc=%d\n", rc);
- return rc;
- }
- }
-
- if (options & DISABLE_REGULATOR) {
- rc = flash_regulator_enable(led, flash_node, false);
- if (rc < 0) {
- dev_err(&led->pdev->dev,
- "disable regulator failed, rc=%d\n", rc);
- return rc;
- }
- }
-
- if (options & QUERY_MAX_CURRENT) {
- rc = qpnp_flash_led_get_max_avail_current(flash_node, led);
- if (rc < 0) {
- dev_err(&led->pdev->dev,
- "query max current failed, rc=%d\n", rc);
- return rc;
- }
- *max_current = rc;
- }
-
- return 0;
-}
-
-static void qpnp_flash_led_work(struct work_struct *work)
-{
- struct flash_node_data *flash_node = container_of(work,
- struct flash_node_data, work);
- struct qpnp_flash_led *led = dev_get_drvdata(&flash_node->pdev->dev);
- union power_supply_propval psy_prop;
- int rc, brightness = flash_node->cdev.brightness;
- int max_curr_avail_ma = 0;
- int total_curr_ma = 0;
- int i;
- u8 val;
- uint temp;
-
- mutex_lock(&led->flash_led_lock);
-
- if (!brightness)
- goto turn_off;
-
- if (led->open_fault) {
- dev_err(&led->pdev->dev, "Open fault detected\n");
- mutex_unlock(&led->flash_led_lock);
- return;
- }
-
- if (!flash_node->flash_on && flash_node->num_regulators > 0) {
- rc = flash_regulator_enable(led, flash_node, true);
- if (rc) {
- mutex_unlock(&led->flash_led_lock);
- return;
- }
- }
-
- if (!led->gpio_enabled && led->pinctrl) {
- rc = pinctrl_select_state(led->pinctrl,
- led->gpio_state_active);
- if (rc) {
- dev_err(&led->pdev->dev, "failed to enable GPIO\n");
- goto error_enable_gpio;
- }
- led->gpio_enabled = true;
- }
-
- if (led->dbg_feature_en) {
- rc = qpnp_led_masked_write(led,
- INT_SET_TYPE(led->base),
- FLASH_STATUS_REG_MASK, 0x1F);
- if (rc) {
- dev_err(&led->pdev->dev,
- "INT_SET_TYPE write failed\n");
- goto exit_flash_led_work;
- }
-
- rc = qpnp_led_masked_write(led,
- IN_POLARITY_HIGH(led->base),
- FLASH_STATUS_REG_MASK, 0x1F);
- if (rc) {
- dev_err(&led->pdev->dev,
- "IN_POLARITY_HIGH write failed\n");
- goto exit_flash_led_work;
- }
-
- rc = qpnp_led_masked_write(led,
- INT_EN_SET(led->base),
- FLASH_STATUS_REG_MASK, 0x1F);
- if (rc) {
- dev_err(&led->pdev->dev, "INT_EN_SET write failed\n");
- goto exit_flash_led_work;
- }
-
- rc = qpnp_led_masked_write(led,
- INT_LATCHED_CLR(led->base),
- FLASH_STATUS_REG_MASK, 0x1F);
- if (rc) {
- dev_err(&led->pdev->dev,
- "INT_LATCHED_CLR write failed\n");
- goto exit_flash_led_work;
- }
- }
-
- if (led->flash_node[led->num_leds - 1].id == FLASH_LED_SWITCH &&
- flash_node->id != FLASH_LED_SWITCH) {
- led->flash_node[led->num_leds - 1].trigger |=
- (0x80 >> flash_node->id);
- if (flash_node->id == FLASH_LED_0)
- led->flash_node[led->num_leds - 1].prgm_current =
- flash_node->prgm_current;
- else if (flash_node->id == FLASH_LED_1)
- led->flash_node[led->num_leds - 1].prgm_current2 =
- flash_node->prgm_current;
- }
-
- if (flash_node->type == TORCH) {
- rc = qpnp_led_masked_write(led,
- FLASH_LED_UNLOCK_SECURE(led->base),
- FLASH_SECURE_MASK, FLASH_UNLOCK_SECURE);
- if (rc) {
- dev_err(&led->pdev->dev, "Secure reg write failed\n");
- goto exit_flash_led_work;
- }
-
- rc = qpnp_led_masked_write(led,
- FLASH_TORCH(led->base),
- FLASH_TORCH_MASK, FLASH_LED_TORCH_ENABLE);
- if (rc) {
- dev_err(&led->pdev->dev, "Torch reg write failed\n");
- goto exit_flash_led_work;
- }
-
- if (flash_node->id == FLASH_LED_SWITCH) {
- val = (u8)(flash_node->prgm_current *
- FLASH_TORCH_MAX_LEVEL
- / flash_node->max_current);
- rc = qpnp_led_masked_write(led,
- led->current_addr,
- FLASH_CURRENT_MASK, val);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Torch reg write failed\n");
- goto exit_flash_led_work;
- }
-
- val = (u8)(flash_node->prgm_current2 *
- FLASH_TORCH_MAX_LEVEL
- / flash_node->max_current);
- rc = qpnp_led_masked_write(led,
- led->current2_addr,
- FLASH_CURRENT_MASK, val);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Torch reg write failed\n");
- goto exit_flash_led_work;
- }
- } else {
- val = (u8)(flash_node->prgm_current *
- FLASH_TORCH_MAX_LEVEL /
- flash_node->max_current);
- if (flash_node->id == FLASH_LED_0) {
- rc = qpnp_led_masked_write(led,
- led->current_addr,
- FLASH_CURRENT_MASK, val);
- if (rc) {
- dev_err(&led->pdev->dev,
- "current reg write failed\n");
- goto exit_flash_led_work;
- }
- } else {
- rc = qpnp_led_masked_write(led,
- led->current2_addr,
- FLASH_CURRENT_MASK, val);
- if (rc) {
- dev_err(&led->pdev->dev,
- "current reg write failed\n");
- goto exit_flash_led_work;
- }
- }
- }
-
- rc = qpnp_led_masked_write(led,
- FLASH_MAX_CURRENT(led->base),
- FLASH_CURRENT_MASK, FLASH_TORCH_MAX_LEVEL);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Max current reg write failed\n");
- goto exit_flash_led_work;
- }
-
- rc = qpnp_led_masked_write(led,
- FLASH_MODULE_ENABLE_CTRL(led->base),
- FLASH_MODULE_ENABLE_MASK, FLASH_MODULE_ENABLE);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Module enable reg write failed\n");
- goto exit_flash_led_work;
- }
-
- if (led->pdata->hdrm_sns_ch0_en ||
- led->pdata->hdrm_sns_ch1_en) {
- if (flash_node->id == FLASH_LED_SWITCH) {
- rc = qpnp_led_masked_write(led,
- FLASH_HDRM_SNS_ENABLE_CTRL0(led->base),
- FLASH_LED_HDRM_SNS_ENABLE_MASK,
- flash_node->trigger &
- FLASH_LED0_TRIGGER ?
- FLASH_LED_HDRM_SNS_ENABLE :
- FLASH_LED_HDRM_SNS_DISABLE);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Headroom sense enable failed\n");
- goto exit_flash_led_work;
- }
-
- rc = qpnp_led_masked_write(led,
- FLASH_HDRM_SNS_ENABLE_CTRL1(led->base),
- FLASH_LED_HDRM_SNS_ENABLE_MASK,
- flash_node->trigger &
- FLASH_LED1_TRIGGER ?
- FLASH_LED_HDRM_SNS_ENABLE :
- FLASH_LED_HDRM_SNS_DISABLE);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Headroom sense enable failed\n");
- goto exit_flash_led_work;
- }
- } else if (flash_node->id == FLASH_LED_0) {
- rc = qpnp_led_masked_write(led,
- FLASH_HDRM_SNS_ENABLE_CTRL0(led->base),
- FLASH_LED_HDRM_SNS_ENABLE_MASK,
- FLASH_LED_HDRM_SNS_ENABLE);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Headroom sense disable failed\n");
- goto exit_flash_led_work;
- }
- } else if (flash_node->id == FLASH_LED_1) {
- rc = qpnp_led_masked_write(led,
- FLASH_HDRM_SNS_ENABLE_CTRL1(led->base),
- FLASH_LED_HDRM_SNS_ENABLE_MASK,
- FLASH_LED_HDRM_SNS_ENABLE);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Headroom sense disable failed\n");
- goto exit_flash_led_work;
- }
- }
- }
-
- rc = qpnp_led_masked_write(led,
- FLASH_LED_STROBE_CTRL(led->base),
- (flash_node->id == FLASH_LED_SWITCH ? FLASH_STROBE_MASK
- | FLASH_LED_STROBE_TYPE_HW
- : flash_node->trigger |
- FLASH_LED_STROBE_TYPE_HW),
- flash_node->trigger);
- if (rc) {
- dev_err(&led->pdev->dev, "Strobe reg write failed\n");
- goto exit_flash_led_work;
- }
- } else if (flash_node->type == FLASH) {
- if (flash_node->trigger & FLASH_LED0_TRIGGER)
- max_curr_avail_ma += flash_node->max_current;
- if (flash_node->trigger & FLASH_LED1_TRIGGER)
- max_curr_avail_ma += flash_node->max_current;
-
- psy_prop.intval = true;
- rc = power_supply_set_property(led->battery_psy,
- POWER_SUPPLY_PROP_FLASH_ACTIVE,
- &psy_prop);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Failed to setup OTG pulse skip enable\n");
- goto exit_flash_led_work;
- }
-
- if (led->pdata->power_detect_en ||
- led->pdata->die_current_derate_en) {
- if (led->battery_psy) {
- power_supply_get_property(led->battery_psy,
- POWER_SUPPLY_PROP_STATUS,
- &psy_prop);
- if (psy_prop.intval < 0) {
- dev_err(&led->pdev->dev,
- "Invalid battery status\n");
- goto exit_flash_led_work;
- }
-
- if (psy_prop.intval ==
- POWER_SUPPLY_STATUS_CHARGING)
- led->charging_enabled = true;
- else if (psy_prop.intval ==
- POWER_SUPPLY_STATUS_DISCHARGING
- || psy_prop.intval ==
- POWER_SUPPLY_STATUS_NOT_CHARGING)
- led->charging_enabled = false;
- }
- max_curr_avail_ma =
- qpnp_flash_led_get_max_avail_current
- (flash_node, led);
- if (max_curr_avail_ma < 0) {
- dev_err(&led->pdev->dev,
- "Failed to get max avail curr\n");
- goto exit_flash_led_work;
- }
- }
-
- if (flash_node->id == FLASH_LED_SWITCH) {
- if (flash_node->trigger & FLASH_LED0_TRIGGER)
- total_curr_ma += flash_node->prgm_current;
- if (flash_node->trigger & FLASH_LED1_TRIGGER)
- total_curr_ma += flash_node->prgm_current2;
-
- if (max_curr_avail_ma < total_curr_ma) {
- flash_node->prgm_current =
- (flash_node->prgm_current *
- max_curr_avail_ma) / total_curr_ma;
- flash_node->prgm_current2 =
- (flash_node->prgm_current2 *
- max_curr_avail_ma) / total_curr_ma;
- }
-
- val = (u8)(flash_node->prgm_current *
- FLASH_MAX_LEVEL / flash_node->max_current);
- rc = qpnp_led_masked_write(led,
- led->current_addr, FLASH_CURRENT_MASK, val);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Current register write failed\n");
- goto exit_flash_led_work;
- }
-
- val = (u8)(flash_node->prgm_current2 *
- FLASH_MAX_LEVEL / flash_node->max_current);
- rc = qpnp_led_masked_write(led,
- led->current2_addr, FLASH_CURRENT_MASK, val);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Current register write failed\n");
- goto exit_flash_led_work;
- }
- } else {
- if (max_curr_avail_ma < flash_node->prgm_current) {
- dev_err(&led->pdev->dev,
- "battery only supprots %d mA\n",
- max_curr_avail_ma);
- flash_node->prgm_current =
- (u16)max_curr_avail_ma;
- }
-
- val = (u8)(flash_node->prgm_current *
- FLASH_MAX_LEVEL
- / flash_node->max_current);
- if (flash_node->id == FLASH_LED_0) {
- rc = qpnp_led_masked_write(
- led,
- led->current_addr,
- FLASH_CURRENT_MASK, val);
- if (rc) {
- dev_err(&led->pdev->dev,
- "current reg write failed\n");
- goto exit_flash_led_work;
- }
- } else if (flash_node->id == FLASH_LED_1) {
- rc = qpnp_led_masked_write(
- led,
- led->current2_addr,
- FLASH_CURRENT_MASK, val);
- if (rc) {
- dev_err(&led->pdev->dev,
- "current reg write failed\n");
- goto exit_flash_led_work;
- }
- }
- }
-
- val = (u8)((flash_node->duration - FLASH_DURATION_DIVIDER)
- / FLASH_DURATION_DIVIDER);
- rc = qpnp_led_masked_write(led,
- FLASH_SAFETY_TIMER(led->base),
- FLASH_SAFETY_TIMER_MASK, val);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Safety timer reg write failed\n");
- goto exit_flash_led_work;
- }
-
- rc = qpnp_led_masked_write(led,
- FLASH_MAX_CURRENT(led->base),
- FLASH_CURRENT_MASK, FLASH_MAX_LEVEL);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Max current reg write failed\n");
- goto exit_flash_led_work;
- }
-
- if (!led->charging_enabled) {
- rc = qpnp_led_masked_write(led,
- FLASH_MODULE_ENABLE_CTRL(led->base),
- FLASH_MODULE_ENABLE, FLASH_MODULE_ENABLE);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Module enable reg write failed\n");
- goto exit_flash_led_work;
- }
-
- usleep_range(FLASH_RAMP_UP_DELAY_US_MIN,
- FLASH_RAMP_UP_DELAY_US_MAX);
- }
-
- if (led->revid_data->pmic_subtype == PMI8996_SUBTYPE &&
- !led->revid_data->rev3) {
- rc = power_supply_set_property(led->battery_psy,
- POWER_SUPPLY_PROP_FLASH_TRIGGER,
- &psy_prop);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Failed to disable charger i/p curr limit\n");
- goto exit_flash_led_work;
- }
- }
-
- if (led->pdata->hdrm_sns_ch0_en ||
- led->pdata->hdrm_sns_ch1_en) {
- if (flash_node->id == FLASH_LED_SWITCH) {
- rc = qpnp_led_masked_write(led,
- FLASH_HDRM_SNS_ENABLE_CTRL0(led->base),
- FLASH_LED_HDRM_SNS_ENABLE_MASK,
- (flash_node->trigger &
- FLASH_LED0_TRIGGER ?
- FLASH_LED_HDRM_SNS_ENABLE :
- FLASH_LED_HDRM_SNS_DISABLE));
- if (rc) {
- dev_err(&led->pdev->dev,
- "Headroom sense enable failed\n");
- goto exit_flash_led_work;
- }
-
- rc = qpnp_led_masked_write(led,
- FLASH_HDRM_SNS_ENABLE_CTRL1(led->base),
- FLASH_LED_HDRM_SNS_ENABLE_MASK,
- (flash_node->trigger &
- FLASH_LED1_TRIGGER ?
- FLASH_LED_HDRM_SNS_ENABLE :
- FLASH_LED_HDRM_SNS_DISABLE));
- if (rc) {
- dev_err(&led->pdev->dev,
- "Headroom sense enable failed\n");
- goto exit_flash_led_work;
- }
- } else if (flash_node->id == FLASH_LED_0) {
- rc = qpnp_led_masked_write(led,
- FLASH_HDRM_SNS_ENABLE_CTRL0(led->base),
- FLASH_LED_HDRM_SNS_ENABLE_MASK,
- FLASH_LED_HDRM_SNS_ENABLE);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Headroom sense disable failed\n");
- goto exit_flash_led_work;
- }
- } else if (flash_node->id == FLASH_LED_1) {
- rc = qpnp_led_masked_write(led,
- FLASH_HDRM_SNS_ENABLE_CTRL1(led->base),
- FLASH_LED_HDRM_SNS_ENABLE_MASK,
- FLASH_LED_HDRM_SNS_ENABLE);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Headroom sense disable failed\n");
- goto exit_flash_led_work;
- }
- }
- }
-
- rc = qpnp_led_masked_write(led,
- FLASH_LED_STROBE_CTRL(led->base),
- (flash_node->id == FLASH_LED_SWITCH ? FLASH_STROBE_MASK
- | FLASH_LED_STROBE_TYPE_HW
- : flash_node->trigger |
- FLASH_LED_STROBE_TYPE_HW),
- flash_node->trigger);
- if (rc) {
- dev_err(&led->pdev->dev, "Strobe reg write failed\n");
- goto exit_flash_led_work;
- }
-
- if (led->strobe_debug && led->dbg_feature_en) {
- udelay(2000);
- rc = regmap_read(led->regmap,
- FLASH_LED_FAULT_STATUS(led->base),
- &temp);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Unable to read from addr= %x, rc(%d)\n",
- FLASH_LED_FAULT_STATUS(led->base), rc);
- goto exit_flash_led_work;
- }
- led->fault_reg = temp;
- }
- } else {
- pr_err("Both Torch and Flash cannot be select at same time\n");
- for (i = 0; i < led->num_leds; i++)
- led->flash_node[i].flash_on = false;
- goto turn_off;
- }
-
- flash_node->flash_on = true;
- mutex_unlock(&led->flash_led_lock);
-
- return;
-
-turn_off:
- if (led->flash_node[led->num_leds - 1].id == FLASH_LED_SWITCH &&
- flash_node->id != FLASH_LED_SWITCH)
- led->flash_node[led->num_leds - 1].trigger &=
- ~(0x80 >> flash_node->id);
- if (flash_node->type == TORCH) {
- /*
- * Checking LED fault status detects hardware open fault.
- * If fault occurs, all subsequent LED enablement requests
- * will be rejected to protect hardware.
- */
- rc = regmap_read(led->regmap,
- FLASH_LED_FAULT_STATUS(led->base), &temp);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Failed to read out fault status register\n");
- goto exit_flash_led_work;
- }
-
- led->open_fault |= (val & FLASH_LED_OPEN_FAULT_DETECTED);
- }
-
- rc = qpnp_led_masked_write(led,
- FLASH_LED_STROBE_CTRL(led->base),
- (flash_node->id == FLASH_LED_SWITCH ? FLASH_STROBE_MASK
- | FLASH_LED_STROBE_TYPE_HW
- : flash_node->trigger
- | FLASH_LED_STROBE_TYPE_HW),
- FLASH_LED_DISABLE);
- if (rc) {
- dev_err(&led->pdev->dev, "Strobe disable failed\n");
- goto exit_flash_led_work;
- }
-
- usleep_range(FLASH_RAMP_DN_DELAY_US_MIN, FLASH_RAMP_DN_DELAY_US_MAX);
-exit_flash_hdrm_sns:
- if (led->pdata->hdrm_sns_ch0_en) {
- if (flash_node->id == FLASH_LED_0 ||
- flash_node->id == FLASH_LED_SWITCH) {
- rc = qpnp_led_masked_write(led,
- FLASH_HDRM_SNS_ENABLE_CTRL0(led->base),
- FLASH_LED_HDRM_SNS_ENABLE_MASK,
- FLASH_LED_HDRM_SNS_DISABLE);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Headroom sense disable failed\n");
- goto exit_flash_hdrm_sns;
- }
- }
- }
-
- if (led->pdata->hdrm_sns_ch1_en) {
- if (flash_node->id == FLASH_LED_1 ||
- flash_node->id == FLASH_LED_SWITCH) {
- rc = qpnp_led_masked_write(led,
- FLASH_HDRM_SNS_ENABLE_CTRL1(led->base),
- FLASH_LED_HDRM_SNS_ENABLE_MASK,
- FLASH_LED_HDRM_SNS_DISABLE);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Headroom sense disable failed\n");
- goto exit_flash_hdrm_sns;
- }
- }
- }
-exit_flash_led_work:
- rc = qpnp_flash_led_module_disable(led, flash_node);
- if (rc) {
- dev_err(&led->pdev->dev, "Module disable failed\n");
- goto exit_flash_led_work;
- }
-error_enable_gpio:
- if (flash_node->flash_on && flash_node->num_regulators > 0)
- flash_regulator_enable(led, flash_node, false);
-
- flash_node->flash_on = false;
- mutex_unlock(&led->flash_led_lock);
-}
-
-static void qpnp_flash_led_brightness_set(struct led_classdev *led_cdev,
- enum led_brightness value)
-{
- struct flash_node_data *flash_node;
- struct qpnp_flash_led *led;
-
- flash_node = container_of(led_cdev, struct flash_node_data, cdev);
- led = dev_get_drvdata(&flash_node->pdev->dev);
-
- if (value < LED_OFF) {
- pr_err("Invalid brightness value\n");
- return;
- }
-
- if (value > flash_node->cdev.max_brightness)
- value = flash_node->cdev.max_brightness;
-
- flash_node->cdev.brightness = value;
- if (led->flash_node[led->num_leds - 1].id ==
- FLASH_LED_SWITCH) {
- if (flash_node->type == TORCH)
- led->flash_node[led->num_leds - 1].type = TORCH;
- else if (flash_node->type == FLASH)
- led->flash_node[led->num_leds - 1].type = FLASH;
-
- led->flash_node[led->num_leds - 1].max_current
- = flash_node->max_current;
-
- if (flash_node->id == FLASH_LED_0 ||
- flash_node->id == FLASH_LED_1) {
- if (value < FLASH_LED_MIN_CURRENT_MA && value != 0)
- value = FLASH_LED_MIN_CURRENT_MA;
-
- flash_node->prgm_current = value;
- flash_node->flash_on = value ? true : false;
- } else if (flash_node->id == FLASH_LED_SWITCH) {
- if (!value) {
- flash_node->prgm_current = 0;
- flash_node->prgm_current2 = 0;
- }
- }
- } else {
- if (value < FLASH_LED_MIN_CURRENT_MA && value != 0)
- value = FLASH_LED_MIN_CURRENT_MA;
- flash_node->prgm_current = value;
- }
-
- queue_work(led->ordered_workq, &flash_node->work);
-}
-
-static int qpnp_flash_led_init_settings(struct qpnp_flash_led *led)
-{
- int rc;
- u8 val, temp_val;
- uint val_int;
-
- rc = qpnp_led_masked_write(led,
- FLASH_MODULE_ENABLE_CTRL(led->base),
- FLASH_MODULE_ENABLE_MASK,
- FLASH_LED_MODULE_CTRL_DEFAULT);
- if (rc) {
- dev_err(&led->pdev->dev, "Module disable failed\n");
- return rc;
- }
-
- rc = qpnp_led_masked_write(led,
- FLASH_LED_STROBE_CTRL(led->base),
- FLASH_STROBE_MASK, FLASH_LED_DISABLE);
- if (rc) {
- dev_err(&led->pdev->dev, "Strobe disable failed\n");
- return rc;
- }
-
- rc = qpnp_led_masked_write(led,
- FLASH_LED_TMR_CTRL(led->base),
- FLASH_TMR_MASK, FLASH_TMR_SAFETY);
- if (rc) {
- dev_err(&led->pdev->dev,
- "LED timer ctrl reg write failed(%d)\n", rc);
- return rc;
- }
-
- val = (u8)(led->pdata->headroom / FLASH_LED_HEADROOM_DIVIDER -
- FLASH_LED_HEADROOM_OFFSET);
- rc = qpnp_led_masked_write(led,
- FLASH_HEADROOM(led->base),
- FLASH_HEADROOM_MASK, val);
- if (rc) {
- dev_err(&led->pdev->dev, "Headroom reg write failed\n");
- return rc;
- }
-
- val = qpnp_flash_led_get_startup_dly(led->pdata->startup_dly);
-
- rc = qpnp_led_masked_write(led,
- FLASH_STARTUP_DELAY(led->base),
- FLASH_STARTUP_DLY_MASK, val);
- if (rc) {
- dev_err(&led->pdev->dev, "Startup delay reg write failed\n");
- return rc;
- }
-
- val = (u8)(led->pdata->clamp_current * FLASH_MAX_LEVEL /
- FLASH_LED_MAX_CURRENT_MA);
- rc = qpnp_led_masked_write(led,
- FLASH_CLAMP_CURRENT(led->base),
- FLASH_CURRENT_MASK, val);
- if (rc) {
- dev_err(&led->pdev->dev, "Clamp current reg write failed\n");
- return rc;
- }
-
- if (led->pdata->pmic_charger_support)
- val = FLASH_LED_FLASH_HW_VREG_OK;
- else
- val = FLASH_LED_FLASH_SW_VREG_OK;
- rc = qpnp_led_masked_write(led,
- FLASH_VREG_OK_FORCE(led->base),
- FLASH_VREG_OK_FORCE_MASK, val);
- if (rc) {
- dev_err(&led->pdev->dev, "VREG OK force reg write failed\n");
- return rc;
- }
-
- if (led->pdata->self_check_en)
- val = FLASH_MODULE_ENABLE;
- else
- val = FLASH_LED_DISABLE;
- rc = qpnp_led_masked_write(led,
- FLASH_FAULT_DETECT(led->base),
- FLASH_FAULT_DETECT_MASK, val);
- if (rc) {
- dev_err(&led->pdev->dev, "Fault detect reg write failed\n");
- return rc;
- }
-
- val = 0x0;
- val |= led->pdata->mask3_en << FLASH_LED_MASK3_ENABLE_SHIFT;
- val |= FLASH_LED_MASK_MODULE_MASK2_ENABLE;
- rc = qpnp_led_masked_write(led, FLASH_MASK_ENABLE(led->base),
- FLASH_MASK_MODULE_CONTRL_MASK, val);
- if (rc) {
- dev_err(&led->pdev->dev, "Mask module enable failed\n");
- return rc;
- }
-
- rc = regmap_read(led->regmap, FLASH_PERPH_RESET_CTRL(led->base),
- &val_int);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Unable to read from address %x, rc(%d)\n",
- FLASH_PERPH_RESET_CTRL(led->base), rc);
- return -EINVAL;
- }
- val = (u8)val_int;
-
- if (led->pdata->follow_rb_disable) {
- rc = qpnp_led_masked_write(led,
- FLASH_LED_UNLOCK_SECURE(led->base),
- FLASH_SECURE_MASK, FLASH_UNLOCK_SECURE);
- if (rc) {
- dev_err(&led->pdev->dev, "Secure reg write failed\n");
- return -EINVAL;
- }
-
- val |= FLASH_FOLLOW_OTST2_RB_MASK;
- rc = qpnp_led_masked_write(led,
- FLASH_PERPH_RESET_CTRL(led->base),
- FLASH_FOLLOW_OTST2_RB_MASK, val);
- if (rc) {
- dev_err(&led->pdev->dev,
- "failed to reset OTST2_RB bit\n");
- return rc;
- }
- } else {
- rc = qpnp_led_masked_write(led,
- FLASH_LED_UNLOCK_SECURE(led->base),
- FLASH_SECURE_MASK, FLASH_UNLOCK_SECURE);
- if (rc) {
- dev_err(&led->pdev->dev, "Secure reg write failed\n");
- return -EINVAL;
- }
-
- val &= ~FLASH_FOLLOW_OTST2_RB_MASK;
- rc = qpnp_led_masked_write(led,
- FLASH_PERPH_RESET_CTRL(led->base),
- FLASH_FOLLOW_OTST2_RB_MASK, val);
- if (rc) {
- dev_err(&led->pdev->dev,
- "failed to reset OTST2_RB bit\n");
- return rc;
- }
- }
-
- if (!led->pdata->thermal_derate_en)
- val = 0x0;
- else {
- val = led->pdata->thermal_derate_en << 7;
- val |= led->pdata->thermal_derate_rate << 3;
- val |= (led->pdata->thermal_derate_threshold -
- FLASH_LED_THERMAL_THRESHOLD_MIN) /
- FLASH_LED_THERMAL_DEVIDER;
- }
- rc = qpnp_led_masked_write(led,
- FLASH_THERMAL_DRATE(led->base),
- FLASH_THERMAL_DERATE_MASK, val);
- if (rc) {
- dev_err(&led->pdev->dev, "Thermal derate reg write failed\n");
- return rc;
- }
-
- if (!led->pdata->current_ramp_en)
- val = 0x0;
- else {
- val = led->pdata->current_ramp_en << 7;
- val |= led->pdata->ramp_up_step << 3;
- val |= led->pdata->ramp_dn_step;
- }
- rc = qpnp_led_masked_write(led,
- FLASH_CURRENT_RAMP(led->base),
- FLASH_CURRENT_RAMP_MASK, val);
- if (rc) {
- dev_err(&led->pdev->dev, "Current ramp reg write failed\n");
- return rc;
- }
-
- if (!led->pdata->vph_pwr_droop_en)
- val = 0x0;
- else {
- val = led->pdata->vph_pwr_droop_en << 7;
- val |= ((led->pdata->vph_pwr_droop_threshold -
- FLASH_LED_VPH_DROOP_THRESHOLD_MIN_MV) /
- FLASH_LED_VPH_DROOP_THRESHOLD_DIVIDER) << 4;
- temp_val =
- qpnp_flash_led_get_droop_debounce_time(
- led->pdata->vph_pwr_droop_debounce_time);
- if (temp_val == 0xFF) {
- dev_err(&led->pdev->dev, "Invalid debounce time\n");
- return temp_val;
- }
-
- val |= temp_val;
- }
- rc = qpnp_led_masked_write(led,
- FLASH_VPH_PWR_DROOP(led->base),
- FLASH_VPH_PWR_DROOP_MASK, val);
- if (rc) {
- dev_err(&led->pdev->dev, "VPH PWR droop reg write failed\n");
- return rc;
- }
-
- led->battery_psy = power_supply_get_by_name("battery");
- if (!led->battery_psy) {
- dev_err(&led->pdev->dev,
- "Failed to get battery power supply\n");
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led,
- struct flash_node_data *flash_node)
-{
- const char *temp_string;
- struct device_node *node = flash_node->cdev.dev->of_node;
- struct device_node *temp = NULL;
- int rc = 0, num_regs = 0;
- u32 val;
-
- rc = of_property_read_string(node, "label", &temp_string);
- if (!rc) {
- if (strcmp(temp_string, "flash") == 0)
- flash_node->type = FLASH;
- else if (strcmp(temp_string, "torch") == 0)
- flash_node->type = TORCH;
- else if (strcmp(temp_string, "switch") == 0)
- flash_node->type = SWITCH;
- else {
- dev_err(&led->pdev->dev, "Wrong flash LED type\n");
- return -EINVAL;
- }
- } else if (rc < 0) {
- dev_err(&led->pdev->dev, "Unable to read flash type\n");
- return rc;
- }
-
- rc = of_property_read_u32(node, "qcom,current", &val);
- if (!rc) {
- if (val < FLASH_LED_MIN_CURRENT_MA)
- val = FLASH_LED_MIN_CURRENT_MA;
- flash_node->prgm_current = val;
- } else if (rc != -EINVAL) {
- dev_err(&led->pdev->dev, "Unable to read current\n");
- return rc;
- }
-
- rc = of_property_read_u32(node, "qcom,id", &val);
- if (!rc)
- flash_node->id = (u8)val;
- else if (rc != -EINVAL) {
- dev_err(&led->pdev->dev, "Unable to read led ID\n");
- return rc;
- }
-
- if (flash_node->type == SWITCH || flash_node->type == FLASH) {
- rc = of_property_read_u32(node, "qcom,duration", &val);
- if (!rc)
- flash_node->duration = (u16)val;
- else if (rc != -EINVAL) {
- dev_err(&led->pdev->dev, "Unable to read duration\n");
- return rc;
- }
- }
-
- switch (led->peripheral_type) {
- case FLASH_SUBTYPE_SINGLE:
- flash_node->trigger = FLASH_LED0_TRIGGER;
- break;
- case FLASH_SUBTYPE_DUAL:
- if (flash_node->id == FLASH_LED_0)
- flash_node->trigger = FLASH_LED0_TRIGGER;
- else if (flash_node->id == FLASH_LED_1)
- flash_node->trigger = FLASH_LED1_TRIGGER;
- break;
- default:
- dev_err(&led->pdev->dev, "Invalid peripheral type\n");
- }
-
- while ((temp = of_get_next_child(node, temp))) {
- if (of_find_property(temp, "regulator-name", NULL))
- num_regs++;
- }
-
- if (num_regs)
- flash_node->num_regulators = num_regs;
-
- return rc;
-}
-
-static int qpnp_flash_led_parse_common_dt(
- struct qpnp_flash_led *led,
- struct device_node *node)
-{
- int rc;
- u32 val, temp_val;
- const char *temp;
-
- led->pdata->headroom = FLASH_LED_HEADROOM_DEFAULT_MV;
- rc = of_property_read_u32(node, "qcom,headroom", &val);
- if (!rc)
- led->pdata->headroom = (u16)val;
- else if (rc != -EINVAL) {
- dev_err(&led->pdev->dev, "Unable to read headroom\n");
- return rc;
- }
-
- led->pdata->startup_dly = FLASH_LED_STARTUP_DELAY_DEFAULT_US;
- rc = of_property_read_u32(node, "qcom,startup-dly", &val);
- if (!rc)
- led->pdata->startup_dly = (u8)val;
- else if (rc != -EINVAL) {
- dev_err(&led->pdev->dev, "Unable to read startup delay\n");
- return rc;
- }
-
- led->pdata->clamp_current = FLASH_LED_CLAMP_CURRENT_DEFAULT_MA;
- rc = of_property_read_u32(node, "qcom,clamp-current", &val);
- if (!rc) {
- if (val < FLASH_LED_MIN_CURRENT_MA)
- val = FLASH_LED_MIN_CURRENT_MA;
- led->pdata->clamp_current = (u16)val;
- } else if (rc != -EINVAL) {
- dev_err(&led->pdev->dev, "Unable to read clamp current\n");
- return rc;
- }
-
- led->pdata->pmic_charger_support =
- of_property_read_bool(node,
- "qcom,pmic-charger-support");
-
- led->pdata->self_check_en =
- of_property_read_bool(node, "qcom,self-check-enabled");
-
- led->pdata->thermal_derate_en =
- of_property_read_bool(node,
- "qcom,thermal-derate-enabled");
-
- if (led->pdata->thermal_derate_en) {
- led->pdata->thermal_derate_rate =
- FLASH_LED_THERMAL_DERATE_RATE_DEFAULT_PERCENT;
- rc = of_property_read_string(node, "qcom,thermal-derate-rate",
- &temp);
- if (!rc) {
- temp_val =
- qpnp_flash_led_get_thermal_derate_rate(temp);
- if (temp_val < 0) {
- dev_err(&led->pdev->dev,
- "Invalid thermal derate rate\n");
- return -EINVAL;
- }
-
- led->pdata->thermal_derate_rate = (u8)temp_val;
- } else {
- dev_err(&led->pdev->dev,
- "Unable to read thermal derate rate\n");
- return -EINVAL;
- }
-
- led->pdata->thermal_derate_threshold =
- FLASH_LED_THERMAL_DERATE_THRESHOLD_DEFAULT_C;
- rc = of_property_read_u32(node, "qcom,thermal-derate-threshold",
- &val);
- if (!rc)
- led->pdata->thermal_derate_threshold = (u8)val;
- else if (rc != -EINVAL) {
- dev_err(&led->pdev->dev,
- "Unable to read thermal derate threshold\n");
- return rc;
- }
- }
-
- led->pdata->current_ramp_en =
- of_property_read_bool(node,
- "qcom,current-ramp-enabled");
- if (led->pdata->current_ramp_en) {
- led->pdata->ramp_up_step = FLASH_LED_RAMP_UP_STEP_DEFAULT_US;
- rc = of_property_read_string(node, "qcom,ramp_up_step", &temp);
- if (!rc) {
- temp_val = qpnp_flash_led_get_ramp_step(temp);
- if (temp_val < 0) {
- dev_err(&led->pdev->dev,
- "Invalid ramp up step values\n");
- return -EINVAL;
- }
- led->pdata->ramp_up_step = (u8)temp_val;
- } else if (rc != -EINVAL) {
- dev_err(&led->pdev->dev,
- "Unable to read ramp up steps\n");
- return rc;
- }
-
- led->pdata->ramp_dn_step = FLASH_LED_RAMP_DN_STEP_DEFAULT_US;
- rc = of_property_read_string(node, "qcom,ramp_dn_step", &temp);
- if (!rc) {
- temp_val = qpnp_flash_led_get_ramp_step(temp);
- if (temp_val < 0) {
- dev_err(&led->pdev->dev,
- "Invalid ramp down step values\n");
- return rc;
- }
- led->pdata->ramp_dn_step = (u8)temp_val;
- } else if (rc != -EINVAL) {
- dev_err(&led->pdev->dev,
- "Unable to read ramp down steps\n");
- return rc;
- }
- }
-
- led->pdata->vph_pwr_droop_en = of_property_read_bool(node,
- "qcom,vph-pwr-droop-enabled");
- if (led->pdata->vph_pwr_droop_en) {
- led->pdata->vph_pwr_droop_threshold =
- FLASH_LED_VPH_PWR_DROOP_THRESHOLD_DEFAULT_MV;
- rc = of_property_read_u32(node,
- "qcom,vph-pwr-droop-threshold", &val);
- if (!rc) {
- led->pdata->vph_pwr_droop_threshold = (u16)val;
- } else if (rc != -EINVAL) {
- dev_err(&led->pdev->dev,
- "Unable to read VPH PWR droop threshold\n");
- return rc;
- }
-
- led->pdata->vph_pwr_droop_debounce_time =
- FLASH_LED_VPH_PWR_DROOP_DEBOUNCE_TIME_DEFAULT_US;
- rc = of_property_read_u32(node,
- "qcom,vph-pwr-droop-debounce-time", &val);
- if (!rc)
- led->pdata->vph_pwr_droop_debounce_time = (u8)val;
- else if (rc != -EINVAL) {
- dev_err(&led->pdev->dev,
- "Unable to read VPH PWR droop debounce time\n");
- return rc;
- }
- }
-
- led->pdata->hdrm_sns_ch0_en = of_property_read_bool(node,
- "qcom,headroom-sense-ch0-enabled");
-
- led->pdata->hdrm_sns_ch1_en = of_property_read_bool(node,
- "qcom,headroom-sense-ch1-enabled");
-
- led->pdata->power_detect_en = of_property_read_bool(node,
- "qcom,power-detect-enabled");
-
- led->pdata->mask3_en = of_property_read_bool(node,
- "qcom,otst2-module-enabled");
-
- led->pdata->follow_rb_disable = of_property_read_bool(node,
- "qcom,follow-otst2-rb-disabled");
-
- led->pdata->die_current_derate_en = of_property_read_bool(node,
- "qcom,die-current-derate-enabled");
-
- if (led->pdata->die_current_derate_en) {
- led->vadc_dev = qpnp_get_vadc(&led->pdev->dev, "die-temp");
- if (IS_ERR(led->vadc_dev)) {
- pr_err("VADC channel property Missing\n");
- return -EINVAL;
- }
-
- if (of_find_property(node, "qcom,die-temp-threshold",
- &led->pdata->temp_threshold_num)) {
- if (led->pdata->temp_threshold_num > 0) {
- led->pdata->die_temp_threshold_degc =
- devm_kzalloc(&led->pdev->dev,
- led->pdata->temp_threshold_num,
- GFP_KERNEL);
-
- if (led->pdata->die_temp_threshold_degc
- == NULL) {
- dev_err(&led->pdev->dev,
- "failed to allocate die temp array\n");
- return -ENOMEM;
- }
- led->pdata->temp_threshold_num /=
- sizeof(unsigned int);
-
- rc = of_property_read_u32_array(node,
- "qcom,die-temp-threshold",
- led->pdata->die_temp_threshold_degc,
- led->pdata->temp_threshold_num);
- if (rc) {
- dev_err(&led->pdev->dev,
- "couldn't read temp threshold rc=%d\n",
- rc);
- return rc;
- }
- }
- }
-
- if (of_find_property(node, "qcom,die-temp-derate-current",
- &led->pdata->temp_derate_curr_num)) {
- if (led->pdata->temp_derate_curr_num > 0) {
- led->pdata->die_temp_derate_curr_ma =
- devm_kzalloc(&led->pdev->dev,
- led->pdata->temp_derate_curr_num,
- GFP_KERNEL);
- if (led->pdata->die_temp_derate_curr_ma
- == NULL) {
- dev_err(&led->pdev->dev,
- "failed to allocate die derate current array\n");
- return -ENOMEM;
- }
- led->pdata->temp_derate_curr_num /=
- sizeof(unsigned int);
-
- rc = of_property_read_u32_array(node,
- "qcom,die-temp-derate-current",
- led->pdata->die_temp_derate_curr_ma,
- led->pdata->temp_derate_curr_num);
- if (rc) {
- dev_err(&led->pdev->dev,
- "couldn't read temp limits rc =%d\n",
- rc);
- return rc;
- }
- }
- }
- if (led->pdata->temp_threshold_num !=
- led->pdata->temp_derate_curr_num) {
- pr_err("Both array size are not same\n");
- return -EINVAL;
- }
- }
-
- led->pinctrl = devm_pinctrl_get(&led->pdev->dev);
- if (IS_ERR_OR_NULL(led->pinctrl)) {
- dev_err(&led->pdev->dev, "Unable to acquire pinctrl\n");
- led->pinctrl = NULL;
- return 0;
- }
-
- led->gpio_state_active = pinctrl_lookup_state(led->pinctrl,
- "flash_led_enable");
- if (IS_ERR_OR_NULL(led->gpio_state_active)) {
- dev_err(&led->pdev->dev, "Cannot lookup LED active state\n");
- devm_pinctrl_put(led->pinctrl);
- led->pinctrl = NULL;
- return PTR_ERR(led->gpio_state_active);
- }
-
- led->gpio_state_suspend = pinctrl_lookup_state(led->pinctrl,
- "flash_led_disable");
- if (IS_ERR_OR_NULL(led->gpio_state_suspend)) {
- dev_err(&led->pdev->dev, "Cannot lookup LED disable state\n");
- devm_pinctrl_put(led->pinctrl);
- led->pinctrl = NULL;
- return PTR_ERR(led->gpio_state_suspend);
- }
-
- return 0;
-}
-
-static int qpnp_flash_led_probe(struct platform_device *pdev)
-{
- struct qpnp_flash_led *led;
- unsigned int base;
- struct device_node *node, *temp;
- struct dentry *root, *file;
- int rc, i = 0, j, num_leds = 0;
- u32 val;
-
- root = NULL;
- node = pdev->dev.of_node;
- if (node == NULL) {
- dev_info(&pdev->dev, "No flash device defined\n");
- return -ENODEV;
- }
-
- rc = of_property_read_u32(pdev->dev.of_node, "reg", &base);
- if (rc < 0) {
- dev_err(&pdev->dev,
- "Couldn't find reg in node = %s rc = %d\n",
- pdev->dev.of_node->full_name, rc);
- return rc;
- }
-
- led = devm_kzalloc(&pdev->dev, sizeof(*led), GFP_KERNEL);
- if (!led)
- return -ENOMEM;
-
- led->regmap = dev_get_regmap(pdev->dev.parent, NULL);
- if (!led->regmap) {
- dev_err(&pdev->dev, "Couldn't get parent's regmap\n");
- return -EINVAL;
- }
-
- led->base = base;
- led->pdev = pdev;
- led->current_addr = FLASH_LED0_CURRENT(led->base);
- led->current2_addr = FLASH_LED1_CURRENT(led->base);
-
- led->pdata = devm_kzalloc(&pdev->dev, sizeof(*led->pdata), GFP_KERNEL);
- if (!led->pdata)
- return -ENOMEM;
-
- led->peripheral_type = (u8)qpnp_flash_led_get_peripheral_type(led);
- if (led->peripheral_type < 0) {
- dev_err(&pdev->dev, "Failed to get peripheral type\n");
- return rc;
- }
-
- rc = qpnp_flash_led_parse_common_dt(led, node);
- if (rc) {
- dev_err(&pdev->dev,
- "Failed to get common config for flash LEDs\n");
- return rc;
- }
-
- rc = qpnp_flash_led_init_settings(led);
- if (rc) {
- dev_err(&pdev->dev, "Failed to initialize flash LED\n");
- return rc;
- }
-
- rc = qpnp_get_pmic_revid(led);
- if (rc)
- return rc;
-
- temp = NULL;
- while ((temp = of_get_next_child(node, temp)))
- num_leds++;
-
- if (!num_leds)
- return -ECHILD;
-
- led->flash_node = devm_kzalloc(&pdev->dev,
- (sizeof(struct flash_node_data) * num_leds),
- GFP_KERNEL);
- if (!led->flash_node) {
- dev_err(&pdev->dev, "Unable to allocate memory\n");
- return -ENOMEM;
- }
-
- mutex_init(&led->flash_led_lock);
-
- led->ordered_workq = alloc_ordered_workqueue("flash_led_workqueue", 0);
- if (!led->ordered_workq) {
- dev_err(&pdev->dev, "Failed to allocate ordered workqueue\n");
- return -ENOMEM;
- }
-
- for_each_child_of_node(node, temp) {
- led->flash_node[i].cdev.brightness_set =
- qpnp_flash_led_brightness_set;
- led->flash_node[i].cdev.brightness_get =
- qpnp_flash_led_brightness_get;
- led->flash_node[i].pdev = pdev;
-
- INIT_WORK(&led->flash_node[i].work, qpnp_flash_led_work);
- rc = of_property_read_string(temp, "qcom,led-name",
- &led->flash_node[i].cdev.name);
- if (rc < 0) {
- dev_err(&led->pdev->dev,
- "Unable to read flash name\n");
- return rc;
- }
-
- rc = of_property_read_string(temp, "qcom,default-led-trigger",
- &led->flash_node[i].cdev.default_trigger);
- if (rc < 0) {
- dev_err(&led->pdev->dev,
- "Unable to read trigger name\n");
- return rc;
- }
-
- rc = of_property_read_u32(temp, "qcom,max-current", &val);
- if (!rc) {
- if (val < FLASH_LED_MIN_CURRENT_MA)
- val = FLASH_LED_MIN_CURRENT_MA;
- led->flash_node[i].max_current = (u16)val;
- led->flash_node[i].cdev.max_brightness = val;
- } else {
- dev_err(&led->pdev->dev,
- "Unable to read max current\n");
- return rc;
- }
- rc = led_classdev_register(&pdev->dev,
- &led->flash_node[i].cdev);
- if (rc) {
- dev_err(&pdev->dev, "Unable to register led\n");
- goto error_led_register;
- }
-
- led->flash_node[i].cdev.dev->of_node = temp;
-
- rc = qpnp_flash_led_parse_each_led_dt(led, &led->flash_node[i]);
- if (rc) {
- dev_err(&pdev->dev,
- "Failed to parse config for each LED\n");
- goto error_led_register;
- }
-
- if (led->flash_node[i].num_regulators) {
- rc = flash_regulator_parse_dt(led, &led->flash_node[i]);
- if (rc) {
- dev_err(&pdev->dev,
- "Unable to parse regulator data\n");
- goto error_led_register;
- }
-
- rc = flash_regulator_setup(led, &led->flash_node[i],
- true);
- if (rc) {
- dev_err(&pdev->dev,
- "Unable to set up regulator\n");
- goto error_led_register;
- }
- }
-
- for (j = 0; j < ARRAY_SIZE(qpnp_flash_led_attrs); j++) {
- rc =
- sysfs_create_file(&led->flash_node[i].cdev.dev->kobj,
- &qpnp_flash_led_attrs[j].attr);
- if (rc)
- goto error_led_register;
- }
-
- i++;
- }
-
- led->num_leds = i;
-
- root = debugfs_create_dir("flashLED", NULL);
- if (IS_ERR_OR_NULL(root)) {
- pr_err("Error creating top level directory err%ld",
- (long)root);
- if (PTR_ERR(root) == -ENODEV)
- pr_err("debugfs is not enabled in kernel");
- goto error_led_debugfs;
- }
-
- led->dbgfs_root = root;
- file = debugfs_create_file("enable_debug", 0600, root, led,
- &flash_led_dfs_dbg_feature_fops);
- if (!file) {
- pr_err("error creating 'enable_debug' entry\n");
- goto error_led_debugfs;
- }
-
- file = debugfs_create_file("latched", 0600, root, led,
- &flash_led_dfs_latched_reg_fops);
- if (!file) {
- pr_err("error creating 'latched' entry\n");
- goto error_led_debugfs;
- }
-
- file = debugfs_create_file("strobe", 0600, root, led,
- &flash_led_dfs_strobe_reg_fops);
- if (!file) {
- pr_err("error creating 'strobe' entry\n");
- goto error_led_debugfs;
- }
-
- dev_set_drvdata(&pdev->dev, led);
-
- return 0;
-
-error_led_debugfs:
- i = led->num_leds - 1;
- j = ARRAY_SIZE(qpnp_flash_led_attrs) - 1;
-error_led_register:
- for (; i >= 0; i--) {
- for (; j >= 0; j--)
- sysfs_remove_file(&led->flash_node[i].cdev.dev->kobj,
- &qpnp_flash_led_attrs[j].attr);
- j = ARRAY_SIZE(qpnp_flash_led_attrs) - 1;
- led_classdev_unregister(&led->flash_node[i].cdev);
- }
- debugfs_remove_recursive(root);
- mutex_destroy(&led->flash_led_lock);
- destroy_workqueue(led->ordered_workq);
-
- return rc;
-}
-
-static int qpnp_flash_led_remove(struct platform_device *pdev)
-{
- struct qpnp_flash_led *led = dev_get_drvdata(&pdev->dev);
- int i, j;
-
- for (i = led->num_leds - 1; i >= 0; i--) {
- if (led->flash_node[i].reg_data) {
- if (led->flash_node[i].flash_on)
- flash_regulator_enable(led,
- &led->flash_node[i], false);
- flash_regulator_setup(led, &led->flash_node[i],
- false);
- }
- for (j = 0; j < ARRAY_SIZE(qpnp_flash_led_attrs); j++)
- sysfs_remove_file(&led->flash_node[i].cdev.dev->kobj,
- &qpnp_flash_led_attrs[j].attr);
- led_classdev_unregister(&led->flash_node[i].cdev);
- }
- debugfs_remove_recursive(led->dbgfs_root);
- mutex_destroy(&led->flash_led_lock);
- destroy_workqueue(led->ordered_workq);
-
- return 0;
-}
-
-static const struct of_device_id spmi_match_table[] = {
- { .compatible = "qcom,qpnp-flash-led",},
- { },
-};
-
-static struct platform_driver qpnp_flash_led_driver = {
- .driver = {
- .name = "qcom,qpnp-flash-led",
- .of_match_table = spmi_match_table,
- },
- .probe = qpnp_flash_led_probe,
- .remove = qpnp_flash_led_remove,
-};
-
-static int __init qpnp_flash_led_init(void)
-{
- return platform_driver_register(&qpnp_flash_led_driver);
-}
-late_initcall(qpnp_flash_led_init);
-
-static void __exit qpnp_flash_led_exit(void)
-{
- platform_driver_unregister(&qpnp_flash_led_driver);
-}
-module_exit(qpnp_flash_led_exit);
-
-MODULE_DESCRIPTION("QPNP Flash LED driver");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("leds:leds-qpnp-flash");
diff --git a/drivers/leds/leds-qpnp-wled.c b/drivers/leds/leds-qpnp-wled.c
index cb19cef..568c9f9 100644
--- a/drivers/leds/leds-qpnp-wled.c
+++ b/drivers/leds/leds-qpnp-wled.c
@@ -160,18 +160,19 @@
#define QPNP_WLED_MOD_EN_SHFT 7
#define QPNP_WLED_MOD_EN 1
#define QPNP_WLED_GATE_DRV_MASK 0xFE
-#define QPNP_WLED_SYNC_DLY_MASK 0xF8
+#define QPNP_WLED_SYNC_DLY_MASK GENMASK(2, 0)
#define QPNP_WLED_SYNC_DLY_MIN_US 0
#define QPNP_WLED_SYNC_DLY_MAX_US 1400
#define QPNP_WLED_SYNC_DLY_STEP_US 200
#define QPNP_WLED_DEF_SYNC_DLY_US 400
-#define QPNP_WLED_FS_CURR_MASK 0xF0
+#define QPNP_WLED_FS_CURR_MASK GENMASK(3, 0)
#define QPNP_WLED_FS_CURR_MIN_UA 0
#define QPNP_WLED_FS_CURR_MAX_UA 30000
#define QPNP_WLED_FS_CURR_STEP_UA 2500
-#define QPNP_WLED_CABC_MASK 0x7F
+#define QPNP_WLED_CABC_MASK 0x80
#define QPNP_WLED_CABC_SHIFT 7
#define QPNP_WLED_CURR_SINK_SHIFT 4
+#define QPNP_WLED_CURR_SINK_MASK GENMASK(7, 4)
#define QPNP_WLED_BRIGHT_LSB_MASK 0xFF
#define QPNP_WLED_BRIGHT_MSB_SHIFT 8
#define QPNP_WLED_BRIGHT_MSB_MASK 0x0F
@@ -208,12 +209,14 @@
#define QPNP_WLED_SEC_UNLOCK 0xA5
#define QPNP_WLED_MAX_STRINGS 4
+#define QPNP_PM660_WLED_MAX_STRINGS 3
#define WLED_MAX_LEVEL_4095 4095
#define QPNP_WLED_RAMP_DLY_MS 20
#define QPNP_WLED_TRIGGER_NONE "none"
#define QPNP_WLED_STR_SIZE 20
#define QPNP_WLED_MIN_MSLEEP 20
#define QPNP_WLED_SC_DLY_MS 20
+#define QPNP_WLED_SOFT_START_DLY_US 10000
#define NUM_SUPPORTED_AVDD_VOLTAGES 6
#define QPNP_WLED_DFLT_AVDD_MV 7600
@@ -381,6 +384,8 @@
u16 ramp_ms;
u16 ramp_step;
u16 cons_sync_write_delay_us;
+ u16 auto_calibration_ovp_count;
+ u16 max_strings;
u8 strings[QPNP_WLED_MAX_STRINGS];
u8 num_strings;
u8 loop_auto_gm_thresh;
@@ -396,6 +401,9 @@
bool en_ext_pfet_sc_pro;
bool prev_state;
bool ovp_irq_disabled;
+ bool auto_calib_enabled;
+ bool auto_calib_done;
+ ktime_t start_ovp_fault_time;
};
/* helper to read a pmic register */
@@ -529,9 +537,14 @@
{
int i, rc;
u8 reg;
+ u16 low_limit = WLED_MAX_LEVEL_4095 * 4 / 1000;
+
+ /* WLED's lower limit of operation is 0.4% */
+ if (level > 0 && level < low_limit)
+ level = low_limit;
/* set brightness registers */
- for (i = 0; i < wled->num_strings; i++) {
+ for (i = 0; i < wled->max_strings; i++) {
reg = level & QPNP_WLED_BRIGHT_LSB_MASK;
rc = qpnp_wled_write_reg(wled,
QPNP_WLED_BRIGHT_LSB_REG(wled->sink_base,
@@ -600,7 +613,8 @@
* OVP interrupt disabled when the module is disabled.
*/
if (state) {
- usleep_range(10000, 11000);
+ usleep_range(QPNP_WLED_SOFT_START_DLY_US,
+ QPNP_WLED_SOFT_START_DLY_US + 1000);
rc = qpnp_wled_psm_config(wled, false);
if (rc < 0)
return rc;
@@ -873,32 +887,25 @@
struct device_attribute *attr, const char *buf, size_t count)
{
struct qpnp_wled *wled = dev_get_drvdata(dev);
- int data, i, rc, temp;
+ int data, i, rc;
u8 reg;
rc = kstrtoint(buf, 10, &data);
if (rc)
return rc;
- for (i = 0; i < wled->num_strings; i++) {
+ for (i = 0; i < wled->max_strings; i++) {
if (data < QPNP_WLED_FS_CURR_MIN_UA)
data = QPNP_WLED_FS_CURR_MIN_UA;
else if (data > QPNP_WLED_FS_CURR_MAX_UA)
data = QPNP_WLED_FS_CURR_MAX_UA;
- rc = qpnp_wled_read_reg(wled,
- QPNP_WLED_FS_CURR_REG(wled->sink_base,
- wled->strings[i]), ®);
+ reg = data / QPNP_WLED_FS_CURR_STEP_UA;
+ rc = qpnp_wled_masked_write_reg(wled,
+ QPNP_WLED_FS_CURR_REG(wled->sink_base, i),
+ QPNP_WLED_FS_CURR_MASK, reg);
if (rc < 0)
return rc;
- reg &= QPNP_WLED_FS_CURR_MASK;
- temp = data / QPNP_WLED_FS_CURR_STEP_UA;
- reg |= temp;
- rc = qpnp_wled_write_reg(wled,
- QPNP_WLED_FS_CURR_REG(wled->sink_base,
- wled->strings[i]), reg);
- if (rc)
- return rc;
}
wled->fs_curr_ua = data;
@@ -1090,6 +1097,229 @@
return 0;
}
+#define AUTO_CALIB_BRIGHTNESS 16
+static int wled_auto_calibrate(struct qpnp_wled *wled)
+{
+ int rc = 0, i;
+ u8 reg = 0, sink_config = 0, sink_test = 0, sink_valid = 0, int_sts;
+
+ mutex_lock(&wled->lock);
+
+ /* disable OVP IRQ */
+ if (wled->ovp_irq > 0 && !wled->ovp_irq_disabled) {
+ disable_irq_nosync(wled->ovp_irq);
+ wled->ovp_irq_disabled = true;
+ }
+
+ /* read configured sink configuration */
+ rc = qpnp_wled_read_reg(wled,
+ QPNP_WLED_CURR_SINK_REG(wled->sink_base), &sink_config);
+ if (rc < 0) {
+ pr_err("Failed to read SINK configuration rc=%d\n", rc);
+ goto failed_calib;
+ }
+
+ /* disable the module before starting calibration */
+ rc = qpnp_wled_masked_write_reg(wled,
+ QPNP_WLED_MODULE_EN_REG(wled->ctrl_base),
+ QPNP_WLED_MODULE_EN_MASK, 0);
+ if (rc < 0) {
+ pr_err("Failed to disable WLED module rc=%d\n", rc);
+ goto failed_calib;
+ }
+
+ /* set low brightness across all sinks */
+ rc = qpnp_wled_set_level(wled, AUTO_CALIB_BRIGHTNESS);
+ if (rc < 0) {
+ pr_err("Failed to set brightness for calibration rc=%d\n", rc);
+ goto failed_calib;
+ }
+
+ /* disable all sinks */
+ rc = qpnp_wled_write_reg(wled,
+ QPNP_WLED_CURR_SINK_REG(wled->sink_base), 0);
+ if (rc < 0) {
+ pr_err("Failed to disable all sinks rc=%d\n", rc);
+ goto failed_calib;
+ }
+
+ rc = qpnp_wled_masked_write_reg(wled,
+ QPNP_WLED_MODULE_EN_REG(wled->ctrl_base),
+ QPNP_WLED_MODULE_EN_MASK,
+ QPNP_WLED_MODULE_EN_MASK);
+ if (rc < 0) {
+ pr_err("Failed to enable WLED module rc=%d\n", rc);
+ goto failed_calib;
+ }
+ /*
+ * Delay for the WLED soft-start, check the OVP status
+ * only after soft-start is complete
+ */
+ usleep_range(QPNP_WLED_SOFT_START_DLY_US,
+ QPNP_WLED_SOFT_START_DLY_US + 1000);
+
+ /* iterate through the strings one by one */
+ for (i = 0; i < wled->max_strings; i++) {
+ sink_test = 1 << (QPNP_WLED_CURR_SINK_SHIFT + i);
+
+ /* Enable feedback control */
+ rc = qpnp_wled_write_reg(wled,
+ QPNP_WLED_FDBK_OP_REG(wled->ctrl_base),
+ i + 1);
+ if (rc < 0) {
+ pr_err("Failed to enable feedback for SINK %d rc = %d\n",
+ i + 1, rc);
+ goto failed_calib;
+ }
+
+ /* enable the sink */
+ rc = qpnp_wled_write_reg(wled,
+ QPNP_WLED_CURR_SINK_REG(wled->sink_base), sink_test);
+ if (rc < 0) {
+ pr_err("Failed to configure SINK %d rc=%d\n",
+ i + 1, rc);
+ goto failed_calib;
+ }
+
+ /* delay for WLED soft-start */
+ usleep_range(QPNP_WLED_SOFT_START_DLY_US,
+ QPNP_WLED_SOFT_START_DLY_US + 1000);
+
+ rc = qpnp_wled_read_reg(wled,
+ QPNP_WLED_INT_RT_STS(wled->ctrl_base), &int_sts);
+ if (rc < 0) {
+ pr_err("Error in reading WLED_INT_RT_STS rc=%d\n", rc);
+ goto failed_calib;
+ }
+
+ if (int_sts & QPNP_WLED_OVP_FAULT_BIT)
+ pr_debug("WLED OVP fault detected with SINK %d\n",
+ i + 1);
+ else
+ sink_valid |= sink_test;
+ }
+
+ if (sink_valid == sink_config) {
+ pr_debug("WLED auto-calibration complete, default sink-config=%x OK!\n",
+ sink_config);
+ } else {
+ pr_warn("Invalid WLED default sink config=%x changing it to=%x\n",
+ sink_config, sink_valid);
+ sink_config = sink_valid;
+ }
+
+ if (!sink_config) {
+ pr_warn("No valid WLED sinks found\n");
+ goto failed_calib;
+ }
+
+ rc = qpnp_wled_masked_write_reg(wled,
+ QPNP_WLED_MODULE_EN_REG(wled->ctrl_base),
+ QPNP_WLED_MODULE_EN_MASK, 0);
+ if (rc < 0) {
+ pr_err("Failed to disable WLED module rc=%d\n", rc);
+ goto failed_calib;
+ }
+
+ /* write the new sink configuration */
+ rc = qpnp_wled_write_reg(wled,
+ QPNP_WLED_CURR_SINK_REG(wled->sink_base), sink_config);
+ if (rc < 0) {
+ pr_err("Failed to reconfigure the default sink rc=%d\n", rc);
+ goto failed_calib;
+ }
+
+ /* MODULATOR_EN setting for valid sinks */
+ for (i = 0; i < wled->max_strings; i++) {
+ if (sink_config & (1 << (QPNP_WLED_CURR_SINK_SHIFT + i)))
+ reg = (QPNP_WLED_MOD_EN << QPNP_WLED_MOD_EN_SHFT);
+ else
+ reg = 0x0; /* disable modulator_en for unused sink */
+
+ if (wled->dim_mode == QPNP_WLED_DIM_HYBRID)
+ reg &= QPNP_WLED_GATE_DRV_MASK;
+ else
+ reg |= ~QPNP_WLED_GATE_DRV_MASK;
+
+ rc = qpnp_wled_write_reg(wled,
+ QPNP_WLED_MOD_EN_REG(wled->sink_base, i), reg);
+ if (rc < 0) {
+ pr_err("Failed to configure MODULATOR_EN rc=%d\n", rc);
+ goto failed_calib;
+ }
+ }
+
+ /* restore the feedback setting */
+ rc = qpnp_wled_write_reg(wled,
+ QPNP_WLED_FDBK_OP_REG(wled->ctrl_base),
+ wled->fdbk_op);
+ if (rc < 0) {
+ pr_err("Failed to restore feedback setting rc=%d\n", rc);
+ goto failed_calib;
+ }
+
+ /* restore brightness */
+ rc = qpnp_wled_set_level(wled, wled->cdev.brightness);
+ if (rc < 0) {
+ pr_err("Failed to set brightness after calibration rc=%d\n",
+ rc);
+ goto failed_calib;
+ }
+
+ rc = qpnp_wled_masked_write_reg(wled,
+ QPNP_WLED_MODULE_EN_REG(wled->ctrl_base),
+ QPNP_WLED_MODULE_EN_MASK,
+ QPNP_WLED_MODULE_EN_MASK);
+ if (rc < 0) {
+ pr_err("Failed to enable WLED module rc=%d\n", rc);
+ goto failed_calib;
+ }
+
+ /* delay for WLED soft-start */
+ usleep_range(QPNP_WLED_SOFT_START_DLY_US,
+ QPNP_WLED_SOFT_START_DLY_US + 1000);
+
+failed_calib:
+ if (wled->ovp_irq > 0 && wled->ovp_irq_disabled) {
+ enable_irq(wled->ovp_irq);
+ wled->ovp_irq_disabled = false;
+ }
+ mutex_unlock(&wled->lock);
+ return rc;
+}
+
+#define WLED_AUTO_CAL_OVP_COUNT 5
+#define WLED_AUTO_CAL_CNT_DLY_US 1000000 /* 1 second */
+static bool qpnp_wled_auto_cal_required(struct qpnp_wled *wled)
+{
+ s64 elapsed_time_us;
+
+ /*
+ * Check if the OVP fault was an occasional one
+ * or if its firing continuously, the latter qualifies
+ * for an auto-calibration check.
+ */
+ if (!wled->auto_calibration_ovp_count) {
+ wled->start_ovp_fault_time = ktime_get();
+ wled->auto_calibration_ovp_count++;
+ } else {
+ elapsed_time_us = ktime_us_delta(ktime_get(),
+ wled->start_ovp_fault_time);
+ if (elapsed_time_us > WLED_AUTO_CAL_CNT_DLY_US)
+ wled->auto_calibration_ovp_count = 0;
+ else
+ wled->auto_calibration_ovp_count++;
+
+ if (wled->auto_calibration_ovp_count >=
+ WLED_AUTO_CAL_OVP_COUNT) {
+ wled->auto_calibration_ovp_count = 0;
+ return true;
+ }
+ }
+
+ return false;
+}
+
/* ovp irq handler */
static irqreturn_t qpnp_wled_ovp_irq_handler(int irq, void *_wled)
{
@@ -1114,6 +1344,21 @@
if (fault_sts & (QPNP_WLED_OVP_FAULT_BIT | QPNP_WLED_ILIM_FAULT_BIT))
pr_err("WLED OVP fault detected, int_sts=%x fault_sts= %x\n",
int_sts, fault_sts);
+
+ if (fault_sts & QPNP_WLED_OVP_FAULT_BIT) {
+ if (wled->auto_calib_enabled && !wled->auto_calib_done) {
+ if (qpnp_wled_auto_cal_required(wled)) {
+ rc = wled_auto_calibrate(wled);
+ if (rc < 0) {
+ pr_err("Failed auto-calibration rc=%d\n",
+ rc);
+ return IRQ_HANDLED;
+ }
+ wled->auto_calib_done = true;
+ }
+ }
+ }
+
return IRQ_HANDLED;
}
@@ -1423,7 +1668,7 @@
static int qpnp_wled_config(struct qpnp_wled *wled)
{
int rc, i, temp;
- u8 reg = 0;
+ u8 reg = 0, sink_en = 0, mask;
/* Configure display type */
rc = qpnp_wled_set_disp(wled, wled->ctrl_base);
@@ -1622,16 +1867,50 @@
rc = qpnp_wled_write_reg(wled, QPNP_WLED_CURR_SINK_REG(wled->sink_base),
reg);
+ for (i = 0; i < wled->max_strings; i++) {
+ /* SYNC DELAY */
+ if (wled->sync_dly_us > QPNP_WLED_SYNC_DLY_MAX_US)
+ wled->sync_dly_us = QPNP_WLED_SYNC_DLY_MAX_US;
+
+ reg = wled->sync_dly_us / QPNP_WLED_SYNC_DLY_STEP_US;
+ mask = QPNP_WLED_SYNC_DLY_MASK;
+ rc = qpnp_wled_masked_write_reg(wled,
+ QPNP_WLED_SYNC_DLY_REG(wled->sink_base, i),
+ mask, reg);
+ if (rc < 0)
+ return rc;
+
+ /* FULL SCALE CURRENT */
+ if (wled->fs_curr_ua > QPNP_WLED_FS_CURR_MAX_UA)
+ wled->fs_curr_ua = QPNP_WLED_FS_CURR_MAX_UA;
+
+ reg = wled->fs_curr_ua / QPNP_WLED_FS_CURR_STEP_UA;
+ mask = QPNP_WLED_FS_CURR_MASK;
+ rc = qpnp_wled_masked_write_reg(wled,
+ QPNP_WLED_FS_CURR_REG(wled->sink_base, i),
+ mask, reg);
+ if (rc < 0)
+ return rc;
+
+ /* CABC */
+ reg = wled->en_cabc ? (1 << QPNP_WLED_CABC_SHIFT) : 0;
+ mask = QPNP_WLED_CABC_MASK;
+ rc = qpnp_wled_masked_write_reg(wled,
+ QPNP_WLED_CABC_REG(wled->sink_base, i),
+ mask, reg);
+ if (rc < 0)
+ return rc;
+ }
+
+ /* Settings specific to valid sinks */
for (i = 0; i < wled->num_strings; i++) {
- if (wled->strings[i] >= QPNP_WLED_MAX_STRINGS) {
+ if (wled->strings[i] >= wled->max_strings) {
dev_err(&wled->pdev->dev, "Invalid string number\n");
return -EINVAL;
}
-
/* MODULATOR */
rc = qpnp_wled_read_reg(wled,
- QPNP_WLED_MOD_EN_REG(wled->sink_base,
- wled->strings[i]), ®);
+ QPNP_WLED_MOD_EN_REG(wled->sink_base, i), ®);
if (rc < 0)
return rc;
reg &= QPNP_WLED_MOD_EN_MASK;
@@ -1643,72 +1922,22 @@
reg |= ~QPNP_WLED_GATE_DRV_MASK;
rc = qpnp_wled_write_reg(wled,
- QPNP_WLED_MOD_EN_REG(wled->sink_base,
- wled->strings[i]), reg);
+ QPNP_WLED_MOD_EN_REG(wled->sink_base, i), reg);
if (rc)
return rc;
- /* SYNC DELAY */
- if (wled->sync_dly_us > QPNP_WLED_SYNC_DLY_MAX_US)
- wled->sync_dly_us = QPNP_WLED_SYNC_DLY_MAX_US;
-
- rc = qpnp_wled_read_reg(wled,
- QPNP_WLED_SYNC_DLY_REG(wled->sink_base,
- wled->strings[i]), ®);
- if (rc < 0)
- return rc;
- reg &= QPNP_WLED_SYNC_DLY_MASK;
- temp = wled->sync_dly_us / QPNP_WLED_SYNC_DLY_STEP_US;
- reg |= temp;
- rc = qpnp_wled_write_reg(wled,
- QPNP_WLED_SYNC_DLY_REG(wled->sink_base,
- wled->strings[i]), reg);
- if (rc)
- return rc;
-
- /* FULL SCALE CURRENT */
- if (wled->fs_curr_ua > QPNP_WLED_FS_CURR_MAX_UA)
- wled->fs_curr_ua = QPNP_WLED_FS_CURR_MAX_UA;
-
- rc = qpnp_wled_read_reg(wled,
- QPNP_WLED_FS_CURR_REG(wled->sink_base,
- wled->strings[i]), ®);
- if (rc < 0)
- return rc;
- reg &= QPNP_WLED_FS_CURR_MASK;
- temp = wled->fs_curr_ua / QPNP_WLED_FS_CURR_STEP_UA;
- reg |= temp;
- rc = qpnp_wled_write_reg(wled,
- QPNP_WLED_FS_CURR_REG(wled->sink_base,
- wled->strings[i]), reg);
- if (rc)
- return rc;
-
- /* CABC */
- rc = qpnp_wled_read_reg(wled,
- QPNP_WLED_CABC_REG(wled->sink_base,
- wled->strings[i]), ®);
- if (rc < 0)
- return rc;
- reg &= QPNP_WLED_CABC_MASK;
- reg |= (wled->en_cabc << QPNP_WLED_CABC_SHIFT);
- rc = qpnp_wled_write_reg(wled,
- QPNP_WLED_CABC_REG(wled->sink_base,
- wled->strings[i]), reg);
- if (rc)
- return rc;
-
- /* Enable CURRENT SINK */
- rc = qpnp_wled_read_reg(wled,
- QPNP_WLED_CURR_SINK_REG(wled->sink_base), ®);
- if (rc < 0)
- return rc;
+ /* SINK EN */
temp = wled->strings[i] + QPNP_WLED_CURR_SINK_SHIFT;
- reg |= (1 << temp);
- rc = qpnp_wled_write_reg(wled,
- QPNP_WLED_CURR_SINK_REG(wled->sink_base), reg);
- if (rc)
- return rc;
+ sink_en |= (1 << temp);
+ }
+ mask = QPNP_WLED_CURR_SINK_MASK;
+ rc = qpnp_wled_masked_write_reg(wled,
+ QPNP_WLED_CURR_SINK_REG(wled->sink_base),
+ mask, sink_en);
+ if (rc < 0) {
+ dev_err(&wled->pdev->dev,
+ "Failed to enable WLED sink config rc = %d\n", rc);
+ return rc;
}
rc = qpnp_wled_sync_reg_toggle(wled);
@@ -1728,8 +1957,13 @@
wled->ovp_irq, rc);
return rc;
}
- disable_irq(wled->ovp_irq);
- wled->ovp_irq_disabled = true;
+ rc = qpnp_wled_read_reg(wled,
+ QPNP_WLED_MODULE_EN_REG(wled->ctrl_base), ®);
+ /* disable the OVP irq only if the module is not enabled */
+ if (!rc && !(reg & QPNP_WLED_MODULE_EN_MASK)) {
+ disable_irq(wled->ovp_irq);
+ wled->ovp_irq_disabled = true;
+ }
}
if (wled->sc_irq >= 0) {
@@ -2091,11 +2325,16 @@
wled->en_cabc = of_property_read_bool(pdev->dev.of_node,
"qcom,en-cabc");
+ if (wled->pmic_rev_id->pmic_subtype == PM660L_SUBTYPE)
+ wled->max_strings = QPNP_PM660_WLED_MAX_STRINGS;
+ else
+ wled->max_strings = QPNP_WLED_MAX_STRINGS;
+
prop = of_find_property(pdev->dev.of_node,
"qcom,led-strings-list", &temp_val);
if (!prop || !temp_val || temp_val > QPNP_WLED_MAX_STRINGS) {
dev_err(&pdev->dev, "Invalid strings info, use default");
- wled->num_strings = QPNP_WLED_MAX_STRINGS;
+ wled->num_strings = wled->max_strings;
for (i = 0; i < wled->num_strings; i++)
wled->strings[i] = i;
} else {
@@ -2118,6 +2357,9 @@
wled->lcd_psm_ctrl = of_property_read_bool(pdev->dev.of_node,
"qcom,lcd-psm-ctrl");
+
+ wled->auto_calib_enabled = of_property_read_bool(pdev->dev.of_node,
+ "qcom,auto-calibration-enable");
return 0;
}
@@ -2186,13 +2428,13 @@
}
mutex_init(&wled->bus_lock);
+ mutex_init(&wled->lock);
rc = qpnp_wled_config(wled);
if (rc) {
dev_err(&pdev->dev, "wled config failed\n");
return rc;
}
- mutex_init(&wled->lock);
INIT_WORK(&wled->work, qpnp_wled_work);
wled->ramp_ms = QPNP_WLED_RAMP_DLY_MS;
wled->ramp_step = 1;
diff --git a/drivers/mailbox/qti-tcs.c b/drivers/mailbox/qti-tcs.c
index c50fc0e..f923db5 100644
--- a/drivers/mailbox/qti-tcs.c
+++ b/drivers/mailbox/qti-tcs.c
@@ -11,12 +11,13 @@
*
*/
-#define pr_fmt(fmt) "%s:%s " fmt, KBUILD_MODNAME, __func__
+#define pr_fmt(fmt) "%s " fmt, KBUILD_MODNAME
#include <linux/atomic.h>
#include <linux/bitmap.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
+#include <linux/ipc_logging.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/list.h>
@@ -40,6 +41,8 @@
#define CREATE_TRACE_POINTS
#include <trace/events/rpmh.h>
+#define TCS_DRV_IPC_LOG_SIZE 2
+
#define MAX_CMDS_PER_TCS 16
#define MAX_TCS_PER_TYPE 3
#define MAX_TCS_SLOTS (MAX_CMDS_PER_TCS * MAX_TCS_PER_TYPE)
@@ -140,8 +143,35 @@
u64 tcs_last_recv_ts[MAX_POOL_SIZE];
atomic_t tcs_send_count[MAX_POOL_SIZE];
atomic_t tcs_irq_count[MAX_POOL_SIZE];
+ void *ipc_log_ctx;
};
+/* Log to IPC and Ftrace */
+#define log_send_msg(drv, m, n, i, a, d, c, t) do { \
+ trace_rpmh_send_msg(drv->name, m, n, i, a, d, c, t); \
+ ipc_log_string(drv->ipc_log_ctx, \
+ "send msg: m=%d n=%d msgid=0x%x addr=0x%x data=0x%x cmpl=%d trigger=%d", \
+ m, n, i, a, d, c, t); \
+ } while (0)
+
+#define log_rpmh_notify_irq(drv, m, a, e) do { \
+ trace_rpmh_notify_irq(drv->name, m, a, e); \
+ ipc_log_string(drv->ipc_log_ctx, \
+ "irq response: m=%d addr=0x%x err=%d", m, a, e); \
+ } while (0)
+
+#define log_rpmh_control_msg(drv, d) do { \
+ trace_rpmh_control_msg(drv->name, d); \
+ ipc_log_string(drv->ipc_log_ctx, "ctrlr msg: data=0x%x", d); \
+ } while (0)
+
+#define log_rpmh_notify(drv, m, a, e) do { \
+ trace_rpmh_notify(drv->name, m, a, e); \
+ ipc_log_string(drv->ipc_log_ctx, \
+ "tx done: m=%d addr=0x%x err=%d", m, a, e); \
+ } while (0)
+
+
static int tcs_response_pool_init(struct tcs_drv *drv)
{
struct tcs_response_pool *pool;
@@ -223,7 +253,6 @@
break;
}
pos++;
- udelay(1);
} while (1);
spin_unlock_irqrestore(&pool->lock, flags);
@@ -241,7 +270,7 @@
return;
msg = resp->msg;
- pr_warn("Response object idx=%d:\n\tfor-tcs=%d\tin-use=%d\n",
+ pr_warn("Response object [idx=%d for-tcs=%d in-use=%d]\n",
resp->idx, resp->m, resp->in_use);
pr_warn("Msg: state=%d\n", msg->state);
for (i = 0; i < msg->num_payload; i++)
@@ -425,8 +454,10 @@
sts = read_tcs_reg(base, TCS_DRV_CMD_STATUS, m, i);
if ((!(sts & CMD_STATUS_ISSUED)) ||
((resp->msg->is_complete || cmd->complete) &&
- (!(sts & CMD_STATUS_COMPL))))
+ (!(sts & CMD_STATUS_COMPL)))) {
resp->err = -EIO;
+ break;
+ }
}
/* Check for response if this was a read request */
@@ -437,13 +468,15 @@
mbox_chan_received_data(resp->chan, resp->msg);
}
- trace_rpmh_notify_irq(drv->name, m, resp->msg->payload[0].addr,
+ log_rpmh_notify_irq(drv, m, resp->msg->payload[0].addr,
resp->err);
/* Clear the AMC mode for non-ACTIVE TCSes */
tcs = get_tcs_from_index(drv, m);
if (tcs && tcs->type != ACTIVE_TCS) {
data = read_tcs_reg(base, TCS_DRV_CONTROL, m, 0);
+ data &= ~TCS_AMC_MODE_TRIGGER;
+ write_tcs_reg_sync(base, TCS_DRV_CONTROL, m, 0, data);
data &= ~TCS_AMC_MODE_ENABLE;
write_tcs_reg(base, TCS_DRV_CONTROL, m, 0, data);
/*
@@ -480,7 +513,7 @@
{
struct tcs_drv *drv = container_of(chan->mbox, struct tcs_drv, mbox);
- trace_rpmh_notify(drv->name, m, msg->payload[0].addr, err);
+ log_rpmh_notify(drv, m, msg->payload[0].addr, err);
mbox_chan_txdone(chan, err);
}
@@ -524,7 +557,7 @@
u32 msgid, cmd_msgid = 0;
u32 cmd_enable = 0;
u32 cmd_complete;
- u32 enable = TCS_AMC_MODE_ENABLE;
+ u32 enable;
struct tcs_cmd *cmd;
int i;
void __iomem *base = drv->reg_base;
@@ -546,7 +579,7 @@
write_tcs_reg(base, TCS_DRV_CMD_MSGID, m, n + i, msgid);
write_tcs_reg(base, TCS_DRV_CMD_ADDR, m, n + i, cmd->addr);
write_tcs_reg(base, TCS_DRV_CMD_DATA, m, n + i, cmd->data);
- trace_rpmh_send_msg(drv->name, m, n + i, msgid, cmd->addr,
+ log_send_msg(drv, m, n + i, msgid, cmd->addr,
cmd->data, cmd->complete, trigger);
}
@@ -558,12 +591,22 @@
write_tcs_reg(base, TCS_DRV_CMD_ENABLE, m, 0, cmd_enable);
if (trigger) {
- /* HW req: Clear the DRV_CONTROL and enable TCS again */
- write_tcs_reg_sync(base, TCS_DRV_CONTROL, m, 0, 0);
+ /*
+ * HW req: Clear the DRV_CONTROL and enable TCS again
+ * While clearing ensure that the AMC mode trigger is cleared
+ * and then the mode enable is cleared.
+ */
+ enable = read_tcs_reg(base, TCS_DRV_CONTROL, m, 0);
+ enable &= ~TCS_AMC_MODE_TRIGGER;
write_tcs_reg_sync(base, TCS_DRV_CONTROL, m, 0, enable);
- /* Enable the AMC mode on the TCS */
+ enable &= ~TCS_AMC_MODE_ENABLE;
+ write_tcs_reg_sync(base, TCS_DRV_CONTROL, m, 0, enable);
+
+ /* Enable the AMC mode on the TCS and then trigger the TCS */
+ enable = TCS_AMC_MODE_ENABLE;
+ write_tcs_reg_sync(base, TCS_DRV_CONTROL, m, 0, enable);
enable |= TCS_AMC_MODE_TRIGGER;
- write_tcs_reg_sync(base, TCS_DRV_CONTROL, m, 0, enable);
+ write_tcs_reg(base, TCS_DRV_CONTROL, m, 0, enable);
}
}
@@ -667,7 +710,8 @@
int n = 0;
/* For active requests find the first free AMC. */
- if (tcs->type == ACTIVE_TCS)
+ if (msg->state == RPMH_ACTIVE_ONLY_STATE ||
+ msg->state == RPMH_AWAKE_STATE)
return find_free_tcs(tcs);
/* Find if we already have the msg in our TCS */
@@ -780,6 +824,10 @@
spin_lock_irqsave(&tcs->tcs_lock, flags);
for (i = 0; i < tcs->num_tcs; i++) {
m = i + tcs->tcs_offset;
+ if (!tcs_is_free(drv, m)) {
+ spin_unlock_irqrestore(&tcs->tcs_lock, flags);
+ return -EBUSY;
+ }
__tcs_buffer_invalidate(drv->reg_base, m);
}
/* Mark the TCS as free */
@@ -795,7 +843,7 @@
int n;
struct tcs_mbox *tcs = get_tcs_from_index(drv, m);
void __iomem *base = drv->reg_base;
- u32 enable, addr, data, msgid;
+ u32 enable, addr, data, msgid, sts, irq_sts;
if (!tcs || tcs_is_free(drv, m))
return;
@@ -804,15 +852,24 @@
if (!enable)
return;
- pr_warn("TCS-%d contents:\n", m);
+ pr_warn("RSC:%s\n", drv->name);
+
+ sts = read_tcs_reg(base, TCS_DRV_STATUS, m, 0);
+ data = read_tcs_reg(base, TCS_DRV_CONTROL, m, 0);
+ irq_sts = read_tcs_reg(base, TCS_DRV_IRQ_STATUS, 0, 0);
+ pr_warn("TCS=%d [ctrlr-sts:%s amc-mode:0x%x irq-sts:%s]\n",
+ m, sts ? "IDLE" : "BUSY", data,
+ (irq_sts & BIT(m)) ? "COMPLETED" : "PENDING");
+
for (n = 0; n < tcs->ncpt; n++) {
if (!(enable & BIT(n)))
continue;
addr = read_tcs_reg(base, TCS_DRV_CMD_ADDR, m, n);
data = read_tcs_reg(base, TCS_DRV_CMD_DATA, m, n);
msgid = read_tcs_reg(base, TCS_DRV_CMD_MSGID, m, n);
- pr_warn("\tn=%d addr=0x%x data=0x%x hdr=0x%x\n",
- n, addr, data, msgid);
+ sts = read_tcs_reg(base, TCS_DRV_CMD_STATUS, m, n);
+ pr_warn("\tCMD=%d [addr=0x%x data=0x%x hdr=0x%x sts=0x%x]\n",
+ n, addr, data, msgid, sts);
}
}
@@ -866,7 +923,8 @@
goto tx_fail;
}
- if (!msg->payload || msg->num_payload > MAX_RPMH_PAYLOAD) {
+ if (!msg->payload || !msg->num_payload ||
+ msg->num_payload > MAX_RPMH_PAYLOAD) {
dev_err(dev, "Payload error\n");
ret = -EINVAL;
goto tx_fail;
@@ -896,8 +954,11 @@
* Since we are re-purposing the wake TCS, invalidate previous
* contents to avoid confusion.
*/
- if (msg->state == RPMH_AWAKE_STATE)
- tcs_mbox_invalidate(chan);
+ if (msg->state == RPMH_AWAKE_STATE) {
+ ret = tcs_mbox_invalidate(chan);
+ if (ret)
+ goto tx_fail;
+ }
/* Post the message to the TCS and trigger */
ret = tcs_mbox_write(chan, msg, true);
@@ -909,8 +970,10 @@
drv, msg, chan, TCS_M_INIT, ret);
dev_err(dev, "Error sending RPMH message %d\n", ret);
- if (resp)
+ if (!IS_ERR(resp))
send_tcs_response(resp);
+ else
+ dev_err(dev, "No response object %ld\n", PTR_ERR(resp));
ret = 0;
}
@@ -932,7 +995,7 @@
for (i = 0; i < msg->num_payload; i++) {
/* Only data is write capable */
writel_relaxed(cpu_to_le32(msg->payload[i].data), addr);
- trace_rpmh_control_msg(drv->name, msg->payload[i].data);
+ log_rpmh_control_msg(drv, msg->payload[i].data);
addr += TCS_HIDDEN_CMD_SHIFT;
}
}
@@ -977,7 +1040,8 @@
goto tx_done;
}
- if (msg->num_payload > MAX_RPMH_PAYLOAD) {
+ if (!msg->payload || (!msg->num_payload && !msg->invalidate) ||
+ msg->num_payload > MAX_RPMH_PAYLOAD) {
dev_err(dev, "Payload error\n");
goto tx_done;
}
@@ -1117,7 +1181,8 @@
if (tcs->num_tcs > MAX_TCS_PER_TYPE)
return -EINVAL;
- if (st > max_tcs)
+ if (st + tcs->num_tcs > max_tcs &&
+ st + tcs->num_tcs >= sizeof(tcs->tcs_mask))
return -EINVAL;
tcs->tcs_mask = ((1 << tcs->num_tcs) - 1) << st;
@@ -1139,10 +1204,12 @@
for (j = 0; j < i; j++) {
ret = of_parse_phandle_with_args(np, "mboxes",
"#mbox-cells", j, &p);
- if (!ret && p.np == pdev->dev.of_node)
+ of_node_put(p.np);
+ if (!ret && p.np == pdev->dev.of_node) {
+ num_chans++;
break;
+ }
}
- num_chans++;
}
if (!num_chans) {
@@ -1200,6 +1267,9 @@
for (i = 0; i < ARRAY_SIZE(drv->tcs_in_use); i++)
atomic_set(&drv->tcs_in_use[i], 0);
+ drv->ipc_log_ctx = ipc_log_context_create(TCS_DRV_IPC_LOG_SIZE,
+ drv->name, 0);
+
ret = mbox_controller_register(&drv->mbox);
if (ret)
return ret;
diff --git a/drivers/md/dm-android-verity.c b/drivers/md/dm-android-verity.c
index 3b19017..eb4bdf6 100644
--- a/drivers/md/dm-android-verity.c
+++ b/drivers/md/dm-android-verity.c
@@ -646,6 +646,8 @@
android_verity_target.direct_access = dm_linear_direct_access,
android_verity_target.io_hints = NULL;
+ set_disk_ro(dm_disk(dm_table_get_md(ti->table)), 0);
+
err = dm_linear_ctr(ti, DM_LINEAR_ARGS, linear_table_args);
if (!err) {
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index ac8235b..0d437c9 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -431,7 +431,7 @@
unsigned long flags;
struct priority_group *pg;
struct pgpath *pgpath;
- bool bypassed = true;
+ unsigned bypassed = 1;
if (!atomic_read(&m->nr_valid_paths)) {
clear_bit(MPATHF_QUEUE_IO, &m->flags);
@@ -470,7 +470,7 @@
*/
do {
list_for_each_entry(pg, &m->priority_groups, list) {
- if (pg->bypassed == bypassed)
+ if (pg->bypassed == !!bypassed)
continue;
pgpath = choose_path_in_pg(m, pg, nr_bytes);
if (!IS_ERR_OR_NULL(pgpath)) {
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 29e2df5..81a7875 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1073,7 +1073,7 @@
*/
DEFINE_WAIT(w);
for (;;) {
- flush_signals(current);
+ sigset_t full, old;
prepare_to_wait(&conf->wait_barrier,
&w, TASK_INTERRUPTIBLE);
if (bio_end_sector(bio) <= mddev->suspend_lo ||
@@ -1082,7 +1082,10 @@
!md_cluster_ops->area_resyncing(mddev, WRITE,
bio->bi_iter.bi_sector, bio_end_sector(bio))))
break;
+ sigfillset(&full);
+ sigprocmask(SIG_BLOCK, &full, &old);
schedule();
+ sigprocmask(SIG_SETMASK, &old, NULL);
}
finish_wait(&conf->wait_barrier, &w);
}
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index f34ad2b..8f117d6 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -5300,12 +5300,15 @@
* userspace, we want an interruptible
* wait.
*/
- flush_signals(current);
prepare_to_wait(&conf->wait_for_overlap,
&w, TASK_INTERRUPTIBLE);
if (logical_sector >= mddev->suspend_lo &&
logical_sector < mddev->suspend_hi) {
+ sigset_t full, old;
+ sigfillset(&full);
+ sigprocmask(SIG_BLOCK, &full, &old);
schedule();
+ sigprocmask(SIG_SETMASK, &old, NULL);
do_prepare = true;
}
goto retry;
@@ -7557,12 +7560,10 @@
{
if (!test_bit(MD_RECOVERY_INTR, &conf->mddev->recovery)) {
- struct md_rdev *rdev;
spin_lock_irq(&conf->device_lock);
conf->previous_raid_disks = conf->raid_disks;
- rdev_for_each(rdev, conf->mddev)
- rdev->data_offset = rdev->new_data_offset;
+ md_finish_reshape(conf->mddev);
smp_wmb();
conf->reshape_progress = MaxSector;
conf->mddev->reshape_position = MaxSector;
diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c
index e868f92..f2d39a9 100644
--- a/drivers/media/dvb-core/dmxdev.c
+++ b/drivers/media/dvb-core/dmxdev.c
@@ -448,7 +448,7 @@
bytes_read = 0;
}
} else {
- if (bytes_read)
+ if (bytes_read) {
/*
* data was read beyond the non-data event,
* making it not relevant anymore
@@ -459,6 +459,7 @@
if (!(events->event_mask.no_wakeup_mask &
event->type))
events->wakeup_events_counter--;
+ }
}
events->read_index = events->notified_index;
diff --git a/drivers/media/pci/cx88/cx88-cards.c b/drivers/media/pci/cx88/cx88-cards.c
index 8f2556e..61611d1 100644
--- a/drivers/media/pci/cx88/cx88-cards.c
+++ b/drivers/media/pci/cx88/cx88-cards.c
@@ -3691,7 +3691,14 @@
core->nr = nr;
sprintf(core->name, "cx88[%d]", core->nr);
- core->tvnorm = V4L2_STD_NTSC_M;
+ /*
+ * Note: Setting initial standard here would cause first call to
+ * cx88_set_tvnorm() to return without programming any registers. Leave
+ * it blank for at this point and it will get set later in
+ * cx8800_initdev()
+ */
+ core->tvnorm = 0;
+
core->width = 320;
core->height = 240;
core->field = V4L2_FIELD_INTERLACED;
diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c
index d83eb3b..3b140ad 100644
--- a/drivers/media/pci/cx88/cx88-video.c
+++ b/drivers/media/pci/cx88/cx88-video.c
@@ -1422,7 +1422,7 @@
/* initial device configuration */
mutex_lock(&core->lock);
- cx88_set_tvnorm(core, core->tvnorm);
+ cx88_set_tvnorm(core, V4L2_STD_NTSC_M);
v4l2_ctrl_handler_setup(&core->video_hdl);
v4l2_ctrl_handler_setup(&core->audio_hdl);
cx88_video_mux(core, 0);
diff --git a/drivers/media/platform/msm/broadcast/tspp.c b/drivers/media/platform/msm/broadcast/tspp.c
index 7717759..2c90e47 100644
--- a/drivers/media/platform/msm/broadcast/tspp.c
+++ b/drivers/media/platform/msm/broadcast/tspp.c
@@ -24,6 +24,7 @@
#include <linux/uaccess.h> /* copy_to_user */
#include <linux/slab.h> /* kfree, kzalloc */
#include <linux/ioport.h> /* XXX_ mem_region */
+#include <asm/dma-iommu.h>
#include <linux/dma-mapping.h> /* dma_XXX */
#include <linux/dmapool.h> /* DMA pools */
#include <linux/delay.h> /* msleep */
@@ -46,6 +47,7 @@
#include <linux/msm-bus.h>
#include <linux/interrupt.h> /* tasklet */
#include <asm/arch_timer.h> /* Timer */
+#include <linux/dma-buf.h>
/*
* General defines
@@ -59,6 +61,10 @@
#define TSPP_NUM_KEYS 8
#define INVALID_CHANNEL 0xFFFFFFFF
#define TSPP_BAM_DEFAULT_IPC_LOGLVL 2
+
+#define TSPP_SMMU_IOVA_START (0x10000000)
+#define TSPP_SMMU_IOVA_SIZE (0x40000000)
+
/*
* BAM descriptor FIFO size (in number of descriptors).
* Max number of descriptors allowed by SPS which is 8K-1.
@@ -489,6 +495,7 @@
struct mutex mutex;
struct tspp_pinctrl pinctrl;
unsigned int tts_source; /* Time stamp source type LPASS timer/TCR */
+ struct dma_iommu_mapping *iommu_mapping;
struct dentry *dent;
struct dentry *debugfs_regs[ARRAY_SIZE(debugfs_tspp_regs)];
@@ -1058,6 +1065,35 @@
tspp_key_entry &= ~(1 << entry);
}
+static int tspp_iommu_init(struct tspp_device *device)
+{
+ struct dma_iommu_mapping *iommu_map;
+
+ iommu_map = arm_iommu_create_mapping(&platform_bus_type,
+ TSPP_SMMU_IOVA_START,
+ TSPP_SMMU_IOVA_SIZE);
+ if (IS_ERR(iommu_map)) {
+ dev_err(&device->pdev->dev, "iommu_create_mapping failure\n");
+ return PTR_ERR(iommu_map);
+ }
+ if (arm_iommu_attach_device(&device->pdev->dev, iommu_map)) {
+ dev_err(&device->pdev->dev, "can't arm_iommu_attach_device\n");
+ arm_iommu_release_mapping(iommu_map);
+ return -EIO;
+ }
+
+ device->iommu_mapping = iommu_map;
+ return 0;
+}
+
+static void tspp_iommu_release_iomapping(struct tspp_device *device)
+{
+ if (device->iommu_mapping)
+ arm_iommu_release_mapping(device->iommu_mapping);
+
+ device->iommu_mapping = NULL;
+}
+
static int tspp_alloc_buffer(u32 channel_id, struct tspp_data_descriptor *desc,
u32 size, struct dma_pool *dma_pool, tspp_allocator *alloc, void *user)
{
@@ -1070,7 +1106,7 @@
if (alloc) {
TSPP_DEBUG("tspp using alloc function");
desc->virt_base = alloc(channel_id, size,
- &desc->phys_base, user);
+ &desc->phys_base, &desc->dma_base, user);
} else {
if (!dma_pool)
desc->virt_base = dma_alloc_coherent(NULL, size,
@@ -2562,7 +2598,8 @@
desc->next = channel->data;
/* prepare the sps descriptor */
- desc->sps.phys_base = desc->desc.phys_base;
+ desc->sps.phys_base = ((alloc != NULL) ? desc->desc.dma_base :
+ desc->desc.phys_base);
desc->sps.base = desc->desc.virt_base;
desc->sps.size = desc->desc.size;
@@ -2600,6 +2637,121 @@
}
EXPORT_SYMBOL(tspp_allocate_buffers);
+/**
+ * tspp_attach_ion_dma_buff- attach ion dma buffer to TSPP device
+ * It will attach the DMA buffer to TSPP device to go through SMMU.
+ *
+ * @dev: TSPP device (up to TSPP_MAX_DEVICES)
+ * @ion_dma_buf: It contains required members for ION buffer dma mapping.
+ *
+ * Return error status
+ *
+ */
+int tspp_attach_ion_dma_buff(u32 dev, struct tspp_ion_dma_buf_info *ion_dma_buf)
+{
+ struct tspp_device *pdev;
+ int dir = DMA_FROM_DEVICE;
+ int ret = -1;
+
+ if (NULL == ion_dma_buf || NULL == ion_dma_buf->dbuf) {
+ pr_err("tspp: invalid input argument");
+ return -EINVAL;
+ }
+
+ if (dev >= TSPP_MAX_DEVICES) {
+ pr_err("tspp: device id out of range");
+ return -ENODEV;
+ }
+
+ pdev = tspp_find_by_id(dev);
+ if (!pdev) {
+ pr_err("tspp: can't find device %i", dev);
+ return -ENODEV;
+ }
+
+ ion_dma_buf->attach = dma_buf_attach(ion_dma_buf->dbuf,
+ &pdev->pdev->dev);
+ if (IS_ERR_OR_NULL(ion_dma_buf->attach)) {
+ dev_err(&pdev->pdev->dev, "%s: dma_buf_attach fail", __func__);
+ return -ENODEV;
+ }
+ ion_dma_buf->table = dma_buf_map_attachment(ion_dma_buf->attach, dir);
+ if (IS_ERR_OR_NULL(ion_dma_buf->table)) {
+ dev_err(&pdev->pdev->dev, "dma_buf_map_attachment fail");
+ dma_buf_detach(ion_dma_buf->dbuf, ion_dma_buf->attach);
+ return -ENODEV;
+ }
+ ret = dma_map_sg(&pdev->pdev->dev, ion_dma_buf->table->sgl,
+ ion_dma_buf->table->nents, dir);
+ if (ret <= 0) {
+ dev_err(&pdev->pdev->dev, "dma_map_sg failed! ret=%d\n", ret);
+ goto unmap_attachment;
+ }
+ if (ion_dma_buf->table->nents > 1) {
+ dev_err(&pdev->pdev->dev, "no of sg table entries %d > 1\n",
+ ion_dma_buf->table->nents);
+ goto unmap_attachment;
+ }
+
+ ion_dma_buf->dma_map_base = sg_dma_address(ion_dma_buf->table->sgl);
+ ion_dma_buf->smmu_map = true;
+ return 0;
+
+unmap_attachment:
+ dma_buf_unmap_attachment(ion_dma_buf->attach, ion_dma_buf->table, dir);
+ dma_buf_detach(ion_dma_buf->dbuf, ion_dma_buf->attach);
+ dma_buf_put(ion_dma_buf->dbuf);
+
+ return ret;
+}
+EXPORT_SYMBOL(tspp_attach_ion_dma_buff);
+
+/**
+ * tspp_detach_ion_dma_buff - detach the mapped ion dma buffer from TSPP device
+ * It will detach previously mapped DMA buffer from TSPP device.
+ *
+ * @dev: TSPP device (up to TSPP_MAX_DEVICES)
+ * @ion_dma_buf: It contains required members for ION buffer dma mapping.
+ *
+ * Return error status
+ *
+ */
+int tspp_detach_ion_dma_buff(u32 dev, struct tspp_ion_dma_buf_info *ion_dma_buf)
+{
+ struct tspp_device *pdev;
+ int dir = DMA_FROM_DEVICE;
+
+ if (ion_dma_buf == NULL || ion_dma_buf->dbuf == NULL ||
+ ion_dma_buf->table == NULL || ion_dma_buf->table->sgl == NULL ||
+ ion_dma_buf->smmu_map == false) {
+ pr_err("tspp: invalid input argument");
+ return -EINVAL;
+ }
+
+ if (dev >= TSPP_MAX_DEVICES) {
+ pr_err("tspp: device id out of range");
+ return -ENODEV;
+ }
+
+ pdev = tspp_find_by_id(dev);
+ if (!pdev) {
+ pr_err("tspp: can't find device %i", dev);
+ return -ENODEV;
+ }
+
+
+ dma_unmap_sg(&pdev->pdev->dev, ion_dma_buf->table->sgl,
+ ion_dma_buf->table->nents, dir);
+ dma_buf_unmap_attachment(ion_dma_buf->attach, ion_dma_buf->table, dir);
+ dma_buf_detach(ion_dma_buf->dbuf, ion_dma_buf->attach);
+ dma_buf_put(ion_dma_buf->dbuf);
+
+ ion_dma_buf->smmu_map = false;
+ return 0;
+}
+EXPORT_SYMBOL(tspp_detach_ion_dma_buff);
+
+
/*** debugfs ***/
static int debugfs_iomem_x32_set(void *data, u64 val)
{
@@ -2959,6 +3111,11 @@
goto err_irq;
device->req_irqs = false;
+ if (tspp_iommu_init(device)) {
+ dev_err(&pdev->dev, "iommu init failed");
+ goto err_iommu;
+ }
+
device->tts_source = TSIF_TTS_TCR;
for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
device->tsif[i].tts_source = device->tts_source;
@@ -3029,6 +3186,8 @@
tspp_debugfs_exit(device);
for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
tsif_debugfs_exit(&device->tsif[i]);
+err_iommu:
+ tspp_iommu_release_iomapping(device);
err_irq:
iounmap(device->bam_props.virt_addr);
err_map_bam:
@@ -3099,6 +3258,9 @@
if (device->tsif_vreg)
regulator_disable(device->tsif_vreg);
+ tspp_iommu_release_iomapping(device);
+ arm_iommu_detach_device(&pdev->dev);
+
pm_runtime_disable(&pdev->dev);
kfree(device);
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c
index da7ecce..a075ed9 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c
@@ -14,6 +14,7 @@
#include <linux/module.h>
#include <linux/kthread.h>
#include <linux/vmalloc.h>
+#include <linux/dma-buf.h>
#include <linux/qcom_tspp.h>
#include "mpq_dvb_debug.h"
#include "mpq_dmx_plugin_common.h"
@@ -189,6 +190,10 @@
/* Mutex protecting the data-structure */
struct mutex mutex;
+
+ /* ion dma buffer mapping structure */
+ struct tspp_ion_dma_buf_info ch_ion_dma_buf;
+
} tsif[TSIF_COUNT];
/* ION client used for TSPP data buffer allocation */
@@ -196,7 +201,8 @@
} mpq_dmx_tspp_info;
static void *tspp_mem_allocator(int channel_id, u32 size,
- phys_addr_t *phys_base, void *user)
+ phys_addr_t *phys_base, dma_addr_t *dma_base,
+ void *user)
{
void *virt_addr = NULL;
int i = TSPP_GET_TSIF_NUM(channel_id);
@@ -213,6 +219,10 @@
(mpq_dmx_tspp_info.tsif[i].ch_mem_heap_phys_base +
(mpq_dmx_tspp_info.tsif[i].buff_index * size));
+ *dma_base =
+ (mpq_dmx_tspp_info.tsif[i].ch_ion_dma_buf.dma_map_base +
+ (mpq_dmx_tspp_info.tsif[i].buff_index * size));
+
mpq_dmx_tspp_info.tsif[i].buff_index++;
return virt_addr;
@@ -539,6 +549,9 @@
mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_virt_base = NULL;
mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_handle = NULL;
+
+ tspp_detach_ion_dma_buff(0,
+ &mpq_dmx_tspp_info.tsif[tsif].ch_ion_dma_buf);
}
/**
@@ -589,6 +602,24 @@
return -ENOMEM;
}
+ mpq_dmx_tspp_info.tsif[tsif].ch_ion_dma_buf.dbuf = ion_share_dma_buf(
+ mpq_dmx_tspp_info.ion_client,
+ mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_handle);
+ if (IS_ERR_OR_NULL(mpq_dmx_tspp_info.tsif[tsif].ch_ion_dma_buf.dbuf)) {
+ MPQ_DVB_ERR_PRINT("%s: ion_share_dma_buf failed\n", __func__);
+ mpq_dmx_channel_mem_free(tsif);
+ return -ENOMEM;
+ }
+
+ result = tspp_attach_ion_dma_buff(0,
+ &mpq_dmx_tspp_info.tsif[tsif].ch_ion_dma_buf);
+ if (result) {
+ MPQ_DVB_ERR_PRINT("%s: tspp_attach_ion_dma_buff failed\n",
+ __func__);
+ mpq_dmx_channel_mem_free(tsif);
+ return result;
+ }
+
return 0;
}
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
index 9d10b06..b0fe8db 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
@@ -11,7 +11,7 @@
*
*/
-#define pr_fmt(fmt) "%s: " fmt, __func__
+#define pr_fmt(fmt) "%s:%d: " fmt, __func__, __LINE__
#include <linux/platform_device.h>
#include <linux/module.h>
@@ -325,7 +325,7 @@
if (mgr->rsc_client)
ret = sde_rsc_client_state_update(mgr->rsc_client,
on ? SDE_RSC_CLK_STATE : SDE_RSC_IDLE_STATE,
- NULL, -1);
+ NULL, SDE_RSC_INVALID_CRTC_ID, NULL);
else
ret = sde_rot_enable_vreg(mgr->module_power.vreg_config,
mgr->module_power.num_vreg, on);
@@ -341,8 +341,6 @@
if (!on) {
mgr->minimum_bw_vote = 0;
sde_rotator_update_perf(mgr);
- } else {
- sde_mdp_init_vbif();
}
mgr->regulator_enable = on;
@@ -426,6 +424,9 @@
if (ret)
goto error_rot_sub;
+ /* reinitialize static vbif setting */
+ sde_mdp_init_vbif();
+
/* Active+Sleep */
msm_bus_scale_client_update_context(
mgr->data_bus.bus_hdl, false,
@@ -945,6 +946,11 @@
"timeout waiting for hw resource, a:%d p:%d\n",
atomic_read(&hw->num_active),
hw->pending_count);
+ SDEROT_EVTLOG(entry->item.session_id,
+ entry->item.sequence_id,
+ atomic_read(&hw->num_active),
+ hw->pending_count,
+ SDE_ROT_EVTLOG_ERROR);
return NULL;
}
}
@@ -1603,9 +1609,14 @@
entry->item.flags,
entry->dnsc_factor_w, entry->dnsc_factor_h);
- wait_for_completion_timeout(
+ ret = wait_for_completion_timeout(
&entry->item.inline_start,
msecs_to_jiffies(ROT_INLINE_START_TIMEOUT_IN_MS));
+ if (!ret) {
+ SDEROT_WARN("timeout waiting for inline start\n");
+ SDEROT_EVTLOG(entry->item.session_id, entry->item.sequence_id,
+ SDE_ROT_EVTLOG_ERROR);
+ }
if (entry->item.ts)
entry->item.ts[SDE_ROTATOR_TS_START] = ktime_get();
@@ -1652,18 +1663,20 @@
static bool sde_rotator_verify_format(struct sde_rot_mgr *mgr,
struct sde_mdp_format_params *in_fmt,
- struct sde_mdp_format_params *out_fmt, bool rotation)
+ struct sde_mdp_format_params *out_fmt, bool rotation, u32 mode)
{
u8 in_v_subsample, in_h_subsample;
u8 out_v_subsample, out_h_subsample;
- if (!sde_rotator_is_valid_pixfmt(mgr, in_fmt->format, true)) {
- SDEROT_ERR("Invalid input format %x\n", in_fmt->format);
+ if (!sde_rotator_is_valid_pixfmt(mgr, in_fmt->format, true, mode)) {
+ SDEROT_ERR("Invalid input format 0x%x (%4.4s)\n",
+ in_fmt->format, (char *)&in_fmt->format);
goto verify_error;
}
- if (!sde_rotator_is_valid_pixfmt(mgr, out_fmt->format, false)) {
- SDEROT_ERR("Invalid output format %x\n", out_fmt->format);
+ if (!sde_rotator_is_valid_pixfmt(mgr, out_fmt->format, false, mode)) {
+ SDEROT_ERR("Invalid output format 0x%x (%4.4s)\n",
+ out_fmt->format, (char *)&out_fmt->format);
goto verify_error;
}
@@ -1712,8 +1725,10 @@
return true;
verify_error:
- SDEROT_ERR("in_fmt=0x%x, out_fmt=0x%x\n",
- in_fmt->format, out_fmt->format);
+ SDEROT_ERR("in_fmt=0x%x (%4.4s), out_fmt=0x%x (%4.4s), mode=%d\n",
+ in_fmt->format, (char *)&in_fmt->format,
+ out_fmt->format, (char *)&out_fmt->format,
+ mode);
return false;
}
@@ -1832,6 +1847,7 @@
{
struct sde_mdp_format_params *in_fmt, *out_fmt;
bool rotation;
+ u32 mode;
if (!mgr || !config) {
SDEROT_ERR("null parameters\n");
@@ -1840,6 +1856,9 @@
rotation = (config->flags & SDE_ROTATION_90) ? true : false;
+ mode = config->output.sbuf ? SDE_ROTATOR_MODE_SBUF :
+ SDE_ROTATOR_MODE_OFFLINE;
+
in_fmt = __verify_input_config(mgr, config);
if (!in_fmt)
return -EINVAL;
@@ -1848,7 +1867,7 @@
if (!out_fmt)
return -EINVAL;
- if (!sde_rotator_verify_format(mgr, in_fmt, out_fmt, rotation)) {
+ if (!sde_rotator_verify_format(mgr, in_fmt, out_fmt, rotation, mode)) {
SDEROT_ERR(
"Rot format pairing invalid, in_fmt:0x%x, out_fmt:0x%x\n",
config->input.format,
@@ -2335,6 +2354,7 @@
if (config->output.sbuf && mgr->sbuf_ctx != private && mgr->sbuf_ctx) {
SDEROT_ERR("too many sbuf sessions\n");
+ ret = -EBUSY;
goto done;
}
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h
index 731ff1e..3d368a1 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h
@@ -141,6 +141,12 @@
SDE_ROTATOR_TRIGGER_COMMAND,
};
+enum sde_rotator_mode {
+ SDE_ROTATOR_MODE_OFFLINE,
+ SDE_ROTATOR_MODE_SBUF,
+ SDE_ROTATOR_MODE_MAX,
+};
+
struct sde_rotation_item {
/* rotation request flag */
uint32_t flags;
@@ -463,9 +469,9 @@
int (*ops_hw_validate_entry)(struct sde_rot_mgr *mgr,
struct sde_rot_entry *entry);
u32 (*ops_hw_get_pixfmt)(struct sde_rot_mgr *mgr, int index,
- bool input);
+ bool input, u32 mode);
int (*ops_hw_is_valid_pixfmt)(struct sde_rot_mgr *mgr, u32 pixfmt,
- bool input);
+ bool input, u32 mode);
int (*ops_hw_get_downscale_caps)(struct sde_rot_mgr *mgr, char *caps,
int len);
int (*ops_hw_get_maxlinewidth)(struct sde_rot_mgr *mgr);
@@ -474,19 +480,19 @@
};
static inline int sde_rotator_is_valid_pixfmt(struct sde_rot_mgr *mgr,
- u32 pixfmt, bool input)
+ u32 pixfmt, bool input, u32 mode)
{
if (mgr && mgr->ops_hw_is_valid_pixfmt)
- return mgr->ops_hw_is_valid_pixfmt(mgr, pixfmt, input);
+ return mgr->ops_hw_is_valid_pixfmt(mgr, pixfmt, input, mode);
return false;
}
static inline u32 sde_rotator_get_pixfmt(struct sde_rot_mgr *mgr,
- int index, bool input)
+ int index, bool input, u32 mode)
{
if (mgr && mgr->ops_hw_get_pixfmt)
- return mgr->ops_hw_get_pixfmt(mgr, index, input);
+ return mgr->ops_hw_get_pixfmt(mgr, index, input, mode);
return 0;
}
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c
index 3e686e9..2a9573d 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c
@@ -21,6 +21,7 @@
#include "sde_rotator_base.h"
#include "sde_rotator_core.h"
#include "sde_rotator_dev.h"
+#include "sde_rotator_trace.h"
#ifdef CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG
#define SDE_EVTLOG_DEFAULT_ENABLE 1
@@ -639,12 +640,13 @@
/*
* sde_rot_dump_panic - Issue evtlog dump and generic panic
*/
-void sde_rot_dump_panic(void)
+void sde_rot_dump_panic(bool do_panic)
{
sde_rot_evtlog_dump_all();
sde_rot_dump_reg_all();
- panic("sde_rotator");
+ if (do_panic)
+ panic("sde_rotator");
}
/*
@@ -740,6 +742,8 @@
(sde_rot_dbg_evtlog.curr + 1) % SDE_ROT_EVTLOG_ENTRY;
sde_rot_dbg_evtlog.last++;
+ trace_sde_rot_evtlog(name, line, log->data_cnt, log->data);
+
spin_unlock_irqrestore(&sde_rot_xlock, flags);
}
@@ -1136,6 +1140,9 @@
if (sscanf(buf, "%5x %x", &off, &cnt) < 2)
return -EINVAL;
+ if (off % sizeof(u32))
+ return -EINVAL;
+
if (off > dbg->max_offset)
return -EINVAL;
@@ -1204,6 +1211,9 @@
if (cnt < 2)
return -EFAULT;
+ if (off % sizeof(u32))
+ return -EFAULT;
+
if (off >= dbg->max_offset)
return -EFAULT;
@@ -1252,6 +1262,9 @@
goto debug_read_error;
}
+ if (dbg->off % sizeof(u32))
+ return -EFAULT;
+
ptr = dbg->base + dbg->off;
tot = 0;
@@ -1425,6 +1438,13 @@
return NULL;
}
+ if (!debugfs_create_u32("open_timeout", 0644,
+ debugfs_root, &rot_dev->open_timeout)) {
+ SDEROT_ERR("fail create open_timeout\n");
+ debugfs_remove_recursive(debugfs_root);
+ return NULL;
+ }
+
if (!debugfs_create_u32("disable_syscache", 0644,
debugfs_root, &rot_dev->disable_syscache)) {
SDEROT_ERR("fail create disable_syscache\n");
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.h
index c6d0151..2fc8e3f 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.h
@@ -18,6 +18,9 @@
#define SDE_ROT_DATA_LIMITER (-1)
#define SDE_ROT_EVTLOG_TOUT_DATA_LIMITER (NULL)
+#define SDE_ROT_EVTLOG_PANIC 0xdead
+#define SDE_ROT_EVTLOG_FATAL 0xbad
+#define SDE_ROT_EVTLOG_ERROR 0xebad
enum sde_rot_dbg_reg_dump_flag {
SDE_ROT_DBG_DUMP_IN_LOG = BIT(0),
@@ -39,7 +42,7 @@
SDE_ROT_EVTLOG_TOUT_DATA_LIMITER)
void sde_rot_evtlog(const char *name, int line, int flag, ...);
-void sde_rot_dump_panic(void);
+void sde_rot_dump_panic(bool do_panic);
void sde_rot_evtlog_tout_handler(bool queue, const char *name, ...);
struct sde_rotator_device;
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
index d300de2..acd4b7d 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
@@ -9,7 +9,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
-#define pr_fmt(fmt) "%s: " fmt, __func__
+#define pr_fmt(fmt) "%s:%d: " fmt, __func__, __LINE__
#include <linux/vmalloc.h>
#include <linux/kernel.h>
@@ -46,6 +46,9 @@
/* acquire fence time out, following other driver fence time out practice */
#define SDE_ROTATOR_FENCE_TIMEOUT MSEC_PER_SEC
+/* Timeout (msec) waiting for ctx open */
+#define SDE_ROTATOR_CTX_OPEN_TIMEOUT 500
+
/* Rotator default fps */
#define SDE_ROTATOR_DEFAULT_FPS 60
@@ -457,6 +460,9 @@
"timeout to stream off s:%d t:%d p:%d\n",
ctx->session_id, q->type,
!list_empty(&ctx->pending_list));
+ SDEROT_EVTLOG(ctx->session_id, q->type,
+ !list_empty(&ctx->pending_list),
+ SDE_ROT_EVTLOG_ERROR);
sde_rot_mgr_lock(rot_dev->mgr);
sde_rotator_cancel_all_requests(rot_dev->mgr, ctx->private);
sde_rot_mgr_unlock(rot_dev->mgr);
@@ -486,7 +492,7 @@
struct sde_rotator_vbinfo *vbinfo =
&ctx->vbinfo_cap[i];
- if (vbinfo->fence && vbinfo->fd < 0) {
+ if (vbinfo->fence) {
/* fence is not used */
SDEDEV_DBG(rot_dev->dev,
"put fence s:%d t:%d i:%d\n",
@@ -893,6 +899,29 @@
goto error_lock;
}
+ /* wait until exclusive ctx, if exists, finishes or timeout */
+ while (rot_dev->excl_ctx) {
+ SDEROT_DBG("waiting to open %s session %d ...\n",
+ file ? "v4l2" : "excl", rot_dev->session_id);
+ mutex_unlock(&rot_dev->lock);
+ ret = wait_event_interruptible_timeout(rot_dev->open_wq,
+ !rot_dev->excl_ctx,
+ msecs_to_jiffies(rot_dev->open_timeout));
+ if (ret < 0) {
+ goto error_lock;
+ } else if (!ret) {
+ SDEROT_WARN("timeout to open session %d\n",
+ rot_dev->session_id);
+ SDEROT_EVTLOG(rot_dev->session_id,
+ SDE_ROT_EVTLOG_ERROR);
+ ret = -EBUSY;
+ goto error_lock;
+ } else if (mutex_lock_interruptible(&rot_dev->lock)) {
+ ret = -ERESTARTSYS;
+ goto error_lock;
+ }
+ }
+
ctx->rot_dev = rot_dev;
ctx->file = file;
@@ -991,8 +1020,8 @@
}
sde_rot_mgr_unlock(rot_dev->mgr);
- /* Create control */
if (ctx->file) {
+ /* Create control */
ctrl_handler = &ctx->ctrl_handler;
v4l2_ctrl_handler_init(ctrl_handler, 4);
v4l2_ctrl_new_std(ctrl_handler,
@@ -1012,7 +1041,14 @@
}
ctx->fh.ctrl_handler = ctrl_handler;
v4l2_ctrl_handler_setup(ctrl_handler);
+ } else {
+ /* acquire exclusive context */
+ SDEDEV_DBG(rot_dev->dev, "acquire exclusive session id:%u\n",
+ ctx->session_id);
+ SDEROT_EVTLOG(ctx->session_id);
+ rot_dev->excl_ctx = ctx;
}
+
mutex_unlock(&rot_dev->lock);
SDEDEV_DBG(ctx->rot_dev->dev, "SDE v4l2 rotator open success\n");
@@ -1059,6 +1095,12 @@
SDEDEV_DBG(rot_dev->dev, "release s:%d\n", session_id);
mutex_lock(&rot_dev->lock);
+ if (rot_dev->excl_ctx == ctx) {
+ SDEDEV_DBG(rot_dev->dev, "release exclusive session id:%u\n",
+ session_id);
+ SDEROT_EVTLOG(session_id);
+ rot_dev->excl_ctx = NULL;
+ }
if (ctx->file) {
v4l2_ctrl_handler_free(&ctx->ctrl_handler);
SDEDEV_DBG(rot_dev->dev, "release streams s:%d\n", session_id);
@@ -1105,6 +1147,7 @@
kfree(ctx->vbinfo_out);
kfree(ctx->vbinfo_cap);
kfree(ctx);
+ wake_up_interruptible(&rot_dev->open_wq);
mutex_unlock(&rot_dev->lock);
SDEDEV_DBG(rot_dev->dev, "release complete s:%d\n", session_id);
return 0;
@@ -1390,7 +1433,8 @@
sde_rot_mgr_lock(rot_dev->mgr);
for (i = 0;; i++) {
- pixfmt = sde_rotator_get_pixfmt(rot_dev->mgr, i, input);
+ pixfmt = sde_rotator_get_pixfmt(rot_dev->mgr, i, input,
+ SDE_ROTATOR_MODE_SBUF);
if (!pixfmt)
break;
if (pixfmts && i < len)
@@ -1451,15 +1495,14 @@
SDEROT_EVTLOG(ctx->session_id, cmd->sequence_id,
cmd->src_rect_x, cmd->src_rect_y,
cmd->src_rect_w, cmd->src_rect_h,
- cmd->src_width, cmd->src_height,
cmd->src_pixfmt,
- cmd->dst_rect_x, cmd->dst_rect_y,
cmd->dst_rect_w, cmd->dst_rect_h,
cmd->dst_pixfmt,
- cmd->rot90, cmd->hflip, cmd->vflip, cmd->secure, cmd->fps,
- cmd->clkrate, cmd->data_bw,
- cmd->dst_writeback, cmd->video_mode, cmd_type);
-
+ (cmd->rot90 << 0) | (cmd->hflip << 1) | (cmd->vflip << 2) |
+ (cmd->secure << 3) | (cmd->dst_writeback << 4) |
+ (cmd->video_mode << 5),
+ cmd->fps, cmd->clkrate, cmd->data_bw,
+ cmd_type);
sde_rot_mgr_lock(rot_dev->mgr);
@@ -1568,7 +1611,7 @@
ret = sde_rotator_session_config(rot_dev->mgr,
ctx->private, &rotcfg);
if (ret) {
- SDEROT_ERR("fail session config s:%d\n",
+ SDEROT_WARN("fail session config s:%d\n",
ctx->session_id);
goto error_session_config;
}
@@ -1579,7 +1622,7 @@
ret = sde_rotator_validate_request(rot_dev->mgr, ctx->private,
req);
if (ret) {
- SDEROT_ERR("fail validate request s:%d\n",
+ SDEROT_WARN("fail validate request s:%d\n",
ctx->session_id);
goto error_validate_request;
}
@@ -1677,13 +1720,17 @@
ret = wait_event_timeout(ctx->wait_queue,
sde_rotator_is_request_retired(request),
msecs_to_jiffies(rot_dev->streamoff_timeout));
- if (!ret)
+ if (!ret) {
SDEROT_ERR("timeout w/o retire s:%d\n",
ctx->session_id);
- else if (ret == 1)
+ SDEROT_EVTLOG(ctx->session_id,
+ SDE_ROT_EVTLOG_ERROR);
+ } else if (ret == 1) {
SDEROT_ERR("timeout w/ retire s:%d\n",
ctx->session_id);
-
+ SDEROT_EVTLOG(ctx->session_id,
+ SDE_ROT_EVTLOG_ERROR);
+ }
sde_rot_mgr_lock(rot_dev->mgr);
}
@@ -1708,6 +1755,12 @@
}
EXPORT_SYMBOL(sde_rotator_inline_commit);
+void sde_rotator_inline_reg_dump(struct platform_device *pdev)
+{
+ sde_rot_dump_panic(false);
+}
+EXPORT_SYMBOL(sde_rotator_inline_reg_dump);
+
/*
* sde_rotator_open - Rotator device open method.
* @file: Pointer to file struct.
@@ -1805,7 +1858,8 @@
bool found = false;
for (i = 0, index = 0; index <= f->index; i++) {
- pixfmt = sde_rotator_get_pixfmt(rot_dev->mgr, i, false);
+ pixfmt = sde_rotator_get_pixfmt(rot_dev->mgr, i, false,
+ SDE_ROTATOR_MODE_OFFLINE);
if (!pixfmt)
return -EINVAL;
@@ -1849,7 +1903,8 @@
bool found = false;
for (i = 0, index = 0; index <= f->index; i++) {
- pixfmt = sde_rotator_get_pixfmt(rot_dev->mgr, i, true);
+ pixfmt = sde_rotator_get_pixfmt(rot_dev->mgr, i, true,
+ SDE_ROTATOR_MODE_OFFLINE);
if (!pixfmt)
return -EINVAL;
@@ -2158,7 +2213,7 @@
&& (buf->index < ctx->nbuf_cap)) {
int idx = buf->index;
- if (ctx->vbinfo_cap[idx].fence && ctx->vbinfo_cap[idx].fd < 0) {
+ if (ctx->vbinfo_cap[idx].fence) {
/* fence is not used */
SDEDEV_DBG(ctx->rot_dev->dev, "put fence s:%d i:%d\n",
ctx->session_id, idx);
@@ -2487,6 +2542,7 @@
struct msm_sde_rotator_fence *fence = arg;
struct msm_sde_rotator_comp_ratio *comp_ratio = arg;
struct sde_rotator_vbinfo *vbinfo;
+ int ret;
switch (cmd) {
case VIDIOC_S_SDE_ROTATOR_FENCE:
@@ -2545,17 +2601,37 @@
vbinfo = &ctx->vbinfo_cap[fence->index];
- if (vbinfo->fence == NULL) {
- vbinfo->fd = -1;
- } else {
- vbinfo->fd =
- sde_rotator_get_sync_fence_fd(vbinfo->fence);
- if (vbinfo->fd < 0) {
+ if (!vbinfo)
+ return -EINVAL;
+
+ if (vbinfo->fence) {
+ ret = sde_rotator_get_sync_fence_fd(vbinfo->fence);
+ if (ret < 0) {
SDEDEV_ERR(rot_dev->dev,
- "fail get fence fd s:%d\n",
- ctx->session_id);
- return vbinfo->fd;
+ "fail get fence fd s:%d\n",
+ ctx->session_id);
+ return ret;
}
+
+ /**
+ * Loose any reference to sync fence once we pass
+ * it to user. Driver does not clean up user
+ * unclosed fence descriptors.
+ */
+ vbinfo->fence = NULL;
+
+ /**
+ * Cache fence descriptor in case user calls this
+ * ioctl multiple times. Cached value would be stale
+ * if user duplicated and closed old descriptor.
+ */
+ vbinfo->fd = ret;
+ } else if (!sde_rotator_get_fd_sync_fence(vbinfo->fd)) {
+ /**
+ * User has closed cached fence descriptor.
+ * Invalidate descriptor cache.
+ */
+ vbinfo->fd = -1;
}
fence->fd = vbinfo->fd;
@@ -2878,6 +2954,9 @@
"error waiting for fence s:%d.%d fd:%d r:%d\n",
ctx->session_id,
vbinfo_cap->fence_ts, vbinfo_out->fd, ret);
+ SDEROT_EVTLOG(ctx->session_id, vbinfo_cap->fence_ts,
+ vbinfo_out->fd, ret,
+ SDE_ROT_EVTLOG_ERROR);
goto error_fence_wait;
} else {
SDEDEV_DBG(rot_dev->dev, "fence exit s:%d.%d fd:%d\n",
@@ -3278,6 +3357,8 @@
rot_dev->min_bw = 0;
rot_dev->min_overhead_us = 0;
rot_dev->drvdata = sde_rotator_get_drv_data(&pdev->dev);
+ rot_dev->open_timeout = SDE_ROTATOR_CTX_OPEN_TIMEOUT;
+ init_waitqueue_head(&rot_dev->open_wq);
rot_dev->pdev = pdev;
rot_dev->dev = &pdev->dev;
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.h
index 627ea86..5ea9e15 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.h
@@ -205,6 +205,9 @@
* @min_overhead_us: Override the minimum overhead in us from perf calculation
* @debugfs_root: Pointer to debugfs directory entry.
* @stats: placeholder for rotator statistics
+ * @open_timeout: maximum wait time for ctx open in msec
+ * @open_wq: wait queue for ctx open
+ * @excl_ctx: Pointer to exclusive ctx
*/
struct sde_rotator_device {
struct mutex lock;
@@ -227,6 +230,9 @@
struct sde_rotator_statistics stats;
struct dentry *debugfs_root;
struct dentry *perf_root;
+ u32 open_timeout;
+ wait_queue_head_t open_wq;
+ struct sde_rotator_ctx *excl_ctx;
};
static inline
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.c
index 573e0a8..7585a6b 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.c
@@ -783,10 +783,15 @@
if (!fmt_found) {
for (i = 0; i < ARRAY_SIZE(sde_mdp_format_ubwc_map); i++) {
fmt = &sde_mdp_format_ubwc_map[i].mdp_format;
- if (format == fmt->format)
+ if (format == fmt->format) {
+ fmt_found = true;
break;
+ }
}
}
+ /* If format not supported than return NULL */
+ if (!fmt_found)
+ fmt = NULL;
return fmt;
}
@@ -845,6 +850,11 @@
case SDE_PIX_FMT_Y_CRCB_H2V2_TILE:
*dst_pixfmt = SDE_PIX_FMT_Y_CRCB_H2V2_TILE;
break;
+ case V4L2_PIX_FMT_RGB565:
+ case SDE_PIX_FMT_RGB_565_UBWC:
+ case SDE_PIX_FMT_RGB_565_TILE:
+ *dst_pixfmt = SDE_PIX_FMT_RGB_565_TILE;
+ break;
case SDE_PIX_FMT_RGBA_8888:
case SDE_PIX_FMT_RGBA_8888_UBWC:
case SDE_PIX_FMT_RGBA_8888_TILE:
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.h
index 5bb6198..545dcfc 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.h
@@ -37,6 +37,7 @@
#define SDE_PIX_FMT_RGBA_1010102_TILE v4l2_fourcc('Q', 'T', '1', '0')
#define SDE_PIX_FMT_RGBX_1010102_TILE v4l2_fourcc('Q', 'T', '1', '1')
#define SDE_PIX_FMT_Y_CBCR_H2V2_P010_TILE v4l2_fourcc('Q', 'T', '1', '2')
+#define SDE_PIX_FMT_RGB_565_TILE v4l2_fourcc('Q', 'T', '1', '3')
#define SDE_ROT_MAX_PLANES 4
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_inline.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_inline.h
index 705eb27..474662e 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_inline.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_inline.h
@@ -112,5 +112,6 @@
int sde_rotator_inline_commit(void *handle, struct sde_rotator_inline_cmd *cmd,
enum sde_rotator_inline_cmd_type cmd_type);
int sde_rotator_inline_release(void *handle);
+void sde_rotator_inline_reg_dump(struct platform_device *pdev);
#endif /* __SDE_ROTATOR_INLINE_H__ */
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r1.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_r1.c
index 9f4a854..1b4913b 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r1.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r1.c
@@ -501,9 +501,10 @@
* @mgr: Pointer to rotator manager
* @index: index of pixel format
* @input: true for input port; false for output port
+ * @mode: operating mode
*/
static u32 sde_hw_rotator_get_pixfmt(struct sde_rot_mgr *mgr,
- int index, bool input)
+ int index, bool input, u32 mode)
{
if (input) {
if (index < ARRAY_SIZE(sde_hw_rotator_input_pixfmts))
@@ -523,9 +524,10 @@
* @mgr: Pointer to rotator manager
* @pixfmt: pixel format to be verified
* @input: true for input port; false for output port
+ * @mode: operating mode
*/
static int sde_hw_rotator_is_valid_pixfmt(struct sde_rot_mgr *mgr, u32 pixfmt,
- bool input)
+ bool input, u32 mode)
{
int i;
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
index 205eeef..3c47dd7 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
@@ -11,7 +11,7 @@
*
*/
-#define pr_fmt(fmt) "%s: " fmt, __func__
+#define pr_fmt(fmt) "%s:%d: " fmt, __func__, __LINE__
#include <linux/platform_device.h>
#include <linux/module.h>
@@ -107,7 +107,7 @@
#define SDE_ROTREG_READ(base, off) \
readl_relaxed(base + (off))
-static u32 sde_hw_rotator_v3_inpixfmts[] = {
+static const u32 sde_hw_rotator_v3_inpixfmts[] = {
SDE_PIX_FMT_XRGB_8888,
SDE_PIX_FMT_ARGB_8888,
SDE_PIX_FMT_ABGR_8888,
@@ -167,7 +167,7 @@
SDE_PIX_FMT_Y_CBCR_H2V2_TP10_UBWC,
};
-static u32 sde_hw_rotator_v3_outpixfmts[] = {
+static const u32 sde_hw_rotator_v3_outpixfmts[] = {
SDE_PIX_FMT_XRGB_8888,
SDE_PIX_FMT_ARGB_8888,
SDE_PIX_FMT_ABGR_8888,
@@ -227,7 +227,7 @@
SDE_PIX_FMT_Y_CBCR_H2V2_TP10_UBWC,
};
-static u32 sde_hw_rotator_v4_inpixfmts[] = {
+static const u32 sde_hw_rotator_v4_inpixfmts[] = {
SDE_PIX_FMT_XRGB_8888,
SDE_PIX_FMT_ARGB_8888,
SDE_PIX_FMT_ABGR_8888,
@@ -307,7 +307,7 @@
SDE_PIX_FMT_XBGR_2101010_TILE,
};
-static u32 sde_hw_rotator_v4_outpixfmts[] = {
+static const u32 sde_hw_rotator_v4_outpixfmts[] = {
SDE_PIX_FMT_XRGB_8888,
SDE_PIX_FMT_ARGB_8888,
SDE_PIX_FMT_ABGR_8888,
@@ -387,6 +387,23 @@
SDE_PIX_FMT_XBGR_2101010_TILE,
};
+static const u32 sde_hw_rotator_v4_inpixfmts_sbuf[] = {
+ SDE_PIX_FMT_Y_CBCR_H2V2_P010,
+ SDE_PIX_FMT_Y_CBCR_H2V2,
+ SDE_PIX_FMT_Y_CBCR_H2V2_TP10_UBWC,
+ SDE_PIX_FMT_Y_CBCR_H2V2_P010_UBWC,
+ SDE_PIX_FMT_Y_CBCR_H2V2_UBWC,
+ SDE_PIX_FMT_Y_CBCR_H2V2_TP10,
+ SDE_PIX_FMT_Y_CBCR_H2V2_P010_TILE,
+ SDE_PIX_FMT_Y_CBCR_H2V2_TILE,
+};
+
+static const u32 sde_hw_rotator_v4_outpixfmts_sbuf[] = {
+ SDE_PIX_FMT_Y_CBCR_H2V2_TP10,
+ SDE_PIX_FMT_Y_CBCR_H2V2_P010_TILE,
+ SDE_PIX_FMT_Y_CBCR_H2V2_TILE,
+};
+
static struct sde_rot_vbif_debug_bus nrt_vbif_dbg_bus_r3[] = {
{0x214, 0x21c, 16, 1, 0x200}, /* arb clients main */
{0x214, 0x21c, 0, 12, 0x13}, /* xin blocks - axi side */
@@ -2637,17 +2654,33 @@
set_bit(SDE_CAPS_SBUF_1, mdata->sde_caps_map);
set_bit(SDE_CAPS_UBWC_2, mdata->sde_caps_map);
set_bit(SDE_CAPS_PARTIALWR, mdata->sde_caps_map);
- rot->inpixfmts = sde_hw_rotator_v4_inpixfmts;
- rot->num_inpixfmt = ARRAY_SIZE(sde_hw_rotator_v4_inpixfmts);
- rot->outpixfmts = sde_hw_rotator_v4_outpixfmts;
- rot->num_outpixfmt = ARRAY_SIZE(sde_hw_rotator_v4_outpixfmts);
+ rot->inpixfmts[SDE_ROTATOR_MODE_OFFLINE] =
+ sde_hw_rotator_v4_inpixfmts;
+ rot->num_inpixfmt[SDE_ROTATOR_MODE_OFFLINE] =
+ ARRAY_SIZE(sde_hw_rotator_v4_inpixfmts);
+ rot->outpixfmts[SDE_ROTATOR_MODE_OFFLINE] =
+ sde_hw_rotator_v4_outpixfmts;
+ rot->num_outpixfmt[SDE_ROTATOR_MODE_OFFLINE] =
+ ARRAY_SIZE(sde_hw_rotator_v4_outpixfmts);
+ rot->inpixfmts[SDE_ROTATOR_MODE_SBUF] =
+ sde_hw_rotator_v4_inpixfmts_sbuf;
+ rot->num_inpixfmt[SDE_ROTATOR_MODE_SBUF] =
+ ARRAY_SIZE(sde_hw_rotator_v4_inpixfmts_sbuf);
+ rot->outpixfmts[SDE_ROTATOR_MODE_SBUF] =
+ sde_hw_rotator_v4_outpixfmts_sbuf;
+ rot->num_outpixfmt[SDE_ROTATOR_MODE_SBUF] =
+ ARRAY_SIZE(sde_hw_rotator_v4_outpixfmts_sbuf);
rot->downscale_caps =
"LINEAR/1.5/2/4/8/16/32/64 TILE/1.5/2/4 TP10/1.5/2";
} else {
- rot->inpixfmts = sde_hw_rotator_v3_inpixfmts;
- rot->num_inpixfmt = ARRAY_SIZE(sde_hw_rotator_v3_inpixfmts);
- rot->outpixfmts = sde_hw_rotator_v3_outpixfmts;
- rot->num_outpixfmt = ARRAY_SIZE(sde_hw_rotator_v3_outpixfmts);
+ rot->inpixfmts[SDE_ROTATOR_MODE_OFFLINE] =
+ sde_hw_rotator_v3_inpixfmts;
+ rot->num_inpixfmt[SDE_ROTATOR_MODE_OFFLINE] =
+ ARRAY_SIZE(sde_hw_rotator_v3_inpixfmts);
+ rot->outpixfmts[SDE_ROTATOR_MODE_OFFLINE] =
+ sde_hw_rotator_v3_outpixfmts;
+ rot->num_outpixfmt[SDE_ROTATOR_MODE_OFFLINE] =
+ ARRAY_SIZE(sde_hw_rotator_v3_outpixfmts);
rot->downscale_caps = (hw_version == SDE_ROT_TYPE_V1_0) ?
"LINEAR/2/4/8/16/32/64 TILE/2/4 TP10/2" :
"LINEAR/1.5/2/4/8/16/32/64 TILE/1.5/2/4 TP10/1.5/2";
@@ -3055,9 +3088,10 @@
* @mgr: Pointer to rotator manager
* @index: index of pixel format
* @input: true for input port; false for output port
+ * @mode: operating mode
*/
static u32 sde_hw_rotator_get_pixfmt(struct sde_rot_mgr *mgr,
- int index, bool input)
+ int index, bool input, u32 mode)
{
struct sde_hw_rotator *rot;
@@ -3068,14 +3102,19 @@
rot = mgr->hw_data;
+ if (mode >= SDE_ROTATOR_MODE_MAX) {
+ SDEROT_ERR("invalid rotator mode %d\n", mode);
+ return 0;
+ }
+
if (input) {
- if ((index < rot->num_inpixfmt) && rot->inpixfmts)
- return rot->inpixfmts[index];
+ if ((index < rot->num_inpixfmt[mode]) && rot->inpixfmts[mode])
+ return rot->inpixfmts[mode][index];
else
return 0;
} else {
- if ((index < rot->num_outpixfmt) && rot->outpixfmts)
- return rot->outpixfmts[index];
+ if ((index < rot->num_outpixfmt[mode]) && rot->outpixfmts[mode])
+ return rot->outpixfmts[mode][index];
else
return 0;
}
@@ -3086,12 +3125,13 @@
* @mgr: Pointer to rotator manager
* @pixfmt: pixel format to be verified
* @input: true for input port; false for output port
+ * @mode: operating mode
*/
static int sde_hw_rotator_is_valid_pixfmt(struct sde_rot_mgr *mgr, u32 pixfmt,
- bool input)
+ bool input, u32 mode)
{
struct sde_hw_rotator *rot;
- u32 *pixfmts;
+ const u32 *pixfmts;
u32 num_pixfmt;
int i;
@@ -3102,12 +3142,17 @@
rot = mgr->hw_data;
+ if (mode >= SDE_ROTATOR_MODE_MAX) {
+ SDEROT_ERR("invalid rotator mode %d\n", mode);
+ return false;
+ }
+
if (input) {
- pixfmts = rot->inpixfmts;
- num_pixfmt = rot->num_inpixfmt;
+ pixfmts = rot->inpixfmts[mode];
+ num_pixfmt = rot->num_inpixfmt[mode];
} else {
- pixfmts = rot->outpixfmts;
- num_pixfmt = rot->num_outpixfmt;
+ pixfmts = rot->outpixfmts[mode];
+ num_pixfmt = rot->num_outpixfmt[mode];
}
if (!pixfmts || !num_pixfmt) {
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h
index 67f7f4b..4c1316c 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h
@@ -259,10 +259,10 @@
* @sbuf_ctx: list of active sbuf context in FIFO order
* @vid_trigger: video mode trigger select
* @cmd_trigger: command mode trigger select
- * @inpixfmts: array of supported input pixel formats forucc
- * @num_inpixfmt: size of the supported input pixel format array
- * @outpixfmts: array of supported output pixel formats in fourcc
- * @num_outpixfmt: size of the supported output pixel formats array
+ * @inpixfmts: array of supported input pixel formats fourcc per mode
+ * @num_inpixfmt: size of the supported input pixel format array per mode
+ * @outpixfmts: array of supported output pixel formats in fourcc per mode
+ * @num_outpixfmt: size of the supported output pixel formats array per mode
* @downscale_caps: capability string of scaling
* @maxlinewidth: maximum line width supported
*/
@@ -320,10 +320,10 @@
struct list_head sbuf_ctx[ROT_QUEUE_MAX];
- u32 *inpixfmts;
- u32 num_inpixfmt;
- u32 *outpixfmts;
- u32 num_outpixfmt;
+ const u32 *inpixfmts[SDE_ROTATOR_MODE_MAX];
+ u32 num_inpixfmt[SDE_ROTATOR_MODE_MAX];
+ const u32 *outpixfmts[SDE_ROTATOR_MODE_MAX];
+ u32 num_outpixfmt[SDE_ROTATOR_MODE_MAX];
const char *downscale_caps;
u32 maxlinewidth;
};
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_trace.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_trace.h
index 691e2ec..5ba37b3 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_trace.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_trace.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014, 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014, 2015-2017, The Linux Foundation. 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 and
@@ -295,6 +295,40 @@
);
+#define SDE_ROT_TRACE_EVTLOG_SIZE 15
+TRACE_EVENT(sde_rot_evtlog,
+ TP_PROTO(const char *tag, u32 tag_id, u32 cnt, u32 data[]),
+ TP_ARGS(tag, tag_id, cnt, data),
+ TP_STRUCT__entry(
+ __field(int, pid)
+ __string(evtlog_tag, tag)
+ __field(u32, tag_id)
+ __array(u32, data, SDE_ROT_TRACE_EVTLOG_SIZE)
+ ),
+ TP_fast_assign(
+ __entry->pid = current->tgid;
+ __assign_str(evtlog_tag, tag);
+ __entry->tag_id = tag_id;
+ if (cnt > SDE_ROT_TRACE_EVTLOG_SIZE)
+ cnt = SDE_ROT_TRACE_EVTLOG_SIZE;
+ memcpy(__entry->data, data, cnt * sizeof(u32));
+ memset(&__entry->data[cnt], 0,
+ (SDE_ROT_TRACE_EVTLOG_SIZE - cnt) *
+ sizeof(u32));
+ ),
+ TP_printk("%d|%s:%d|%x|%x|%x|%x|%x|%x|%x|%x|%x|%x|%x|%x|%x|%x|%x",
+ __entry->pid, __get_str(evtlog_tag),
+ __entry->tag_id,
+ __entry->data[0], __entry->data[1],
+ __entry->data[2], __entry->data[3],
+ __entry->data[4], __entry->data[5],
+ __entry->data[6], __entry->data[7],
+ __entry->data[8], __entry->data[9],
+ __entry->data[10], __entry->data[11],
+ __entry->data[12], __entry->data[13],
+ __entry->data[14])
+)
+
#endif /* if !defined(TRACE_SDE_ROTATOR_H) ||
* defined(TRACE_HEADER_MULTI_READ)
*/
diff --git a/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c b/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c
index a7b1852..45e8771 100644
--- a/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c
+++ b/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c
@@ -330,7 +330,9 @@
*/
/* Decoder parameters */
int width, height, lcu_size, dpb_bpp, opb_bpp, fps, opb_factor;
- bool unified_dpb_opb, dpb_compression_enabled, opb_compression_enabled;
+ bool unified_dpb_opb, dpb_compression_enabled, opb_compression_enabled,
+ llc_ref_read_l2_cache_enabled = false,
+ llc_vpss_ds_line_buf_enabled = false;
fp_t dpb_opb_scaling_ratio, dpb_read_compression_factor,
dpb_write_compression_factor, opb_compression_factor,
qsmmu_bw_overhead_factor, height_ratio;
@@ -342,7 +344,8 @@
fp_t bins_to_bit_factor, dpb_write_factor, ten_bpc_packing_factor,
ten_bpc_bpp_factor, vsp_read_factor, vsp_write_factor,
bw_for_1x_8bpc, dpb_bw_for_1x,
- motion_vector_complexity = 0, row_cache_penalty = 0, opb_bw = 0;
+ motion_vector_complexity = 0, row_cache_penalty = 0, opb_bw = 0,
+ dpb_total = 0;
/* Output parameters */
struct {
@@ -352,6 +355,10 @@
total;
} ddr = {0};
+ struct {
+ fp_t dpb_read, opb_read, total;
+ } llc = {0};
+
unsigned long ret = 0;
unsigned int integer_part, frac_part;
@@ -407,6 +414,11 @@
opb_compression_factor = !opb_compression_enabled ? FP_ONE :
__compression_ratio(__lut(width, height, fps), opb_bpp);
+ llc_ref_read_l2_cache_enabled = llc_vpss_ds_line_buf_enabled = false;
+ if (d->use_sys_cache) {
+ llc_ref_read_l2_cache_enabled = true;
+ llc_vpss_ds_line_buf_enabled = true;
+ }
/* Derived parameters setup */
lcu_per_frame = DIV_ROUND_UP(width, lcu_size) *
@@ -462,6 +474,12 @@
ddr.dpb_write = fp_div(fp_mult(dpb_bw_for_1x, dpb_write_factor),
dpb_write_compression_factor);
+ dpb_total = ddr.dpb_read + ddr.dpb_write;
+ if (llc_ref_read_l2_cache_enabled) {
+ row_cache_penalty = FP(1, 30, 100);
+ ddr.dpb_read = fp_div(ddr.dpb_read, row_cache_penalty);
+ llc.dpb_read = dpb_total - ddr.dpb_read;
+ }
opb_factor = dpb_bpp == 8 ? 8 : 4;
@@ -473,6 +491,11 @@
FP(1, 50, 100)), dpb_opb_scaling_ratio),
opb_compression_factor);
+ if (llc_vpss_ds_line_buf_enabled) {
+ llc.opb_read = ddr.opb_read;
+ ddr.opb_write -= ddr.opb_read;
+ ddr.opb_read = 0;
+ }
ddr.total = ddr.vsp_read + ddr.vsp_write +
ddr.collocated_read + ddr.collocated_write +
ddr.opb_read + ddr.opb_write +
@@ -481,6 +504,7 @@
qsmmu_bw_overhead_factor = FP(1, 3, 100);
ddr.total = fp_mult(ddr.total, qsmmu_bw_overhead_factor);
+ llc.total = llc.dpb_read + llc.opb_read;
/* Dump all the variables for easier debugging */
if (debug) {
@@ -521,6 +545,8 @@
{"DERIVED PARAMETERS (2)", "", DUMP_HEADER_MAGIC},
{"MV complexity", DUMP_FP_FMT, motion_vector_complexity},
{"row cache penalty", DUMP_FP_FMT, row_cache_penalty},
+ {"qsmmu_bw_overhead_factor", DUMP_FP_FMT,
+ qsmmu_bw_overhead_factor},
{"OPB B/W (single instance)", DUMP_FP_FMT, opb_bw},
{"INTERMEDIATE DDR B/W", "", DUMP_HEADER_MAGIC},
@@ -536,6 +562,8 @@
{"OPB write", DUMP_FP_FMT, ddr.opb_write},
{"DPB read", DUMP_FP_FMT, ddr.dpb_read},
{"DPB write", DUMP_FP_FMT, ddr.dpb_write},
+ {"LLC DPB read", DUMP_FP_FMT, llc.dpb_read},
+ {"LLC OPB read", DUMP_FP_FMT, llc.opb_read},
};
__dump(dump, ARRAY_SIZE(dump));
@@ -546,7 +574,7 @@
ret = kbps(fp_round(ddr.total));
break;
case GOVERNOR_LLCC:
- dprintk(VIDC_PROF, "LLCC Voting not supported yet\n");
+ ret = kbps(fp_round(llc.total));
break;
default:
dprintk(VIDC_ERR, "%s - Unknown governor\n", __func__);
@@ -565,32 +593,25 @@
*/
/* Encoder Parameters */
- enum hal_video_codec standard;
- int width, height, fps;
- enum hal_uncompressed_format dpb_color_format;
- enum hal_uncompressed_format original_color_format;
+ int width, height, fps, dpb_bpp, lcu_per_frame, lcu_size,
+ vertical_tile_width, colocated_bytes_per_lcu, bitrate,
+ ref_overlap_bw_factor;
+ enum hal_uncompressed_format dpb_color_format, original_color_format;
bool dpb_compression_enabled, original_compression_enabled,
- two_stage_encoding, low_power, rotation, cropping_or_scaling;
+ work_mode_1, low_power, rotation, cropping_or_scaling,
+ b_frames_enabled = false,
+ llc_dual_core_ref_read_buf_enabled = false,
+ llc_top_line_buf_enabled = false,
+ llc_ref_chroma_cache_enabled = false;
fp_t dpb_compression_factor, original_compression_factor,
- qsmmu_bw_overhead_factor;
- bool b_frames_enabled;
-
- /* Derived Parameters */
- int lcu_size;
- enum gop {
- GOP_IBBP,
- GOP_IPPP,
- } gop;
- unsigned long bitrate;
- fp_t bins_to_bit_factor, chroma_luma_factor_dpb, one_frame_bw_dpb,
- chroma_luma_factor_original, one_frame_bw_original,
- line_buffer_size_per_lcu, line_buffer_size, line_buffer_bw,
- bw_increase_p, bw_increase_b;
- int collocated_mv_per_lcu, max_transaction_size,
- search_window_size_vertical_p, search_window_factor_p,
- search_window_factor_bw_p,
- search_window_size_vertical_b, search_window_factor_b,
- search_window_factor_bw_b;
+ input_compression_factor, qsmmu_bw_overhead_factor,
+ ref_y_bw_factor, ref_cb_cr_bw_factor, ten_bpc_bpp_factor,
+ bw_for_1x_8bpc, dpb_bw_for_1x, ref_cb_cr_read,
+ bins_to_bit_factor, ref_y_read, ten_bpc_packing_factor,
+ dpb_write_factor, ref_overlap_bw, llc_ref_y_read,
+ llc_ref_cb_cr_read;
+ fp_t integer_part, frac_part;
+ unsigned long ret = 0;
/* Output paramaters */
struct {
@@ -599,27 +620,49 @@
original_write, dpb_read, dpb_write, total;
} ddr = {0};
- unsigned long ret = 0;
- fp_t integer_part, frac_part;
+ struct {
+ fp_t dpb_read, line_buffer, total;
+ } llc = {0};
/* Encoder Parameters setup */
+ ten_bpc_packing_factor = FP(1, 67, 1000);
+ ten_bpc_bpp_factor = FP(1, 1, 4);
+ rotation = false;
+ cropping_or_scaling = false;
+ vertical_tile_width = 960;
+ ref_y_bw_factor = FP(1, 30, 100);
+ ref_cb_cr_bw_factor = FP(1, 50, 100);
+ dpb_write_factor = FP(1, 8, 100);
- standard = d->codec;
+
+ /* Derived Parameters */
+ lcu_size = d->lcu_size;
+ fps = d->fps;
+ b_frames_enabled = d->b_frames_enabled;
width = max(d->input_width, BASELINE_DIMENSIONS.width);
height = max(d->input_height, BASELINE_DIMENSIONS.height);
+ bitrate = __lut(width, height, fps)->bitrate;
+ lcu_per_frame = DIV_ROUND_UP(width, lcu_size) *
+ DIV_ROUND_UP(height, lcu_size);
dpb_color_format = HAL_COLOR_FORMAT_NV12_UBWC;
original_color_format = d->num_formats >= 1 ?
d->color_formats[0] : HAL_UNUSED_COLOR;
- fps = d->fps;
+ dpb_bpp = d->num_formats >= 1 ? __bpp(d->color_formats[0]) : INT_MAX;
dpb_compression_enabled = __ubwc(dpb_color_format);
original_compression_enabled = __ubwc(original_color_format);
- two_stage_encoding = false;
+ work_mode_1 = d->work_mode == VIDC_WORK_MODE_1;
low_power = d->power_mode == VIDC_POWER_LOW;
- b_frames_enabled = false;
+ bins_to_bit_factor = work_mode_1 ?
+ FP_INT(0) : FP_INT(4);
+
+ if (d->use_sys_cache) {
+ llc_dual_core_ref_read_buf_enabled = true;
+ llc_ref_chroma_cache_enabled = true;
+ }
/*
* Convert Q16 number into Integer and Fractional part upto 2 places.
@@ -636,96 +679,106 @@
dpb_compression_factor = FP(integer_part, frac_part, 100);
- original_compression_factor = dpb_compression_factor;
+ integer_part = d->input_cr >> 16;
+ frac_part =
+ ((d->input_cr - (integer_part * 65536)) * 100) >> 16;
- rotation = false;
- cropping_or_scaling = false;
+ input_compression_factor = FP(integer_part, frac_part, 100);
- /* Derived Parameters */
- lcu_size = 16;
- gop = b_frames_enabled ? GOP_IBBP : GOP_IPPP;
- bitrate = __lut(width, height, fps)->bitrate;
- bins_to_bit_factor = FP(1, 6, 10);
+ original_compression_factor =
+ original_compression_enabled ? d->use_dpb_read ?
+ dpb_compression_factor : input_compression_factor :
+ FP_ONE;
- /*
- * FIXME: Minor color format related hack: a lot of the derived params
- * depend on the YUV bitdepth as a variable. However, we don't have
- * appropriate enums defined yet (hence no support). As a result omit
- * a lot of the checks (which should look like the snippet below) in
- * favour of hardcoding.
- * dpb_color_format == YUV420 ? 0.5 :
- * dpb_color_format == YUV422 ? 1.0 : 2.0
- * Similar hacks are annotated inline in code with the string "CF hack"
- * for documentation purposes.
- */
- chroma_luma_factor_dpb = FP(0, 1, 2);
- one_frame_bw_dpb = fp_mult(FP_ONE + chroma_luma_factor_dpb,
- fp_div(FP_INT(width * height * fps),
- FP_INT(1000 * 1000)));
-
- chroma_luma_factor_original = FP(0, 1, 2); /* XXX: CF hack */
- one_frame_bw_original = fp_mult(FP_ONE + chroma_luma_factor_original,
- fp_div(FP_INT(width * height * fps),
- FP_INT(1000 * 1000)));
-
- line_buffer_size_per_lcu = FP_ZERO;
- if (lcu_size == 16)
- line_buffer_size_per_lcu = FP_INT(128) + fp_mult(FP_INT(256),
- FP_ONE /*XXX: CF hack */);
- else
- line_buffer_size_per_lcu = FP_INT(192) + fp_mult(FP_INT(512),
- FP_ONE /*XXX: CF hack */);
-
- line_buffer_size = fp_div(
- fp_mult(FP_INT(width / lcu_size),
- line_buffer_size_per_lcu),
- FP_INT(1024));
- line_buffer_bw = fp_mult(line_buffer_size,
- fp_div(FP_INT((height / lcu_size /
- (two_stage_encoding ? 2 : 1) - 1) * fps),
- FP_INT(1000)));
-
- collocated_mv_per_lcu = lcu_size == 16 ? 16 : 64;
- max_transaction_size = 256;
-
- search_window_size_vertical_p = low_power ? 32 :
- b_frames_enabled ? 80 :
- width > 2048 ? 64 : 48;
- search_window_factor_p = search_window_size_vertical_p * 2 / lcu_size;
- search_window_factor_bw_p = !two_stage_encoding ?
- search_window_size_vertical_p * 2 / lcu_size + 1 :
- (search_window_size_vertical_p * 2 / lcu_size + 2) / 2;
- bw_increase_p = fp_mult(one_frame_bw_dpb,
- FP_INT(search_window_factor_bw_p - 1) / 3);
-
- search_window_size_vertical_b = 48;
- search_window_factor_b = search_window_size_vertical_b * 2 / lcu_size;
- search_window_factor_bw_b = !two_stage_encoding ?
- search_window_size_vertical_b * 2 / lcu_size + 1 :
- (search_window_size_vertical_b * 2 / lcu_size + 2) / 2;
- bw_increase_b = fp_mult(one_frame_bw_dpb,
- FP_INT((search_window_factor_bw_b - 1) / 3));
-
- /* Output parameters for DDR */
ddr.vsp_read = fp_mult(fp_div(FP_INT(bitrate), FP_INT(8)),
bins_to_bit_factor);
ddr.vsp_write = ddr.vsp_read + fp_div(FP_INT(bitrate), FP_INT(8));
- ddr.collocated_read = fp_div(FP_INT(DIV_ROUND_UP(width, lcu_size) *
- DIV_ROUND_UP(height, lcu_size) *
- collocated_mv_per_lcu * fps), FP_INT(1000 * 1000));
+ colocated_bytes_per_lcu = lcu_size == 16 ? 16 :
+ lcu_size == 32 ? 64 : 256;
+
+ ddr.collocated_read = FP_INT(lcu_per_frame *
+ colocated_bytes_per_lcu * fps / bps(1));
+
ddr.collocated_write = ddr.collocated_read;
+ ddr.line_buffer_read = FP_INT(16 * lcu_per_frame * fps / bps(1));
+
ddr.line_buffer_write = ddr.line_buffer_read;
- ddr.original_read = fp_div(one_frame_bw_original,
- original_compression_factor);
+ llc.line_buffer = ddr.line_buffer_read + ddr.line_buffer_write;
+ if (llc_top_line_buf_enabled)
+ ddr.line_buffer_read = ddr.line_buffer_write = FP_INT(0);
+
+ llc.line_buffer -= (ddr.line_buffer_read + ddr.line_buffer_write);
+
+ bw_for_1x_8bpc = fp_div(FP_INT(width * height), FP_INT(32 * 8));
+
+ bw_for_1x_8bpc = fp_mult(bw_for_1x_8bpc,
+ fp_div(FP_INT(256 * 30), FP_INT(1000 * 1000)));
+
+ dpb_bw_for_1x = dpb_bpp == 8 ? bw_for_1x_8bpc :
+ fp_mult(bw_for_1x_8bpc, fp_mult(ten_bpc_packing_factor,
+ ten_bpc_bpp_factor));
+
+ ddr.original_read = fp_div(fp_mult(FP(1, 50, 100), dpb_bw_for_1x),
+ input_compression_factor);
+
ddr.original_write = FP_ZERO;
- ddr.dpb_read = FP_ZERO;
+ ref_y_bw_factor =
+ width == vertical_tile_width ? FP_INT(1) : ref_y_bw_factor;
- ddr.dpb_read = fp_div(ddr.dpb_read, dpb_compression_factor);
- ddr.dpb_write = fp_div(one_frame_bw_dpb, dpb_compression_factor);
+ ref_y_read = fp_mult(ref_y_bw_factor, dpb_bw_for_1x);
+
+ ref_y_read = fp_div(ref_y_read, dpb_compression_factor);
+
+ ref_y_read =
+ b_frames_enabled ? fp_mult(ref_y_read, FP_INT(2)) : ref_y_read;
+
+ llc_ref_y_read = ref_y_read;
+ if (llc_dual_core_ref_read_buf_enabled)
+ ref_y_read = fp_div(ref_y_read, FP_INT(2));
+
+ llc_ref_y_read -= ref_y_read;
+
+ ref_cb_cr_read = fp_mult(ref_cb_cr_bw_factor, dpb_bw_for_1x);
+
+ ref_cb_cr_read = fp_div(ref_cb_cr_read, dpb_compression_factor);
+
+ ref_cb_cr_read =
+ b_frames_enabled ? fp_mult(ref_cb_cr_read, FP_INT(2)) :
+ ref_cb_cr_read;
+
+ llc_ref_cb_cr_read = ref_cb_cr_read;
+
+ if (llc_ref_chroma_cache_enabled)
+ ref_cb_cr_read = fp_div(ref_cb_cr_read, ref_cb_cr_bw_factor);
+
+ if (llc_dual_core_ref_read_buf_enabled)
+ ref_cb_cr_read = fp_div(ref_cb_cr_read, FP_INT(2));
+
+ llc_ref_cb_cr_read -= ref_cb_cr_read;
+
+ ddr.dpb_write = fp_mult(dpb_write_factor, dpb_bw_for_1x);
+
+ ddr.dpb_write = fp_mult(ddr.dpb_write, FP(1, 50, 100));
+
+ ddr.dpb_write = fp_div(ddr.dpb_write, input_compression_factor);
+
+ ref_overlap_bw_factor =
+ width <= vertical_tile_width ? FP_INT(0) : FP_INT(1);
+
+ ref_overlap_bw = fp_mult(ddr.dpb_write, ref_overlap_bw_factor);
+
+ ref_overlap_bw = fp_div(ref_overlap_bw, dpb_write_factor);
+
+ ref_overlap_bw = fp_mult(ref_overlap_bw,
+ (dpb_write_factor - FP_INT(1)));
+
+ ddr.dpb_read = ref_y_read + ref_cb_cr_read + ref_overlap_bw;
+
+ llc.dpb_read = llc_ref_y_read + llc_ref_cb_cr_read;
ddr.total = ddr.vsp_read + ddr.vsp_write +
ddr.collocated_read + ddr.collocated_write +
@@ -733,13 +786,14 @@
ddr.original_read + ddr.original_write +
ddr.dpb_read + ddr.dpb_write;
+ llc.total = llc.dpb_read + llc.line_buffer;
+
qsmmu_bw_overhead_factor = FP(1, 3, 100);
ddr.total = fp_mult(ddr.total, qsmmu_bw_overhead_factor);
if (debug) {
struct dump dump[] = {
{"ENCODER PARAMETERS", "", DUMP_HEADER_MAGIC},
- {"standard", "%#x", standard},
{"width", "%d", width},
{"height", "%d", height},
{"DPB format", "%#x", dpb_color_format},
@@ -748,8 +802,8 @@
{"DPB compression enable", "%d", dpb_compression_enabled},
{"original compression enable", "%d",
original_compression_enabled},
- {"two stage encoding", "%d", two_stage_encoding},
{"low power mode", "%d", low_power},
+ {"Work Mode", "%d", work_mode_1},
{"DPB compression factor", DUMP_FP_FMT,
dpb_compression_factor},
{"original compression factor", DUMP_FP_FMT,
@@ -759,46 +813,27 @@
{"DERIVED PARAMETERS", "", DUMP_HEADER_MAGIC},
{"LCU size", "%d", lcu_size},
- {"GOB pattern", "%d", gop},
{"bitrate (Mbit/sec)", "%lu", bitrate},
{"bins to bit factor", DUMP_FP_FMT, bins_to_bit_factor},
- {"B-frames enabled", "%d", b_frames_enabled},
- {"search window size vertical (B)", "%d",
- search_window_size_vertical_b},
- {"search window factor (B)", "%d", search_window_factor_b},
- {"search window factor BW (B)", "%d",
- search_window_factor_bw_b},
- {"bw increase (MB/s) (B)", DUMP_FP_FMT, bw_increase_b},
- {"search window size vertical (P)", "%d",
- search_window_size_vertical_p},
- {"search window factor (P)", "%d", search_window_factor_p},
- {"search window factor BW (P)", "%d",
- search_window_factor_bw_p},
- {"bw increase (MB/s) (P)", DUMP_FP_FMT, bw_increase_p},
- {"chroma/luma factor DPB", DUMP_FP_FMT,
- chroma_luma_factor_dpb},
- {"one frame BW DPB (MB/s)", DUMP_FP_FMT, one_frame_bw_dpb},
- {"chroma/Luma factor original", DUMP_FP_FMT,
- chroma_luma_factor_original},
- {"one frame BW original (MB/s)", DUMP_FP_FMT,
- one_frame_bw_original},
- {"line buffer size per LCU", DUMP_FP_FMT,
- line_buffer_size_per_lcu},
- {"line buffer size (KB)", DUMP_FP_FMT, line_buffer_size},
- {"line buffer BW (MB/s)", DUMP_FP_FMT, line_buffer_bw},
- {"collocated MVs per LCU", "%d", collocated_mv_per_lcu},
+ {"qsmmu_bw_overhead_factor",
+ DUMP_FP_FMT, qsmmu_bw_overhead_factor},
{"INTERMEDIATE B/W DDR", "", DUMP_HEADER_MAGIC},
+ {"ref_y_read", DUMP_FP_FMT, ref_y_read},
+ {"ref_cb_cr_read", DUMP_FP_FMT, ref_cb_cr_read},
+ {"ref_overlap_bw", DUMP_FP_FMT, ref_overlap_bw},
{"VSP read", DUMP_FP_FMT, ddr.vsp_read},
- {"VSP read", DUMP_FP_FMT, ddr.vsp_write},
+ {"VSP write", DUMP_FP_FMT, ddr.vsp_write},
{"collocated read", DUMP_FP_FMT, ddr.collocated_read},
- {"collocated read", DUMP_FP_FMT, ddr.collocated_write},
+ {"collocated write", DUMP_FP_FMT, ddr.collocated_write},
{"line buffer read", DUMP_FP_FMT, ddr.line_buffer_read},
- {"line buffer read", DUMP_FP_FMT, ddr.line_buffer_write},
+ {"line buffer write", DUMP_FP_FMT, ddr.line_buffer_write},
{"original read", DUMP_FP_FMT, ddr.original_read},
- {"original read", DUMP_FP_FMT, ddr.original_write},
+ {"original write", DUMP_FP_FMT, ddr.original_write},
{"DPB read", DUMP_FP_FMT, ddr.dpb_read},
{"DPB write", DUMP_FP_FMT, ddr.dpb_write},
+ {"LLC DPB read", DUMP_FP_FMT, llc.dpb_read},
+ {"LLC Line buffer", DUMP_FP_FMT, llc.line_buffer},
};
__dump(dump, ARRAY_SIZE(dump));
}
@@ -808,7 +843,7 @@
ret = kbps(fp_round(ddr.total));
break;
case GOVERNOR_LLCC:
- dprintk(VIDC_PROF, "LLCC Voting not supported yet\n");
+ ret = kbps(fp_round(llc.total));
break;
default:
dprintk(VIDC_ERR, "%s - Unknown governor\n", __func__);
@@ -866,6 +901,7 @@
exit:
*freq = clamp(ab_kbps, dev->min_freq, dev->max_freq ?: UINT_MAX);
+ trace_msm_vidc_perf_bus_vote(gov->devfreq_gov.name, *freq);
return 0;
}
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index 32e79f2..4512409 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -164,6 +164,9 @@
case HFI_VIDEO_CODEC_VP9:
hal_codec = HAL_VIDEO_CODEC_VP9;
break;
+ case HFI_VIDEO_CODEC_TME:
+ hal_codec = HAL_VIDEO_CODEC_TME;
+ break;
default:
dprintk(VIDC_INFO, "%s: invalid codec 0x%x\n",
__func__, hfi_codec);
@@ -220,6 +223,9 @@
case HAL_VIDEO_CODEC_VP9:
hfi_codec = HFI_VIDEO_CODEC_VP9;
break;
+ case HAL_VIDEO_CODEC_TME:
+ hfi_codec = HFI_VIDEO_CODEC_TME;
+ break;
default:
dprintk(VIDC_INFO, "%s: invalid codec 0x%x\n",
__func__, hal_codec);
@@ -1238,10 +1244,8 @@
pkt->rg_property_data[1] = HFI_RATE_CONTROL_CBR_VFR;
break;
case HAL_RATE_CONTROL_VBR_CFR:
- pkt->rg_property_data[1] = HFI_RATE_CONTROL_VBR_CFR;
- break;
case HAL_RATE_CONTROL_VBR_VFR:
- pkt->rg_property_data[1] = HFI_RATE_CONTROL_VBR_VFR;
+ pkt->rg_property_data[1] = HFI_RATE_CONTROL_VBR_CFR;
break;
case HAL_RATE_CONTROL_MBR_CFR:
pkt->rg_property_data[1] = HFI_RATE_CONTROL_MBR_CFR;
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index e5d1576..52b9b32 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -775,6 +775,47 @@
return size;
}
+static int copy_profile_caps_to_sessions(struct hfi_profile_level *prof,
+ u32 profile_count, struct msm_vidc_capability *capabilities,
+ u32 num_sessions, u32 codecs, u32 domain)
+{
+ u32 i = 0, j = 0;
+ struct msm_vidc_capability *capability;
+ u32 sess_codec;
+ u32 sess_domain;
+
+ /*
+ * iterate over num_sessions and copy all the profile capabilities
+ * to matching sessions.
+ */
+ for (i = 0; i < num_sessions; i++) {
+ sess_codec = 0;
+ sess_domain = 0;
+ capability = &capabilities[i];
+
+ if (capability->codec)
+ sess_codec =
+ vidc_get_hfi_codec(capability->codec);
+ if (capability->domain)
+ sess_domain =
+ vidc_get_hfi_domain(capability->domain);
+
+ if (!(sess_codec & codecs && sess_domain & domain))
+ continue;
+
+ capability->profile_level.profile_count = profile_count;
+ for (j = 0; j < profile_count; j++) {
+ /* HFI and HAL follow same enums, hence no conversion */
+ capability->profile_level.profile_level[j].profile =
+ prof[j].profile;
+ capability->profile_level.profile_level[j].level =
+ prof[j].level;
+ }
+ }
+
+ return 0;
+}
+
static int copy_caps_to_sessions(struct hfi_capability_supported *cap,
u32 num_caps, struct msm_vidc_capability *capabilities,
u32 num_sessions, u32 codecs, u32 domain)
@@ -914,38 +955,25 @@
}
case HFI_PROPERTY_PARAM_PROFILE_LEVEL_SUPPORTED:
{
- struct msm_vidc_capability capability;
- char *ptr = NULL;
- u32 count = 0;
- u32 prof_count = 0;
- struct hfi_profile_level *prof_level;
struct hfi_profile_level_supported *prop =
(struct hfi_profile_level_supported *)
(data_ptr + next_offset);
- ptr = (char *) &prop->rg_profile_level[0];
- prof_count = prop->profile_count;
- next_offset += sizeof(u32);
+ next_offset += sizeof(u32) +
+ prop->profile_count *
+ sizeof(struct hfi_profile_level);
- if (prof_count > MAX_PROFILE_COUNT) {
- prof_count = MAX_PROFILE_COUNT;
+ if (prop->profile_count > MAX_PROFILE_COUNT) {
+ prop->profile_count = MAX_PROFILE_COUNT;
dprintk(VIDC_WARN,
"prop count exceeds max profile count\n");
break;
}
- while (prof_count) {
- prof_level = (struct hfi_profile_level *)ptr;
- capability.
- profile_level.profile_level[count].profile
- = prof_level->profile;
- capability.
- profile_level.profile_level[count].level
- = prof_level->level;
- prof_count--;
- count++;
- ptr += sizeof(struct hfi_profile_level);
- next_offset += sizeof(struct hfi_profile_level);
- }
+
+ copy_profile_caps_to_sessions(
+ &prop->rg_profile_level[0],
+ prop->profile_count, capabilities,
+ num_sessions, codecs, domain);
num_properties--;
break;
}
@@ -969,6 +997,15 @@
num_properties--;
break;
}
+ case HFI_PROPERTY_TME_VERSION_SUPPORTED:
+ {
+ capabilities->tme_version =
+ *((u32 *)(data_ptr + next_offset));
+ next_offset +=
+ sizeof(u32);
+ num_properties--;
+ break;
+ }
default:
dprintk(VIDC_DBG,
"%s: default case - data_ptr %pK, prop_id 0x%x\n",
@@ -1140,6 +1177,12 @@
buffreq->buffer[10].buffer_type =
HAL_BUFFER_INTERNAL_PERSIST_1;
break;
+ case HFI_BUFFER_COMMON_INTERNAL_RECON:
+ memcpy(&buffreq->buffer[11], hfi_buf_req,
+ sizeof(struct hfi_buffer_requirements));
+ buffreq->buffer[11].buffer_type =
+ HAL_BUFFER_INTERNAL_RECON;
+ break;
default:
dprintk(VIDC_ERR,
"hal_process_sess_get_prop_buf_req: bad_buffer_type: %d\n",
diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
index 8c63469..54766a2 100644
--- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
@@ -347,6 +347,14 @@
}
INIT_DELAYED_WORK(&core->fw_unload_work, msm_vidc_fw_unload_handler);
+
+ mutex_lock(&core->lock);
+ core->vote_data = kcalloc(MAX_SUPPORTED_INSTANCES,
+ sizeof(*core->vote_data), GFP_KERNEL);
+ if (!core->vote_data)
+ dprintk(VIDC_ERR, "%s: failed to allocate memory\n", __func__);
+ mutex_unlock(&core->lock);
+
return rc;
}
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 988f79c..f17f3da 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -373,6 +373,15 @@
.default_value = 0,
.step = OPERATING_FRAME_RATE_STEP,
},
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_MODE,
+ .name = "Low Latency Mode",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_DISABLE,
+ .maximum = V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_ENABLE,
+ .default_value = V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_DISABLE,
+ .step = 1,
+ },
};
#define NUM_CTRLS ARRAY_SIZE(msm_vdec_ctrls)
@@ -1062,6 +1071,14 @@
ctrl->val >> 16);
inst->clk_data.operating_rate = ctrl->val;
break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_MODE:
+ if (ctrl->val ==
+ V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_ENABLE)
+ hal_property.enable = 1;
+ else
+ hal_property.enable = 0;
+ inst->clk_data.low_latency_mode = (bool) hal_property.enable;
+ break;
default:
break;
}
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 5c587e2..03b4e4d 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -117,6 +117,17 @@
"Level unknown",
};
+static const char *const tme_profile[] = {
+ "0",
+ "1",
+ "2",
+ "3",
+};
+
+static const char *const tme_level[] = {
+ "Integer",
+};
+
static const char *const hevc_profile[] = {
"Main",
"Main10",
@@ -486,6 +497,46 @@
.qmenu = hevc_tier_level,
},
{
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_TME_PROFILE,
+ .name = "TME Profile",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_0,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_3,
+ .default_value =
+ V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_0,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_0) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_1) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_2) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_3)
+ ),
+ .qmenu = tme_profile,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_TME_LEVEL,
+ .name = "TME Level",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_TME_LEVEL_INTEGER,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_TME_LEVEL_INTEGER,
+ .default_value = V4L2_MPEG_VIDC_VIDEO_TME_LEVEL_INTEGER,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDC_VIDEO_TME_LEVEL_INTEGER)
+ ),
+ .qmenu = tme_level,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_TME_PAYLOAD_VERSION,
+ .name = "TME Payload Version",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = 0xFFFFFFF,
+ .default_value = 0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .flags = V4L2_CTRL_FLAG_READ_ONLY,
+ .qmenu = NULL,
+ },
+ {
.id = V4L2_CID_MPEG_VIDC_VIDEO_ROTATION,
.name = "Rotation",
.type = V4L2_CTRL_TYPE_MENU,
@@ -1064,6 +1115,13 @@
.get_frame_size = get_frame_size_tp10_ubwc,
.type = OUTPUT_PORT,
},
+ {
+ .name = "TME",
+ .description = "TME MBI format",
+ .fourcc = V4L2_PIX_FMT_TME,
+ .get_frame_size = get_frame_size_compressed,
+ .type = CAPTURE_PORT,
+ },
};
static int msm_venc_set_csc(struct msm_vidc_inst *inst);
@@ -1345,6 +1403,29 @@
temp_ctrl->val);
pdata = &profile_level;
break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_TME_PROFILE:
+ temp_ctrl =
+ TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_TME_LEVEL);
+
+ property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT;
+ profile_level.profile = msm_comm_v4l2_to_hal(ctrl->id,
+ ctrl->val);
+ profile_level.level = msm_comm_v4l2_to_hal(
+ V4L2_CID_MPEG_VIDC_VIDEO_TME_LEVEL,
+ temp_ctrl->val);
+ pdata = &profile_level;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_TME_LEVEL:
+ temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_TME_PROFILE);
+
+ property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT;
+ profile_level.level = msm_comm_v4l2_to_hal(ctrl->id,
+ ctrl->val);
+ profile_level.profile = msm_comm_v4l2_to_hal(
+ V4L2_CID_MPEG_VIDC_VIDEO_TME_PROFILE,
+ temp_ctrl->val);
+ pdata = &profile_level;
+ break;
case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION:
{
property_id = HAL_PARAM_VPE_ROTATION;
@@ -1553,23 +1634,25 @@
break;
}
- buff_req_buffer = get_buff_req_buffer(inst,
- HAL_BUFFER_EXTRADATA_INPUT);
-
extra_idx = EXTRADATA_IDX(inst->bufq[OUTPUT_PORT].num_planes);
+ if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
+ buff_req_buffer = get_buff_req_buffer(inst,
+ HAL_BUFFER_EXTRADATA_INPUT);
- inst->bufq[OUTPUT_PORT].plane_sizes[extra_idx] =
- buff_req_buffer ?
- buff_req_buffer->buffer_size : 0;
-
- buff_req_buffer = get_buff_req_buffer(inst,
- HAL_BUFFER_EXTRADATA_OUTPUT);
+ inst->bufq[OUTPUT_PORT].plane_sizes[extra_idx] =
+ buff_req_buffer ?
+ buff_req_buffer->buffer_size : 0;
+ }
extra_idx = EXTRADATA_IDX(inst->bufq[CAPTURE_PORT].num_planes);
- inst->bufq[CAPTURE_PORT].plane_sizes[extra_idx] =
- buff_req_buffer ?
- buff_req_buffer->buffer_size : 0;
+ if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
+ buff_req_buffer = get_buff_req_buffer(inst,
+ HAL_BUFFER_EXTRADATA_OUTPUT);
+ inst->bufq[CAPTURE_PORT].plane_sizes[extra_idx] =
+ buff_req_buffer ?
+ buff_req_buffer->buffer_size : 0;
+ }
property_id = 0;
}
break;
@@ -1597,7 +1680,7 @@
break;
case V4L2_CID_MPEG_VIDC_VIDEO_USELTRFRAME:
property_id = HAL_CONFIG_VENC_USELTRFRAME;
- use_ltr.ref_ltr = ctrl->val;
+ use_ltr.ref_ltr = 0x1 << ctrl->val;
use_ltr.use_constraint = false;
use_ltr.frames = 0;
pdata = &use_ltr;
@@ -2360,6 +2443,7 @@
rc = -EINVAL;
goto exit;
}
+ inst->clk_data.opb_fourcc = f->fmt.pix_mp.pixelformat;
memcpy(&inst->fmts[fmt->type], fmt,
sizeof(struct msm_vidc_format));
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 427568c..d08d40f 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -140,7 +140,8 @@
int msm_vidc_query_ctrl(void *instance, struct v4l2_queryctrl *ctrl)
{
struct msm_vidc_inst *inst = instance;
- int rc = 0;
+ struct hal_profile_level_supported *prof_level_supported;
+ int rc = 0, i = 0, profile_mask = 0, v4l2_prof_value = 0, max_level = 0;
if (!inst || !ctrl)
return -EINVAL;
@@ -178,6 +179,43 @@
case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
msm_vidc_ctrl_get_range(ctrl, &inst->capability.slice_bytes);
break;
+ case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+ case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE:
+ case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_PROFILE:
+ {
+ prof_level_supported = &inst->capability.profile_level;
+ for (i = 0; i < prof_level_supported->profile_count; i++) {
+ v4l2_prof_value = msm_comm_hal_to_v4l2(ctrl->id,
+ prof_level_supported->profile_level[i].profile);
+ if (v4l2_prof_value == -EINVAL) {
+ dprintk(VIDC_WARN, "Invalid profile");
+ rc = -EINVAL;
+ }
+ profile_mask |= (1 << v4l2_prof_value);
+ }
+ ctrl->flags = profile_mask;
+ break;
+ }
+ case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+ case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL:
+ case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL:
+ case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_LEVEL:
+ {
+ prof_level_supported = &inst->capability.profile_level;
+ for (i = 0; i < prof_level_supported->profile_count; i++) {
+ if (max_level < prof_level_supported->
+ profile_level[i].level) {
+ max_level = prof_level_supported->
+ profile_level[i].level;
+ }
+ }
+ ctrl->maximum = msm_comm_hal_to_v4l2(ctrl->id, max_level);
+ if (ctrl->maximum == -EINVAL) {
+ dprintk(VIDC_WARN, "Invalid max level");
+ rc = -EINVAL;
+ }
+ break;
+ }
default:
rc = -EINVAL;
}
@@ -426,6 +464,12 @@
if (vb2->type != type || vb2->index != index)
continue;
+ if (mbuf->flags & MSM_VIDC_FLAG_RBR_PENDING) {
+ print_vidc_buffer(VIDC_DBG,
+ "skip rel buf (rbr pending)", inst, mbuf);
+ continue;
+ }
+
print_vidc_buffer(VIDC_DBG, "release buf", inst, mbuf);
msm_comm_unmap_vidc_buffer(inst, mbuf);
list_del(&mbuf->list);
@@ -442,6 +486,7 @@
struct msm_vidc_inst *inst = instance;
int rc = 0, i = 0;
struct buf_queue *q = NULL;
+ u32 cr = 0;
if (!inst || !inst->core || !b || !valid_v4l2_buffer(b, inst)) {
dprintk(VIDC_ERR, "%s: invalid params, inst %pK\n",
@@ -453,8 +498,16 @@
b->m.planes[i].m.fd = b->m.planes[i].reserved[0];
b->m.planes[i].data_offset = b->m.planes[i].reserved[1];
}
+
msm_comm_qbuf_cache_operations(inst, b);
+ /* Compression ratio is valid only for Encoder YUV buffers. */
+ if (inst->session_type == MSM_VIDC_ENCODER &&
+ b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ cr = b->m.planes[0].reserved[2];
+ msm_comm_update_input_cr(inst, b->index, cr);
+ }
+
q = msm_comm_get_vb2q(inst, b->type);
if (!q) {
dprintk(VIDC_ERR,
@@ -712,7 +765,6 @@
rc = set_buffer_count(inst, bufreq->buffer_count_min_host,
bufreq->buffer_count_actual, HAL_BUFFER_INPUT);
}
-
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: {
buffer_type = msm_comm_get_hal_output_buffer(inst);
@@ -1116,7 +1168,7 @@
q->mem_ops = &msm_vidc_vb2_mem_ops;
q->drv_priv = inst;
- q->allow_zero_bytesused = 1;
+ q->allow_zero_bytesused = !V4L2_TYPE_IS_OUTPUT(type);
q->copy_timestamp = 1;
return vb2_queue_init(q);
}
@@ -1401,6 +1453,9 @@
}
ctrl->val = bufreq->buffer_count_min_host;
break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_TME_PAYLOAD_VERSION:
+ ctrl->val = inst->capability.tme_version;
+ break;
default:
/*
* Other controls aren't really volatile, shouldn't need to
@@ -1494,11 +1549,13 @@
INIT_MSM_VIDC_LIST(&inst->scratchbufs);
INIT_MSM_VIDC_LIST(&inst->freqs);
+ INIT_MSM_VIDC_LIST(&inst->input_crs);
INIT_MSM_VIDC_LIST(&inst->persistbufs);
INIT_MSM_VIDC_LIST(&inst->pending_getpropq);
INIT_MSM_VIDC_LIST(&inst->outputbufs);
INIT_MSM_VIDC_LIST(&inst->registeredbufs);
INIT_MSM_VIDC_LIST(&inst->reconbufs);
+ INIT_MSM_VIDC_LIST(&inst->eosbufs);
kref_init(&inst->kref);
@@ -1603,6 +1660,9 @@
DEINIT_MSM_VIDC_LIST(&inst->pending_getpropq);
DEINIT_MSM_VIDC_LIST(&inst->outputbufs);
DEINIT_MSM_VIDC_LIST(&inst->registeredbufs);
+ DEINIT_MSM_VIDC_LIST(&inst->eosbufs);
+ DEINIT_MSM_VIDC_LIST(&inst->freqs);
+ DEINIT_MSM_VIDC_LIST(&inst->input_crs);
kfree(inst);
inst = NULL;
@@ -1632,6 +1692,8 @@
msm_comm_free_freq_table(inst);
+ msm_comm_free_input_cr_table(inst);
+
if (msm_comm_release_scratch_buffers(inst, false))
dprintk(VIDC_ERR,
"Failed to release scratch buffers\n");
@@ -1650,6 +1712,8 @@
*/
msm_comm_validate_output_buffers(inst);
+ msm_comm_release_eos_buffers(inst);
+
if (msm_comm_release_output_buffers(inst, true))
dprintk(VIDC_ERR,
"Failed to release output buffers\n");
@@ -1694,6 +1758,9 @@
DEINIT_MSM_VIDC_LIST(&inst->pending_getpropq);
DEINIT_MSM_VIDC_LIST(&inst->outputbufs);
DEINIT_MSM_VIDC_LIST(&inst->registeredbufs);
+ DEINIT_MSM_VIDC_LIST(&inst->eosbufs);
+ DEINIT_MSM_VIDC_LIST(&inst->freqs);
+ DEINIT_MSM_VIDC_LIST(&inst->input_crs);
mutex_destroy(&inst->sync_lock);
mutex_destroy(&inst->bufq[CAPTURE_PORT].lock);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
index 4327309..d557959 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
@@ -19,6 +19,9 @@
#define MSM_VIDC_MIN_UBWC_COMPLEXITY_FACTOR (1 << 16)
#define MSM_VIDC_MAX_UBWC_COMPLEXITY_FACTOR (4 << 16)
+#define MSM_VIDC_MIN_UBWC_COMPRESSION_RATIO (1 << 16)
+#define MSM_VIDC_MAX_UBWC_COMPRESSION_RATIO (5 << 16)
+
static inline unsigned long int get_ubwc_compression_ratio(
struct ubwc_cr_stats_info_type ubwc_stats_info)
{
@@ -90,36 +93,56 @@
mutex_unlock(&inst->reconbufs.lock);
}
-static int fill_recon_stats(struct msm_vidc_inst *inst,
+static int fill_dynamic_stats(struct msm_vidc_inst *inst,
struct vidc_bus_vote_data *vote_data)
{
- struct recon_buf *binfo;
- u32 CR = 0, min_cf = MSM_VIDC_MIN_UBWC_COMPLEXITY_FACTOR,
- max_cf = MSM_VIDC_MAX_UBWC_COMPLEXITY_FACTOR;
+ struct recon_buf *binfo, *nextb;
+ struct vidc_input_cr_data *temp, *next;
+ u32 min_cf = 0, max_cf = 0;
+ u32 min_input_cr = 0, max_input_cr = 0, min_cr = 0, max_cr = 0;
mutex_lock(&inst->reconbufs.lock);
- list_for_each_entry(binfo, &inst->reconbufs.list, list) {
- CR = max(CR, binfo->CR);
+ list_for_each_entry_safe(binfo, nextb, &inst->reconbufs.list, list) {
+ min_cr = min(min_cr, binfo->CR);
+ max_cr = max(max_cr, binfo->CR);
min_cf = min(min_cf, binfo->CF);
max_cf = max(max_cf, binfo->CF);
}
mutex_unlock(&inst->reconbufs.lock);
+ mutex_lock(&inst->input_crs.lock);
+ list_for_each_entry_safe(temp, next, &inst->input_crs.list, list) {
+ min_input_cr = min(min_input_cr, temp->input_cr);
+ max_input_cr = max(max_input_cr, temp->input_cr);
+ }
+ mutex_unlock(&inst->input_crs.lock);
+
/* Sanitize CF values from HW . */
max_cf = min_t(u32, max_cf, MSM_VIDC_MAX_UBWC_COMPLEXITY_FACTOR);
min_cf = max_t(u32, min_cf, MSM_VIDC_MIN_UBWC_COMPLEXITY_FACTOR);
+ max_cr = min_t(u32, max_cr, MSM_VIDC_MAX_UBWC_COMPRESSION_RATIO);
+ min_cr = max_t(u32, min_cr, MSM_VIDC_MIN_UBWC_COMPRESSION_RATIO);
+ max_input_cr = min_t(u32,
+ max_input_cr, MSM_VIDC_MAX_UBWC_COMPRESSION_RATIO);
+ min_input_cr = max_t(u32,
+ min_input_cr, MSM_VIDC_MIN_UBWC_COMPRESSION_RATIO);
- vote_data->compression_ratio = CR;
+ vote_data->compression_ratio = min_cr;
vote_data->complexity_factor = max_cf;
+ vote_data->input_cr = min_input_cr;
vote_data->use_dpb_read = false;
+
+ /* Check if driver can vote for lower bus BW */
if (inst->clk_data.load <= inst->clk_data.load_norm) {
+ vote_data->compression_ratio = max_cr;
vote_data->complexity_factor = min_cf;
+ vote_data->input_cr = max_input_cr;
vote_data->use_dpb_read = true;
}
- dprintk(VIDC_DBG,
- "Compression Ratio = %d Complexity Factor = %d\n",
- vote_data->compression_ratio,
+ dprintk(VIDC_PROF,
+ "Input CR = %d Recon CR = %d Complexity Factor = %d\n",
+ vote_data->input_cr, vote_data->compression_ratio,
vote_data->complexity_factor);
return 0;
@@ -139,15 +162,16 @@
hdev = core->device;
+ mutex_lock(&core->lock);
vote_data = core->vote_data;
if (!vote_data) {
dprintk(VIDC_PROF,
"Failed to get vote_data for inst %pK\n",
inst);
+ mutex_unlock(&core->lock);
return -EINVAL;
}
- mutex_lock(&core->lock);
list_for_each_entry(inst, &core->instances, list) {
int codec = 0;
struct msm_vidc_buffer *temp, *next;
@@ -157,6 +181,7 @@
if (!inst) {
dprintk(VIDC_ERR, "%s Invalid args\n",
__func__);
+ mutex_unlock(&core->lock);
return -EINVAL;
}
@@ -165,7 +190,7 @@
&inst->registeredbufs.list, list) {
if (temp->vvb.vb2_buf.type ==
V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
- temp->deferred) {
+ temp->flags & MSM_VIDC_FLAG_DEFERRED) {
filled_len = max(filled_len,
temp->vvb.vb2_buf.planes[0].bytesused);
device_addr = temp->smem[0].device_addr;
@@ -184,6 +209,8 @@
inst->fmts[OUTPUT_PORT].fourcc :
inst->fmts[CAPTURE_PORT].fourcc;
+ memset(&(vote_data[i]), 0x0, sizeof(struct vidc_bus_vote_data));
+
vote_data[i].domain = get_hal_domain(inst->session_type);
vote_data[i].codec = get_hal_codec(codec);
vote_data[i].input_width = max(inst->prop.width[OUTPUT_PORT],
@@ -196,6 +223,9 @@
max(inst->prop.height[CAPTURE_PORT],
inst->prop.height[OUTPUT_PORT]);
vote_data[i].lcu_size = codec == V4L2_PIX_FMT_HEVC ? 32 : 16;
+ vote_data[i].b_frames_enabled =
+ msm_comm_g_ctrl_for_id(inst,
+ V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES) != 0;
if (inst->clk_data.operating_rate)
vote_data[i].fps =
@@ -225,9 +255,9 @@
vote_data[i].num_formats = 2;
}
vote_data[i].work_mode = inst->clk_data.work_mode;
- fill_recon_stats(inst, &vote_data[i]);
+ fill_dynamic_stats(inst, &vote_data[i]);
- if (core->resources.sys_cache_enabled)
+ if (core->resources.sys_cache_res_set)
vote_data[i].use_sys_cache = true;
i++;
@@ -354,10 +384,15 @@
if (!found) {
temp = kzalloc(sizeof(*temp), GFP_KERNEL);
+ if (!temp) {
+ dprintk(VIDC_WARN, "%s: malloc failure.\n", __func__);
+ goto exit;
+ }
temp->freq = freq;
temp->device_addr = device_addr;
list_add_tail(&temp->list, &inst->freqs.list);
}
+exit:
mutex_unlock(&inst->freqs.lock);
}
@@ -413,6 +448,48 @@
mutex_unlock(&inst->freqs.lock);
}
+void msm_comm_free_input_cr_table(struct msm_vidc_inst *inst)
+{
+ struct vidc_input_cr_data *temp, *next;
+
+ mutex_lock(&inst->input_crs.lock);
+ list_for_each_entry_safe(temp, next, &inst->input_crs.list, list) {
+ list_del(&temp->list);
+ kfree(temp);
+ }
+ INIT_LIST_HEAD(&inst->input_crs.list);
+ mutex_unlock(&inst->input_crs.lock);
+}
+
+void msm_comm_update_input_cr(struct msm_vidc_inst *inst,
+ u32 index, u32 cr)
+{
+ struct vidc_input_cr_data *temp, *next;
+ bool found = false;
+
+ mutex_lock(&inst->input_crs.lock);
+ list_for_each_entry_safe(temp, next, &inst->input_crs.list, list) {
+ if (temp->index == index) {
+ temp->input_cr = cr;
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ temp = kzalloc(sizeof(*temp), GFP_KERNEL);
+ if (!temp) {
+ dprintk(VIDC_WARN, "%s: malloc failure.\n", __func__);
+ goto exit;
+ }
+ temp->index = index;
+ temp->input_cr = cr;
+ list_add_tail(&temp->list, &inst->input_crs.list);
+ }
+exit:
+ mutex_unlock(&inst->input_crs.lock);
+}
+
static unsigned long msm_vidc_max_freq(struct msm_vidc_core *core)
{
struct allowed_clock_rates_table *allowed_clks_tbl = NULL;
@@ -433,7 +510,7 @@
u32 vpp_cycles_per_mb;
u32 mbs_per_second;
- mbs_per_second = msm_comm_get_inst_load(inst,
+ mbs_per_second = msm_comm_get_inst_load_per_core(inst,
LOAD_CALC_NO_QUIRKS);
/*
@@ -447,6 +524,8 @@
inst->clk_data.entry->low_power_cycles :
inst->clk_data.entry->vpp_cycles;
+ vpp_cycles = mbs_per_second * vpp_cycles_per_mb;
+
vsp_cycles = mbs_per_second * inst->clk_data.entry->vsp_cycles;
/* 10 / 7 is overhead factor */
@@ -456,7 +535,7 @@
vsp_cycles = mbs_per_second * inst->clk_data.entry->vsp_cycles;
/* 10 / 7 is overhead factor */
- vsp_cycles += ((inst->prop.fps * filled_len * 8) / 7) * 10;
+ vsp_cycles += ((inst->prop.fps * filled_len * 8) * 10) / 7;
} else {
dprintk(VIDC_ERR, "Unknown session type = %s\n", __func__);
@@ -542,7 +621,7 @@
temp->state >= MSM_VIDC_RELEASE_RESOURCES_DONE)
continue;
- mbs_per_second = msm_comm_get_inst_load(temp,
+ mbs_per_second = msm_comm_get_inst_load_per_core(temp,
LOAD_CALC_NO_QUIRKS);
cycles = temp->clk_data.entry->vpp_cycles;
@@ -599,7 +678,7 @@
list_for_each_entry_safe(temp, next, &inst->registeredbufs.list, list) {
if (temp->vvb.vb2_buf.type ==
V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
- temp->deferred) {
+ temp->flags & MSM_VIDC_FLAG_DEFERRED) {
filled_len = max(filled_len,
temp->vvb.vb2_buf.planes[0].bytesused);
device_addr = temp->smem[0].device_addr;
@@ -743,7 +822,7 @@
core = inst->core;
dcvs = &inst->clk_data;
- load = msm_comm_get_inst_load(inst, LOAD_CALC_NO_QUIRKS);
+ load = msm_comm_get_inst_load_per_core(inst, LOAD_CALC_NO_QUIRKS);
cycles = inst->clk_data.entry->vpp_cycles;
allowed_clks_tbl = core->resources.allowed_clks_tbl;
if (inst->session_type == MSM_VIDC_ENCODER) {
@@ -967,10 +1046,7 @@
} else {
continue;
}
- if (inst->clk_data.core_id == 3)
- cycles = cycles / 2;
-
- current_inst_mbs_per_sec = msm_comm_get_inst_load(inst,
+ current_inst_mbs_per_sec = msm_comm_get_inst_load_per_core(inst,
LOAD_CALC_NO_QUIRKS);
load += current_inst_mbs_per_sec * cycles;
}
@@ -1045,9 +1121,11 @@
if (inst->session_type == MSM_VIDC_ENCODER && hier_mode) {
if (current_inst_load / 2 + core0_load <= max_freq &&
current_inst_load / 2 + core1_load <= max_freq) {
- inst->clk_data.core_id = VIDC_CORE_ID_3;
- msm_vidc_power_save_mode_enable(inst, false);
- goto decision_done;
+ if (inst->clk_data.work_mode == VIDC_WORK_MODE_2) {
+ inst->clk_data.core_id = VIDC_CORE_ID_3;
+ msm_vidc_power_save_mode_enable(inst, false);
+ goto decision_done;
+ }
}
}
@@ -1056,9 +1134,11 @@
core0_lp_load <= max_freq &&
current_inst_lp_load / 2 +
core1_lp_load <= max_freq) {
- inst->clk_data.core_id = VIDC_CORE_ID_3;
- msm_vidc_power_save_mode_enable(inst, true);
- goto decision_done;
+ if (inst->clk_data.work_mode == VIDC_WORK_MODE_2) {
+ inst->clk_data.core_id = VIDC_CORE_ID_3;
+ msm_vidc_power_save_mode_enable(inst, true);
+ goto decision_done;
+ }
}
}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.h b/drivers/media/platform/msm/vidc/msm_vidc_clocks.h
index 705cb7c..707f034 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.h
@@ -33,6 +33,9 @@
int msm_vidc_decide_core_and_power_mode(struct msm_vidc_inst *inst);
void msm_vidc_clear_freq_entry(struct msm_vidc_inst *inst,
u32 device_addr);
+void msm_comm_free_input_cr_table(struct msm_vidc_inst *inst);
+void msm_comm_update_input_cr(struct msm_vidc_inst *inst, u32 index,
+ u32 cr);
void update_recon_stats(struct msm_vidc_inst *inst,
struct recon_stats_type *recon_stats);
#endif
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 03ad0a0..ac53d83 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -35,8 +35,6 @@
V4L2_EVENT_MSM_VIDC_RELEASE_BUFFER_REFERENCE
#define L_MODE V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY
-#define MAX_SUPPORTED_INSTANCES 16
-
const char *const mpeg_video_vidc_extradata[] = {
"Extradata none",
"Extradata MB Quantization",
@@ -81,7 +79,6 @@
static void msm_comm_generate_sys_error(struct msm_vidc_inst *inst);
static void handle_session_error(enum hal_command_response cmd, void *data);
static void msm_vidc_print_running_insts(struct msm_vidc_core *core);
-static void msm_comm_print_debug_info(struct msm_vidc_inst *inst);
bool msm_comm_turbo_session(struct msm_vidc_inst *inst)
{
@@ -492,6 +489,26 @@
default:
goto unknown_value;
}
+ case V4L2_CID_MPEG_VIDC_VIDEO_TME_PROFILE:
+ switch (value) {
+ case V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_0:
+ return HAL_TME_PROFILE_0;
+ case V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_1:
+ return HAL_TME_PROFILE_1;
+ case V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_2:
+ return HAL_TME_PROFILE_2;
+ case V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_3:
+ return HAL_TME_PROFILE_3;
+ default:
+ goto unknown_value;
+ }
+ case V4L2_CID_MPEG_VIDC_VIDEO_TME_LEVEL:
+ switch (value) {
+ case V4L2_MPEG_VIDC_VIDEO_TME_LEVEL_INTEGER:
+ return HAL_TME_LEVEL_INTEGER;
+ default:
+ goto unknown_value;
+ }
case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION:
switch (value) {
case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_NONE:
@@ -536,6 +553,51 @@
return -EINVAL;
}
+int msm_comm_get_v4l2_profile(int fourcc, int profile)
+{
+ switch (fourcc) {
+ case V4L2_PIX_FMT_H264:
+ return msm_comm_hal_to_v4l2(
+ V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+ profile);
+ case V4L2_PIX_FMT_HEVC:
+ return msm_comm_hal_to_v4l2(
+ V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE,
+ profile);
+ case V4L2_PIX_FMT_VP8:
+ case V4L2_PIX_FMT_VP9:
+ case V4L2_PIX_FMT_MPEG2:
+ return 0;
+ default:
+ dprintk(VIDC_WARN, "Unknown codec id %x\n", fourcc);
+ return 0;
+ }
+}
+
+int msm_comm_get_v4l2_level(int fourcc, int level)
+{
+ switch (fourcc) {
+ case V4L2_PIX_FMT_H264:
+ return msm_comm_hal_to_v4l2(
+ V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+ level);
+ case V4L2_PIX_FMT_HEVC:
+ return msm_comm_hal_to_v4l2(
+ V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL,
+ level);
+ case V4L2_PIX_FMT_VP8:
+ return msm_comm_hal_to_v4l2(
+ V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL,
+ level);
+ case V4L2_PIX_FMT_VP9:
+ case V4L2_PIX_FMT_MPEG2:
+ return 0;
+ default:
+ dprintk(VIDC_WARN, "Unknown codec id %x\n", fourcc);
+ return 0;
+ }
+}
+
int msm_comm_ctrl_init(struct msm_vidc_inst *inst,
struct msm_vidc_ctrl *drv_ctrls, u32 num_ctrls,
const struct v4l2_ctrl_ops *ctrl_ops)
@@ -740,6 +802,17 @@
return load;
}
+int msm_comm_get_inst_load_per_core(struct msm_vidc_inst *inst,
+ enum load_calc_quirks quirks)
+{
+ int load = msm_comm_get_inst_load(inst, quirks);
+
+ if (inst->clk_data.core_id == VIDC_CORE_ID_3)
+ load = load / 2;
+
+ return load;
+}
+
int msm_comm_get_load(struct msm_vidc_core *core,
enum session_type type, enum load_calc_quirks quirks)
{
@@ -795,7 +868,6 @@
case V4L2_PIX_FMT_H264_MVC:
codec = HAL_VIDEO_CODEC_MVC;
break;
-
case V4L2_PIX_FMT_MPEG1:
codec = HAL_VIDEO_CODEC_MPEG1;
break;
@@ -811,6 +883,9 @@
case V4L2_PIX_FMT_HEVC:
codec = HAL_VIDEO_CODEC_HEVC;
break;
+ case V4L2_PIX_FMT_TME:
+ codec = HAL_VIDEO_CODEC_TME;
+ break;
default:
dprintk(VIDC_ERR, "Wrong codec: %d\n", fourcc);
codec = HAL_UNUSED_CODEC;
@@ -957,8 +1032,8 @@
/* This should come from sys_init_done */
core->resources.max_inst_count =
sys_init_msg->max_sessions_supported ?
- sys_init_msg->max_sessions_supported :
- MAX_SUPPORTED_INSTANCES;
+ min_t(u32, sys_init_msg->max_sessions_supported,
+ MAX_SUPPORTED_INSTANCES) : MAX_SUPPORTED_INSTANCES;
core->resources.max_secure_inst_count =
core->resources.max_secure_inst_count ?
@@ -979,11 +1054,6 @@
__func__, core->codec_count, core->enc_codec_supported,
core->dec_codec_supported);
- core->vote_data = kcalloc(MAX_SUPPORTED_INSTANCES,
- sizeof(core->vote_data), GFP_KERNEL);
- if (!core->vote_data)
- dprintk(VIDC_ERR, "%s: failed to allocate memory\n", __func__);
-
complete(&(core->completions[index]));
}
@@ -1260,6 +1330,9 @@
static void msm_vidc_comm_update_ctrl_limits(struct msm_vidc_inst *inst)
{
if (inst->session_type == MSM_VIDC_ENCODER) {
+ if (get_hal_codec(inst->fmts[CAPTURE_PORT].fourcc) ==
+ HAL_VIDEO_CODEC_TME)
+ return;
msm_vidc_comm_update_ctrl(inst,
V4L2_CID_MPEG_VIDC_VIDEO_HYBRID_HIERP_MODE,
&inst->capability.hier_p_hybrid);
@@ -1434,6 +1507,15 @@
print_cap("max_work_modes", &inst->capability.max_work_modes);
print_cap("ubwc_cr_stats", &inst->capability.ubwc_cr_stats);
+ dprintk(VIDC_DBG, "profile count : %u",
+ inst->capability.profile_level.profile_count);
+ for (i = 0; i < inst->capability.profile_level.profile_count; i++) {
+ dprintk(VIDC_DBG, "profile : %u ", inst->capability.
+ profile_level.profile_level[i].profile);
+ dprintk(VIDC_DBG, "level : %u ", inst->capability.
+ profile_level.profile_level[i].level);
+ }
+
signal_session_msg_receipt(cmd, inst);
/*
@@ -1528,6 +1610,12 @@
* ptr[2] = bit depth
* ptr[3] = pic struct (progressive or interlaced)
* ptr[4] = colour space
+ * ptr[5] = crop_data(top)
+ * ptr[6] = crop_data(left)
+ * ptr[7] = crop_data(height)
+ * ptr[8] = crop_data(width)
+ * ptr[9] = profile
+ * ptr[10] = level
*/
inst->entropy_mode = event_notify->entropy_mode;
@@ -1552,10 +1640,17 @@
ptr[6] = event_notify->crop_data.left;
ptr[7] = event_notify->crop_data.height;
ptr[8] = event_notify->crop_data.width;
+ ptr[9] = msm_comm_get_v4l2_profile(
+ inst->fmts[OUTPUT_PORT].fourcc,
+ event_notify->profile);
+ ptr[10] = msm_comm_get_v4l2_level(
+ inst->fmts[OUTPUT_PORT].fourcc,
+ event_notify->level);
dprintk(VIDC_DBG,
- "Event payload: height = %d width = %d\n",
- event_notify->height, event_notify->width);
+ "Event payload: height = %d width = %d profile = %d level = %d\n",
+ event_notify->height, event_notify->width,
+ ptr[9], ptr[10]);
dprintk(VIDC_DBG,
"Event payload: bit_depth = %d pic_struct = %d colour_space = %d\n",
@@ -2036,6 +2131,7 @@
}
dprintk(VIDC_WARN, "SYS_ERROR received for core %pK\n", core);
+ msm_vidc_noc_error_info(core);
call_hfi_op(hdev, flush_debug_queue, hdev->hfi_device_data);
list_for_each_entry(inst, &core->instances, list) {
dprintk(VIDC_WARN,
@@ -2180,6 +2276,26 @@
return 0;
}
+static bool is_eos_buffer(struct msm_vidc_inst *inst, u32 device_addr)
+{
+ struct eos_buf *temp, *next;
+ bool found = false;
+
+ mutex_lock(&inst->eosbufs.lock);
+ list_for_each_entry_safe(temp, next, &inst->eosbufs.list, list) {
+ if (temp->smem.device_addr == device_addr) {
+ found = true;
+ list_del(&temp->list);
+ msm_comm_smem_free(inst, &temp->smem);
+ kfree(temp);
+ break;
+ }
+ }
+ mutex_unlock(&inst->eosbufs.lock);
+
+ return found;
+}
+
static void handle_ebd(enum hal_command_response cmd, void *data)
{
struct msm_vidc_cb_data_done *response = data;
@@ -2204,6 +2320,13 @@
}
empty_buf_done = (struct vidc_hal_ebd *)&response->input_done;
+ /* If this is internal EOS buffer, handle it in driver */
+ if (is_eos_buffer(inst, empty_buf_done->packet_buffer)) {
+ dprintk(VIDC_DBG, "Received EOS buffer %pK\n",
+ (void *)(u64)empty_buf_done->packet_buffer);
+ goto exit;
+ }
+
planes[0] = empty_buf_done->packet_buffer;
planes[1] = empty_buf_done->extra_data_buffer;
@@ -2688,8 +2811,6 @@
int msm_comm_check_core_init(struct msm_vidc_core *core)
{
int rc = 0;
- struct hfi_device *hdev;
- struct msm_vidc_inst *inst = NULL;
mutex_lock(&core->lock);
if (core->state >= VIDC_CORE_INIT_DONE) {
@@ -2698,29 +2819,12 @@
goto exit;
}
dprintk(VIDC_DBG, "Waiting for SYS_INIT_DONE\n");
- hdev = (struct hfi_device *)core->device;
rc = wait_for_completion_timeout(
&core->completions[SYS_MSG_INDEX(HAL_SYS_INIT_DONE)],
msecs_to_jiffies(core->resources.msm_vidc_hw_rsp_timeout));
if (!rc) {
dprintk(VIDC_ERR, "%s: Wait interrupted or timed out: %d\n",
__func__, SYS_MSG_INDEX(HAL_SYS_INIT_DONE));
- call_hfi_op(hdev, flush_debug_queue, hdev->hfi_device_data);
- dprintk(VIDC_ERR,
- "SYS_INIT timeout can potentially crash the system\n");
- /*
- * For SYS_INIT, there will not be any inst pointer.
- * Just grab one of the inst from instances list and
- * use it.
- */
- inst = list_first_entry(&core->instances,
- struct msm_vidc_inst, list);
-
- mutex_unlock(&core->lock);
- msm_comm_print_debug_info(inst);
- mutex_lock(&core->lock);
-
- msm_vidc_handle_hw_error(core);
rc = -EIO;
goto exit;
} else {
@@ -3686,6 +3790,64 @@
rc = msm_comm_session_continue(inst);
break;
}
+ case V4L2_DEC_CMD_STOP:
+ {
+ struct vidc_frame_data data = {0};
+ struct hfi_device *hdev;
+ struct eos_buf *binfo;
+ u32 smem_flags = 0;
+
+ get_inst(inst->core, inst);
+ if (inst->session_type != MSM_VIDC_DECODER) {
+ dprintk(VIDC_DBG,
+ "Non-Decoder session. DEC_STOP is not valid\n");
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
+ if (!binfo) {
+ dprintk(VIDC_ERR, "%s: Out of memory\n", __func__);
+ rc = -ENOMEM;
+ goto exit;
+ }
+
+ if (inst->flags & VIDC_SECURE)
+ smem_flags |= SMEM_SECURE;
+
+ rc = msm_comm_smem_alloc(inst,
+ SZ_4K, 1, smem_flags,
+ HAL_BUFFER_INPUT, 0, &binfo->smem);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to allocate output memory\n");
+ goto exit;
+ }
+
+ mutex_lock(&inst->eosbufs.lock);
+ list_add_tail(&binfo->list, &inst->eosbufs.list);
+ mutex_unlock(&inst->eosbufs.lock);
+
+ data.alloc_len = binfo->smem.size;
+ data.device_addr = binfo->smem.device_addr;
+ data.clnt_data = data.device_addr;
+ data.buffer_type = HAL_BUFFER_INPUT;
+ data.filled_len = 0;
+ data.offset = 0;
+ data.flags = HAL_BUFFERFLAG_EOS;
+ data.timestamp = LLONG_MAX;
+ data.extradata_addr = data.device_addr;
+ data.extradata_size = 0;
+ dprintk(VIDC_DBG, "Queueing EOS buffer %pK\n",
+ (void *)(u64)data.device_addr);
+ hdev = inst->core->device;
+
+ rc = call_hfi_op(hdev, session_etb, inst->session,
+ &data);
+exit:
+ put_inst(inst);
+ break;
+ }
default:
dprintk(VIDC_ERR, "Unknown Command %d\n", which_cmd);
rc = -ENOTSUPP;
@@ -3772,7 +3934,7 @@
continue;
/* count only deferred buffers */
- if (!mbuf->deferred)
+ if (!(mbuf->flags & MSM_VIDC_FLAG_DEFERRED))
continue;
++count;
@@ -3800,7 +3962,7 @@
continue;
/* count only deferred buffers */
- if (!mbuf->deferred)
+ if (!(mbuf->flags & MSM_VIDC_FLAG_DEFERRED))
continue;
++count;
@@ -3848,6 +4010,41 @@
}
}
+static int msm_comm_qbuf_rbr(struct msm_vidc_inst *inst,
+ struct msm_vidc_buffer *mbuf)
+{
+ int rc = 0;
+ struct hfi_device *hdev;
+ struct vidc_frame_data frame_data = {0};
+
+ if (!inst || !inst->core || !inst->core->device || !mbuf) {
+ dprintk(VIDC_ERR, "%s: Invalid arguments\n", __func__);
+ return -EINVAL;
+ }
+
+ hdev = inst->core->device;
+
+ if (inst->state == MSM_VIDC_CORE_INVALID) {
+ dprintk(VIDC_ERR, "%s: inst is in bad state\n", __func__);
+ return -EINVAL;
+ }
+
+ rc = msm_comm_scale_clocks_and_bus(inst);
+ populate_frame_data(&frame_data, mbuf, inst);
+
+ rc = call_hfi_op(hdev, session_ftb, inst->session, &frame_data);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to issue ftb: %d\n", rc);
+ goto err_bad_input;
+ }
+
+ log_frame(inst, &frame_data, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+
+err_bad_input:
+ return rc;
+}
+
+
/*
* Attempts to queue `vb` to hardware. If, for various reasons, the buffer
* cannot be queued to hardware, the buffer will be staged for commit in the
@@ -3879,10 +4076,6 @@
return -EINVAL;
}
- /* initially assume every buffer is going to be deferred */
- if (mbuf)
- mbuf->deferred = true;
-
batch_mode = msm_comm_g_ctrl_for_id(inst, V4L2_CID_VIDC_QBUF_MODE)
== V4L2_VIDC_QBUF_BATCHED;
capture_count = (batch_mode ? &count_single_batch : &count_buffers)
@@ -3910,7 +4103,7 @@
if (defer) {
if (mbuf) {
- mbuf->deferred = true;
+ mbuf->flags |= MSM_VIDC_FLAG_DEFERRED;
print_vidc_buffer(VIDC_DBG, "deferred qbuf",
inst, mbuf);
}
@@ -3951,7 +4144,7 @@
list_for_each_entry_safe(temp, next, &inst->registeredbufs.list, list) {
struct vidc_frame_data *frame_data = NULL;
- if (!temp->deferred)
+ if (!(temp->flags & MSM_VIDC_FLAG_DEFERRED))
continue;
switch (temp->vvb.vb2_buf.type) {
@@ -3973,7 +4166,7 @@
populate_frame_data(frame_data, temp, inst);
/* this buffer going to be queued (not deferred) */
- temp->deferred = false;
+ temp->flags &= ~MSM_VIDC_FLAG_DEFERRED;
print_vidc_buffer(VIDC_DBG, "qbuf", inst, temp);
}
@@ -4067,9 +4260,14 @@
return -EINVAL;
}
extra_buffers = msm_vidc_get_extra_buff_count(inst, HAL_BUFFER_INPUT);
-
bufreq->buffer_count_min_host = bufreq->buffer_count_min +
extra_buffers;
+ bufreq = get_buff_req_buffer(inst, HAL_BUFFER_EXTRADATA_INPUT);
+ if (bufreq) {
+ if (bufreq->buffer_count_min)
+ bufreq->buffer_count_min_host =
+ bufreq->buffer_count_min + extra_buffers;
+ }
if (msm_comm_get_stream_output_mode(inst) ==
HAL_VIDEO_DECODER_SECONDARY) {
@@ -4467,6 +4665,26 @@
return rc;
}
+void msm_comm_release_eos_buffers(struct msm_vidc_inst *inst)
+{
+ struct eos_buf *buf, *next;
+
+ if (!inst) {
+ dprintk(VIDC_ERR,
+ "Invalid instance pointer = %pK\n", inst);
+ return;
+ }
+
+ mutex_lock(&inst->eosbufs.lock);
+ list_for_each_entry_safe(buf, next, &inst->eosbufs.list, list) {
+ list_del(&buf->list);
+ kfree(buf);
+ }
+ INIT_LIST_HEAD(&inst->eosbufs.list);
+ mutex_unlock(&inst->eosbufs.lock);
+}
+
+
int msm_comm_release_recon_buffers(struct msm_vidc_inst *inst)
{
struct recon_buf *buf, *next;
@@ -4666,8 +4884,7 @@
return 0;
}
- if (!list_empty(&inst->reconbufs.list))
- msm_comm_release_recon_buffers(inst);
+ msm_comm_release_recon_buffers(inst);
for (i = 0; i < internal_buf->buffer_count_actual; i++) {
binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
@@ -4725,10 +4942,16 @@
&inst->bufq[port].vb2_bufq.queued_list) {
struct vb2_buffer *vb = container_of(ptr,
struct vb2_buffer, queued_entry);
- vb->planes[0].bytesused = 0;
- print_vb2_buffer(VIDC_ERR, "flush in invalid",
- inst, vb);
- vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+ if (vb->state == VB2_BUF_STATE_ACTIVE) {
+ vb->planes[0].bytesused = 0;
+ print_vb2_buffer(VIDC_ERR, "flush in invalid",
+ inst, vb);
+ vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+ } else {
+ dprintk(VIDC_WARN,
+ "%s VB is in state %d not in ACTIVE state\n"
+ , __func__, vb->state);
+ }
}
mutex_unlock(&inst->bufq[port].lock);
}
@@ -4738,7 +4961,7 @@
int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags)
{
- int rc = 0;
+ int i, rc = 0;
bool ip_flush = false;
bool op_flush = false;
struct msm_vidc_buffer *mbuf, *next;
@@ -4763,8 +4986,6 @@
return 0;
}
- /* Finish FLUSH As Soon As Possible. */
-
msm_clock_data_reset(inst);
if (inst->state == MSM_VIDC_CORE_INVALID) {
@@ -4777,22 +4998,41 @@
mutex_lock(&inst->registeredbufs.lock);
list_for_each_entry_safe(mbuf, next, &inst->registeredbufs.list, list) {
- /* flush only deferred buffers (which are not queued yet) */
- if (!mbuf->deferred)
- continue;
-
- /* don't flush input buffers if flush not requested on it */
+ /* don't flush input buffers if input flush is not requested */
if (!ip_flush && mbuf->vvb.vb2_buf.type ==
V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
continue;
+ /* flush only deferred or rbr pending buffers */
+ if (!(mbuf->flags & MSM_VIDC_FLAG_DEFERRED ||
+ mbuf->flags & MSM_VIDC_FLAG_RBR_PENDING))
+ continue;
+
+ /*
+ * flush buffers which are queued by client already,
+ * the refcount will be two or more for those buffers.
+ */
+ if (!(mbuf->smem[0].refcount >= 2))
+ continue;
+
print_vidc_buffer(VIDC_DBG, "flush buf", inst, mbuf);
msm_comm_flush_vidc_buffer(inst, mbuf);
- msm_comm_unmap_vidc_buffer(inst, mbuf);
- /* remove from list */
- list_del(&mbuf->list);
- kref_put_mbuf(mbuf);
+ for (i = 0; i < mbuf->vvb.vb2_buf.num_planes; i++) {
+ if (msm_smem_unmap_dma_buf(inst, &mbuf->smem[i]))
+ print_vidc_buffer(VIDC_ERR,
+ "dqbuf: unmap failed.", inst, mbuf);
+ if (msm_smem_unmap_dma_buf(inst, &mbuf->smem[i]))
+ print_vidc_buffer(VIDC_ERR,
+ "dqbuf: unmap failed..", inst, mbuf);
+ }
+ if (!mbuf->smem[0].refcount) {
+ list_del(&mbuf->list);
+ kref_put_mbuf(mbuf);
+ } else {
+ /* buffer is no more a deferred buffer */
+ mbuf->flags &= ~MSM_VIDC_FLAG_DEFERRED;
+ }
}
mutex_unlock(&inst->registeredbufs.lock);
@@ -4924,6 +5164,28 @@
return ret;
};
+int msm_vidc_noc_error_info(struct msm_vidc_core *core)
+{
+ struct hfi_device *hdev;
+
+ if (!core || !core->device) {
+ dprintk(VIDC_WARN, "%s: Invalid parameters: %pK\n",
+ __func__, core);
+ return -EINVAL;
+ }
+
+ if (!core->resources.non_fatal_pagefaults)
+ return 0;
+
+ if (!core->smmu_fault_handled)
+ return 0;
+
+ hdev = core->device;
+ call_hfi_op(hdev, noc_error_info, hdev->hfi_device_data);
+
+ return 0;
+}
+
int msm_vidc_trigger_ssr(struct msm_vidc_core *core,
enum hal_ssr_trigger_type type)
{
@@ -5076,6 +5338,8 @@
int rc = 0;
struct hfi_device *hdev;
struct msm_vidc_core *core;
+ u32 output_height, output_width;
+ u32 rotation;
if (!inst || !inst->core || !inst->core->device) {
dprintk(VIDC_WARN, "%s: Invalid parameter\n", __func__);
@@ -5097,34 +5361,47 @@
return -ENOTSUPP;
}
+ rotation = msm_comm_g_ctrl_for_id(inst,
+ V4L2_CID_MPEG_VIDC_VIDEO_ROTATION);
+
+ output_height = inst->prop.height[CAPTURE_PORT];
+ output_width = inst->prop.width[CAPTURE_PORT];
+
+ if ((output_width != output_height) &&
+ (rotation == V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_90 ||
+ rotation == V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_270)) {
+
+ output_width = inst->prop.height[CAPTURE_PORT];
+ output_height = inst->prop.width[CAPTURE_PORT];
+ dprintk(VIDC_DBG,
+ "Rotation=%u Swapped Output W=%u H=%u to check capability",
+ rotation, output_width, output_height);
+ }
+
if (!rc) {
- if (inst->prop.width[CAPTURE_PORT] < capability->width.min ||
- inst->prop.height[CAPTURE_PORT] <
- capability->height.min) {
+ if (output_width < capability->width.min ||
+ output_height < capability->height.min) {
dprintk(VIDC_ERR,
"Unsupported WxH = (%u)x(%u), min supported is - (%u)x(%u)\n",
- inst->prop.width[CAPTURE_PORT],
- inst->prop.height[CAPTURE_PORT],
+ output_width,
+ output_height,
capability->width.min,
capability->height.min);
rc = -ENOTSUPP;
}
- if (!rc && inst->prop.width[CAPTURE_PORT] >
- capability->width.max) {
+ if (!rc && output_width > capability->width.max) {
dprintk(VIDC_ERR,
"Unsupported width = %u supported max width = %u\n",
- inst->prop.width[CAPTURE_PORT],
+ output_width,
capability->width.max);
rc = -ENOTSUPP;
}
- if (!rc && inst->prop.height[CAPTURE_PORT]
- * inst->prop.width[CAPTURE_PORT] >
+ if (!rc && output_height * output_width >
capability->width.max * capability->height.max) {
dprintk(VIDC_ERR,
"Unsupported WxH = (%u)x(%u), max supported is - (%u)x(%u)\n",
- inst->prop.width[CAPTURE_PORT],
- inst->prop.height[CAPTURE_PORT],
+ output_width, output_height,
capability->width.max, capability->height.max);
rc = -ENOTSUPP;
}
@@ -5353,8 +5630,8 @@
}
} else if (inst->session_type == MSM_VIDC_ENCODER) {
if (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- if (!i) /* yuv */
- skip = true;
+ /* yuv and extradata */
+ skip = true;
} else if (b->type ==
V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
if (!i) /* bitstream */
@@ -5515,7 +5792,9 @@
dprintk(VIDC_PROF, "reported fps changed for %pK: %d->%d\n",
inst, inst->prop.fps, fps);
inst->prop.fps = fps;
- if (inst->session_type == MSM_VIDC_ENCODER) {
+ if (inst->session_type == MSM_VIDC_ENCODER &&
+ get_hal_codec(inst->fmts[CAPTURE_PORT].fourcc) !=
+ HAL_VIDEO_CODEC_TME) {
frame_rate.frame_rate = inst->prop.fps * BIT(16);
frame_rate.buffer_type = HAL_BUFFER_OUTPUT;
pdata = &frame_rate;
@@ -5589,32 +5868,6 @@
mutex_unlock(&inst->outputbufs.lock);
}
-static void msm_comm_print_debug_info(struct msm_vidc_inst *inst)
-{
- struct msm_vidc_core *core = NULL;
- struct msm_vidc_inst *temp = NULL;
-
- if (!inst || !inst->core) {
- dprintk(VIDC_ERR, "%s - invalid param %pK %pK\n",
- __func__, inst, core);
- return;
- }
- core = inst->core;
-
- dprintk(VIDC_ERR, "Venus core frequency = %lu", core->curr_freq);
- mutex_lock(&core->lock);
- dprintk(VIDC_ERR, "Printing instance info that caused Error\n");
- msm_comm_print_inst_info(inst);
- dprintk(VIDC_ERR, "Printing remaining instances info\n");
- list_for_each_entry(temp, &core->instances, list) {
- /* inst already printed above. Hence don't repeat.*/
- if (temp == inst)
- continue;
- msm_comm_print_inst_info(temp);
- }
- mutex_unlock(&core->lock);
-}
-
int msm_comm_session_continue(void *instance)
{
struct msm_vidc_inst *inst = instance;
@@ -5694,27 +5947,27 @@
if (vb2->num_planes == 1)
dprintk(tag,
- "%s: %s: %x : idx %2d fd %d off %d daddr %x size %d filled %d flags 0x%x ts %lld refcnt %d\n",
+ "%s: %s: %x : idx %2d fd %d off %d daddr %x size %d filled %d flags 0x%x ts %lld refcnt %d mflags 0x%x\n",
str, vb2->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ?
"OUTPUT" : "CAPTURE", hash32_ptr(inst->session),
vb2->index, vb2->planes[0].m.fd,
vb2->planes[0].data_offset, mbuf->smem[0].device_addr,
vb2->planes[0].length, vb2->planes[0].bytesused,
mbuf->vvb.flags, mbuf->vvb.vb2_buf.timestamp,
- mbuf->smem[0].refcount);
+ mbuf->smem[0].refcount, mbuf->flags);
else
dprintk(tag,
- "%s: %s: %x : idx %2d fd %d off %d daddr %x size %d filled %d flags 0x%x ts %lld refcnt %d, extradata: fd %d off %d daddr %x size %d filled %d refcnt %d\n",
+ "%s: %s: %x : idx %2d fd %d off %d daddr %x size %d filled %d flags 0x%x ts %lld refcnt %d mflags 0x%x, extradata: fd %d off %d daddr %x size %d filled %d refcnt %d\n",
str, vb2->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ?
"OUTPUT" : "CAPTURE", hash32_ptr(inst->session),
vb2->index, vb2->planes[0].m.fd,
vb2->planes[0].data_offset, mbuf->smem[0].device_addr,
vb2->planes[0].length, vb2->planes[0].bytesused,
mbuf->vvb.flags, mbuf->vvb.vb2_buf.timestamp,
- mbuf->smem[0].refcount, vb2->planes[1].m.fd,
- vb2->planes[1].data_offset, mbuf->smem[1].device_addr,
- vb2->planes[1].length, vb2->planes[1].bytesused,
- mbuf->smem[1].refcount);
+ mbuf->smem[0].refcount, mbuf->flags,
+ vb2->planes[1].m.fd, vb2->planes[1].data_offset,
+ mbuf->smem[1].device_addr, vb2->planes[1].length,
+ vb2->planes[1].bytesused, mbuf->smem[1].refcount);
}
void print_vb2_buffer(u32 tag, const char *str, struct msm_vidc_inst *inst,
@@ -5733,13 +5986,14 @@
vb2->planes[0].bytesused);
else
dprintk(tag,
- "%s: %s: %x : idx %2d fd %d off %d size %d filled %d, extradata: fd %d off %d size %d\n",
+ "%s: %s: %x : idx %2d fd %d off %d size %d filled %d, extradata: fd %d off %d size %d filled %d\n",
str, vb2->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ?
"OUTPUT" : "CAPTURE", hash32_ptr(inst->session),
vb2->index, vb2->planes[0].m.fd,
vb2->planes[0].data_offset, vb2->planes[0].length,
vb2->planes[0].bytesused, vb2->planes[1].m.fd,
- vb2->planes[1].data_offset, vb2->planes[1].length);
+ vb2->planes[1].data_offset, vb2->planes[1].length,
+ vb2->planes[1].bytesused);
}
void print_v4l2_buffer(u32 tag, const char *str, struct msm_vidc_inst *inst,
@@ -5759,7 +6013,7 @@
v4l2->m.planes[0].bytesused);
else
dprintk(tag,
- "%s: %s: %x : idx %2d fd %d off %d size %d filled %d, extradata: fd %d off %d size %d\n",
+ "%s: %s: %x : idx %2d fd %d off %d size %d filled %d, extradata: fd %d off %d size %d filled %d\n",
str, v4l2->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ?
"OUTPUT" : "CAPTURE", hash32_ptr(inst->session),
v4l2->index, v4l2->m.planes[0].m.fd,
@@ -5768,7 +6022,8 @@
v4l2->m.planes[0].bytesused,
v4l2->m.planes[1].m.fd,
v4l2->m.planes[1].data_offset,
- v4l2->m.planes[1].length);
+ v4l2->m.planes[1].length,
+ v4l2->m.planes[1].bytesused);
}
bool msm_comm_compare_vb2_plane(struct msm_vidc_inst *inst,
@@ -5959,8 +6214,11 @@
* always compare dma_buf addresses which is guaranteed
* to be same across the processes (duplicate fds).
*/
- dma_planes[i] = (unsigned long)dma_buf_get(vb2->planes[i].m.fd);
- dma_buf_put((struct dma_buf *)dma_planes[i]);
+ dma_planes[i] = (unsigned long)msm_smem_get_dma_buf(
+ vb2->planes[i].m.fd);
+ if (!dma_planes[i])
+ return NULL;
+ msm_smem_put_dma_buf((struct dma_buf *)dma_planes[i]);
}
mutex_lock(&inst->registeredbufs.lock);
@@ -5983,6 +6241,9 @@
kref_init(&mbuf->kref);
}
+ /* Initially assume all the buffer are going to be deferred */
+ mbuf->flags |= MSM_VIDC_FLAG_DEFERRED;
+
vbuf = to_vb2_v4l2_buffer(vb2);
memcpy(&mbuf->vvb, vbuf, sizeof(struct vb2_v4l2_buffer));
vb = &mbuf->vvb.vb2_buf;
@@ -6029,6 +6290,16 @@
if (found_plane0)
rc = -EEXIST;
}
+ /*
+ * If RBR pending on this buffer then enable RBR_PENDING flag
+ * and clear the DEFERRED flag to avoid this buffer getting
+ * queued to video hardware in msm_comm_qbuf() which tries to
+ * queue all the DEFERRED buffers.
+ */
+ if (rc == -EEXIST) {
+ mbuf->flags |= MSM_VIDC_FLAG_RBR_PENDING;
+ mbuf->flags &= ~MSM_VIDC_FLAG_DEFERRED;
+ }
}
/* add the new buffer to list */
@@ -6125,10 +6396,14 @@
}
}
if (found) {
+ /* send RBR event to client */
msm_vidc_queue_rbr_event(inst,
mbuf->vvb.vb2_buf.planes[0].m.fd,
mbuf->vvb.vb2_buf.planes[0].data_offset);
+ /* clear RBR_PENDING flag */
+ mbuf->flags &= ~MSM_VIDC_FLAG_RBR_PENDING;
+
for (i = 0; i < mbuf->vvb.vb2_buf.num_planes; i++) {
if (msm_smem_unmap_dma_buf(inst, &mbuf->smem[i]))
print_vidc_buffer(VIDC_ERR,
@@ -6164,7 +6439,7 @@
if (!found)
goto unlock;
- /* found means client queued the buffer already */
+ /* buffer found means client queued the buffer already */
if (inst->in_reconfig || inst->in_flush) {
print_vidc_buffer(VIDC_DBG, "rbr flush buf", inst, mbuf);
msm_comm_flush_vidc_buffer(inst, mbuf);
@@ -6176,12 +6451,16 @@
/* don't queue the buffer */
found = false;
}
+ /* clear DEFERRED flag, if any, as the buffer is going to be queued */
+ if (found)
+ mbuf->flags &= ~MSM_VIDC_FLAG_DEFERRED;
+
unlock:
mutex_unlock(&inst->registeredbufs.lock);
if (found) {
print_vidc_buffer(VIDC_DBG, "rbr qbuf", inst, mbuf);
- rc = msm_comm_qbuf(inst, mbuf);
+ rc = msm_comm_qbuf_rbr(inst, mbuf);
if (rc)
print_vidc_buffer(VIDC_ERR,
"rbr qbuf failed", inst, mbuf);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h
index 18ba4a5..a272a10 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h
@@ -56,6 +56,7 @@
bool check_for_reuse);
int msm_comm_release_persist_buffers(struct msm_vidc_inst *inst);
int msm_comm_release_recon_buffers(struct msm_vidc_inst *inst);
+void msm_comm_release_eos_buffers(struct msm_vidc_inst *inst);
int msm_comm_release_output_buffers(struct msm_vidc_inst *inst,
bool force_release);
void msm_comm_validate_output_buffers(struct msm_vidc_inst *inst);
@@ -84,6 +85,8 @@
int msm_comm_check_core_init(struct msm_vidc_core *core);
int msm_comm_get_inst_load(struct msm_vidc_inst *inst,
enum load_calc_quirks quirks);
+int msm_comm_get_inst_load_per_core(struct msm_vidc_inst *inst,
+ enum load_calc_quirks quirks);
int msm_comm_get_load(struct msm_vidc_core *core,
enum session_type type, enum load_calc_quirks quirks);
int msm_comm_set_color_format(struct msm_vidc_inst *inst,
@@ -101,6 +104,8 @@
void msm_comm_print_inst_info(struct msm_vidc_inst *inst);
int msm_comm_v4l2_to_hal(int id, int value);
int msm_comm_hal_to_v4l2(int id, int value);
+int msm_comm_get_v4l2_profile(int fourcc, int profile);
+int msm_comm_get_v4l2_level(int fourcc, int level);
int msm_comm_session_continue(void *instance);
enum hal_uncompressed_format msm_comm_get_hal_uncompressed(int fourcc);
u32 get_frame_size_nv12(int plane, u32 height, u32 width);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index e554a46..1ad28ba 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -49,6 +49,7 @@
#define MAX_NUM_OUTPUT_BUFFERS VIDEO_MAX_FRAME // same as VB2_MAX_FRAME
#define MAX_NUM_CAPTURE_BUFFERS VIDEO_MAX_FRAME // same as VB2_MAX_FRAME
+#define MAX_SUPPORTED_INSTANCES 16
/* Maintains the number of FTB's between each FBD over a window */
#define DCVS_FTB_WINDOW 16
@@ -143,6 +144,12 @@
unsigned long freq;
};
+struct vidc_input_cr_data {
+ struct list_head list;
+ u32 index;
+ u32 input_cr;
+};
+
struct recon_buf {
struct list_head list;
u32 buffer_index;
@@ -150,6 +157,11 @@
u32 CF;
};
+struct eos_buf {
+ struct list_head list;
+ struct msm_smem smem;
+};
+
struct internal_buf {
struct list_head list;
enum hal_buffer buffer_type;
@@ -321,11 +333,13 @@
struct msm_vidc_format fmts[MAX_PORT_NUM];
struct buf_queue bufq[MAX_PORT_NUM];
struct msm_vidc_list freqs;
+ struct msm_vidc_list input_crs;
struct msm_vidc_list scratchbufs;
struct msm_vidc_list persistbufs;
struct msm_vidc_list pending_getpropq;
struct msm_vidc_list outputbufs;
struct msm_vidc_list reconbufs;
+ struct msm_vidc_list eosbufs;
struct msm_vidc_list registeredbufs;
struct buffer_requirements buff_req;
struct smem_client *mem_client;
@@ -381,16 +395,22 @@
void handle_cmd_response(enum hal_command_response cmd, void *data);
int msm_vidc_trigger_ssr(struct msm_vidc_core *core,
enum hal_ssr_trigger_type type);
+int msm_vidc_noc_error_info(struct msm_vidc_core *core);
int msm_vidc_check_session_supported(struct msm_vidc_inst *inst);
int msm_vidc_check_scaling_supported(struct msm_vidc_inst *inst);
void msm_vidc_queue_v4l2_event(struct msm_vidc_inst *inst, int event_type);
+enum msm_vidc_flags {
+ MSM_VIDC_FLAG_DEFERRED = BIT(0),
+ MSM_VIDC_FLAG_RBR_PENDING = BIT(1),
+};
+
struct msm_vidc_buffer {
struct list_head list;
struct kref kref;
struct msm_smem smem[VIDEO_MAX_PLANES];
struct vb2_v4l2_buffer vvb;
- bool deferred;
+ enum msm_vidc_flags flags;
};
void msm_comm_handle_thermal_event(void);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_platform.c b/drivers/media/platform/msm/vidc/msm_vidc_platform.c
index 8a701cb..7ca6ab0 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_platform.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_platform.c
@@ -44,6 +44,7 @@
CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_ENCODER, 125, 675, 320),
CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_ENCODER, 125, 675, 320),
CODEC_ENTRY(V4L2_PIX_FMT_VP8, MSM_VIDC_ENCODER, 125, 675, 320),
+ CODEC_ENTRY(V4L2_PIX_FMT_TME, MSM_VIDC_ENCODER, 125, 675, 320),
CODEC_ENTRY(V4L2_PIX_FMT_MPEG2, MSM_VIDC_DECODER, 50, 200, 200),
CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_DECODER, 50, 200, 200),
CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_DECODER, 50, 200, 200),
@@ -68,6 +69,10 @@
.value = 1,
},
{
+ .key = "qcom,domain-attr-non-fatal-faults",
+ .value = 1,
+ },
+ {
.key = "qcom,max-secure-instances",
.value = 5,
},
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
index 039b457..46fb75f 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
@@ -785,6 +785,9 @@
"qcom,fw-unload-delay");
res->msm_vidc_hw_rsp_timeout = find_key_value(platform_data,
"qcom,hw-resp-timeout");
+ res->non_fatal_pagefaults = find_key_value(platform_data,
+ "qcom,domain-attr-non-fatal-faults");
+
return rc;
}
@@ -980,8 +983,13 @@
return -EINVAL;
}
- if (core->smmu_fault_handled)
+ if (core->smmu_fault_handled) {
+ if (core->resources.non_fatal_pagefaults) {
+ msm_vidc_noc_error_info(core);
+ MSM_VIDC_ERROR(true);
+ }
return -ENOSYS;
+ }
dprintk(VIDC_ERR, "%s - faulting address: %lx\n", __func__, iova);
@@ -1061,6 +1069,21 @@
goto err_setup_cb;
}
+ if (core->resources.non_fatal_pagefaults) {
+ int data = 1;
+
+ dprintk(VIDC_DBG, "set non-fatal-faults attribute on %s\n",
+ dev_name(dev));
+ rc = iommu_domain_set_attr(cb->mapping->domain,
+ DOMAIN_ATTR_NON_FATAL_FAULTS, &data);
+ if (rc) {
+ dprintk(VIDC_WARN,
+ "%s: set non fatal attribute failed: %s %d\n",
+ __func__, dev_name(dev), rc);
+ /* ignore the error */
+ }
+ }
+
iommu_set_fault_handler(cb->mapping->domain,
msm_vidc_smmu_fault_handler, (void *)core);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_resources.h b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
index 755f0c86..31d5a42 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_resources.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
@@ -161,7 +161,7 @@
uint32_t dcvs_tbl_size;
struct dcvs_limit *dcvs_limit;
bool sys_cache_present;
- bool sys_cache_enabled;
+ bool sys_cache_res_set;
struct subcache_set subcache_set;
struct reg_set reg_set;
struct addr_set qdss_addr_set;
@@ -189,6 +189,7 @@
int msm_vidc_hw_rsp_timeout;
int msm_vidc_firmware_unload_delay;
uint32_t msm_vidc_pwr_collapse_delay;
+ bool non_fatal_pagefaults;
struct msm_vidc_codec_data *codec_data;
int codec_data_count;
};
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index b430d14..82c3ffc 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -99,8 +99,10 @@
static void __unload_fw(struct venus_hfi_device *device);
static int __tzbsp_set_video_state(enum tzbsp_video_state state);
static int __enable_subcaches(struct venus_hfi_device *device);
+static int __set_subcaches(struct venus_hfi_device *device);
+static int __release_subcaches(struct venus_hfi_device *device);
static int __disable_subcaches(struct venus_hfi_device *device);
-
+static int venus_hfi_noc_error_info(void *dev);
/**
* Utility function to enforce some of our assumptions. Spam calls to this
@@ -1088,6 +1090,7 @@
return rc;
}
+ trace_msm_vidc_perf_clock_scale(cl->name, freq);
dprintk(VIDC_PROF, "Scaling clock %s to %u\n",
cl->name, freq);
}
@@ -1747,10 +1750,8 @@
dprintk(VIDC_WARN, "Failed to send image version pkt to f/w\n");
rc = __enable_subcaches(device);
- if (rc) {
- dprintk(VIDC_WARN,
- "Failed to enable subcaches, err = %d\n", rc);
- }
+ if (!rc)
+ __set_subcaches(device);
if (dev->res->pm_qos_latency_us) {
#ifdef CONFIG_SMP
@@ -2804,9 +2805,11 @@
}
}
+ __flush_debug_queue(device, device->raw_packet);
+
rc = __suspend(device);
if (rc)
- dprintk(VIDC_ERR, "Failed venus power off\n");
+ dprintk(VIDC_ERR, "Failed __suspend\n");
/* Cancel pending delayed works if any */
cancel_delayed_work(&venus_hfi_pm_work);
@@ -3405,6 +3408,15 @@
.exit = NULL,
};
+ if (!strcmp(bus->governor, "msm-vidc-llcc")) {
+ if (msm_vidc_syscache_disable) {
+ dprintk(VIDC_DBG,
+ "Skipping LLC bus init %s: %s\n",
+ bus->name, bus->governor);
+ continue;
+ }
+ }
+
/*
* This is stupid, but there's no other easy way to ahold
* of struct bus_info in venus_hfi_devfreq_*()
@@ -3763,39 +3775,64 @@
int rc = 0;
u32 c = 0;
struct subcache_info *sinfo;
- u32 resource[VIDC_MAX_SUBCACHE_SIZE];
- struct hfi_resource_syscache_info_type *sc_res_info;
- struct hfi_resource_subcache_type *sc_res;
- struct vidc_resource_hdr rhdr;
if (msm_vidc_syscache_disable || !is_sys_cache_present(device))
return 0;
- memset((void *)resource, 0x0, (sizeof(u32) * VIDC_MAX_SUBCACHE_SIZE));
-
- sc_res_info = (struct hfi_resource_syscache_info_type *)resource;
- sc_res = &(sc_res_info->rg_subcache_entries[0]);
-
/* Activate subcaches */
venus_hfi_for_each_subcache(device, sinfo) {
rc = llcc_slice_activate(sinfo->subcache);
if (rc) {
dprintk(VIDC_ERR, "Failed to activate %s: %d\n",
sinfo->name, rc);
- continue;
+ goto err_activate_fail;
}
sinfo->isactive = true;
-
- /* Update the entry */
- sc_res[c].size = sinfo->subcache->llcc_slice_size;
- sc_res[c].sc_id = sinfo->subcache->llcc_slice_id;
- dprintk(VIDC_DBG, "Activate subcache %s\n", sinfo->name);
+ dprintk(VIDC_DBG, "Activated subcache %s\n", sinfo->name);
c++;
}
+ dprintk(VIDC_DBG, "Activated %d Subcaches to Venus\n", c);
+
+ return 0;
+
+err_activate_fail:
+ __release_subcaches(device);
+ __disable_subcaches(device);
+ return -EINVAL;
+}
+
+static int __set_subcaches(struct venus_hfi_device *device)
+{
+ int rc = 0;
+ u32 c = 0;
+ struct subcache_info *sinfo;
+ u32 resource[VIDC_MAX_SUBCACHE_SIZE];
+ struct hfi_resource_syscache_info_type *sc_res_info;
+ struct hfi_resource_subcache_type *sc_res;
+ struct vidc_resource_hdr rhdr;
+
+ if (device->res->sys_cache_res_set) {
+ dprintk(VIDC_DBG, "Subcaches already set to Venus\n");
+ return 0;
+ }
+
+ memset((void *)resource, 0x0, (sizeof(u32) * VIDC_MAX_SUBCACHE_SIZE));
+
+ sc_res_info = (struct hfi_resource_syscache_info_type *)resource;
+ sc_res = &(sc_res_info->rg_subcache_entries[0]);
+
+ venus_hfi_for_each_subcache(device, sinfo) {
+ if (sinfo->isactive == true) {
+ sc_res[c].size = sinfo->subcache->llcc_slice_size;
+ sc_res[c].sc_id = sinfo->subcache->llcc_slice_id;
+ c++;
+ }
+ }
+
/* Set resource to Venus for activated subcaches */
if (c) {
- dprintk(VIDC_DBG, "Setting Subcaches\n");
+ dprintk(VIDC_DBG, "Setting %d Subcaches\n", c);
rhdr.resource_handle = sc_res_info; /* cookie */
rhdr.resource_id = VIDC_RESOURCE_SYSCACHE;
@@ -3814,9 +3851,8 @@
sinfo->isset = true;
}
- dprintk(VIDC_DBG, "Activated & Set Subcaches to Venus\n");
-
- device->res->sys_cache_enabled = true;
+ dprintk(VIDC_DBG, "Set Subcaches done to Venus\n");
+ device->res->sys_cache_res_set = true;
return 0;
@@ -3826,7 +3862,7 @@
return rc;
}
-static int __disable_subcaches(struct venus_hfi_device *device)
+static int __release_subcaches(struct venus_hfi_device *device)
{
struct subcache_info *sinfo;
int rc = 0;
@@ -3839,8 +3875,6 @@
if (msm_vidc_syscache_disable || !is_sys_cache_present(device))
return 0;
- dprintk(VIDC_DBG, "Disabling Subcaches\n");
-
memset((void *)resource, 0x0, (sizeof(u32) * VIDC_MAX_SUBCACHE_SIZE));
sc_res_info = (struct hfi_resource_syscache_info_type *)resource;
@@ -3858,16 +3892,29 @@
}
if (c > 0) {
+ dprintk(VIDC_DBG, "Releasing %d subcaches\n", c);
rhdr.resource_handle = sc_res_info; /* cookie */
rhdr.resource_id = VIDC_RESOURCE_SYSCACHE;
rc = __core_release_resource(device, &rhdr);
if (rc)
- dprintk(VIDC_ERR, "Failed to release subcaches\n");
-
- dprintk(VIDC_DBG, "Release %d subcaches\n", c);
+ dprintk(VIDC_ERR,
+ "Failed to release %d subcaches\n", c);
}
+ device->res->sys_cache_res_set = false;
+
+ return rc;
+}
+
+static int __disable_subcaches(struct venus_hfi_device *device)
+{
+ struct subcache_info *sinfo;
+ int rc = 0;
+
+ if (msm_vidc_syscache_disable || !is_sys_cache_present(device))
+ return 0;
+
/* De-activate subcaches */
venus_hfi_for_each_subcache_reverse(device, sinfo) {
if (sinfo->isactive == true) {
@@ -3883,8 +3930,6 @@
}
}
- device->res->sys_cache_enabled = false;
-
return rc;
}
@@ -3984,10 +4029,7 @@
return 0;
}
- dprintk(VIDC_PROF, "Entering power collapse\n");
-
- if (__disable_subcaches(device))
- dprintk(VIDC_ERR, "Failed to disable subcaches\n");
+ dprintk(VIDC_PROF, "Entering suspend\n");
if (device->res->pm_qos_latency_us &&
pm_qos_request_active(&device->qos))
@@ -3999,8 +4041,10 @@
goto err_tzbsp_suspend;
}
+ __disable_subcaches(device);
+
__venus_power_off(device);
- dprintk(VIDC_PROF, "Venus power collapsed\n");
+ dprintk(VIDC_PROF, "Venus power off\n");
return rc;
err_tzbsp_suspend:
@@ -4061,10 +4105,8 @@
__sys_set_debug(device, msm_vidc_fw_debug);
rc = __enable_subcaches(device);
- if (rc) {
- dprintk(VIDC_WARN,
- "Failed to enable subcaches, err = %d\n", rc);
- }
+ if (!rc)
+ __set_subcaches(device);
dprintk(VIDC_PROF, "Resumed from power collapse\n");
exit:
@@ -4231,6 +4273,64 @@
return rc;
}
+static int venus_hfi_noc_error_info(void *dev)
+{
+ struct venus_hfi_device *device;
+ u32 val = 0;
+
+ if (!dev) {
+ dprintk(VIDC_ERR, "%s: null device\n", __func__);
+ return -EINVAL;
+ }
+ device = dev;
+
+ mutex_lock(&device->lock);
+ dprintk(VIDC_ERR, "%s: non error information\n", __func__);
+
+ val = __read_register(device, 0x0C500);
+ dprintk(VIDC_ERR, "NOC_ERR_SWID_LOW(0x00AA0C500): %#x\n", val);
+
+ val = __read_register(device, 0x0C504);
+ dprintk(VIDC_ERR, "NOC_ERR_SWID_HIGH(0x00AA0C504): %#x\n", val);
+
+ val = __read_register(device, 0x0C508);
+ dprintk(VIDC_ERR, "NOC_ERR_MAINCTL_LOW(0x00AA0C508): %#x\n", val);
+
+ val = __read_register(device, 0x0C510);
+ dprintk(VIDC_ERR, "NOC_ERR_ERRVLD_LOW(0x00AA0C510): %#x\n", val);
+
+ val = __read_register(device, 0x0C518);
+ dprintk(VIDC_ERR, "NOC_ERR_ERRCLR_LOW(0x00AA0C518): %#x\n", val);
+
+ val = __read_register(device, 0x0C520);
+ dprintk(VIDC_ERR, "NOC_ERR_ERRLOG0_LOW(0x00AA0C520): %#x\n", val);
+
+ val = __read_register(device, 0x0C524);
+ dprintk(VIDC_ERR, "NOC_ERR_ERRLOG0_HIGH(0x00AA0C524): %#x\n", val);
+
+ val = __read_register(device, 0x0C528);
+ dprintk(VIDC_ERR, "NOC_ERR_ERRLOG1_LOW(0x00AA0C528): %#x\n", val);
+
+ val = __read_register(device, 0x0C52C);
+ dprintk(VIDC_ERR, "NOC_ERR_ERRLOG1_HIGH(0x00AA0C52C): %#x\n", val);
+
+ val = __read_register(device, 0x0C530);
+ dprintk(VIDC_ERR, "NOC_ERR_ERRLOG2_LOW(0x00AA0C530): %#x\n", val);
+
+ val = __read_register(device, 0x0C534);
+ dprintk(VIDC_ERR, "NOC_ERR_ERRLOG2_HIGH(0x00AA0C534): %#x\n", val);
+
+ val = __read_register(device, 0x0C538);
+ dprintk(VIDC_ERR, "NOC_ERR_ERRLOG3_LOW(0x00AA0C538): %#x\n", val);
+
+ val = __read_register(device, 0x0C53C);
+ dprintk(VIDC_ERR, "NOC_ERR_ERRLOG3_HIGH(0x00AA0C53C): %#x\n", val);
+
+ mutex_unlock(&device->lock);
+
+ return 0;
+}
+
static int __initialize_packetization(struct venus_hfi_device *device)
{
int rc = 0;
@@ -4402,6 +4502,7 @@
hdev->get_core_capabilities = venus_hfi_get_core_capabilities;
hdev->suspend = venus_hfi_suspend;
hdev->flush_debug_queue = venus_hfi_flush_debug_queue;
+ hdev->noc_error_info = venus_hfi_noc_error_info;
hdev->get_default_properties = venus_hfi_get_default_properties;
}
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index fbd3b02..f350f25 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -273,6 +273,7 @@
HAL_VIDEO_CODEC_VP8 = 0x00001000,
HAL_VIDEO_CODEC_HEVC = 0x00002000,
HAL_VIDEO_CODEC_VP9 = 0x00004000,
+ HAL_VIDEO_CODEC_TME = 0x00008000,
HAL_VIDEO_CODEC_HEVC_HYBRID = 0x80000000,
HAL_UNUSED_CODEC = 0x10000000,
};
@@ -385,6 +386,17 @@
HAL_VPX_LEVEL_VERSION_3 = 0x00000008,
};
+enum hal_tme_profile {
+ HAL_TME_PROFILE_0 = 0x00000001,
+ HAL_TME_PROFILE_1 = 0x00000002,
+ HAL_TME_PROFILE_2 = 0x00000004,
+ HAL_TME_PROFILE_3 = 0x00000008,
+};
+
+enum hal_tme_level {
+ HAL_TME_LEVEL_INTEGER = 0x00000001,
+};
+
struct hal_frame_rate {
enum hal_buffer buffer_type;
u32 frame_rate;
@@ -1203,6 +1215,7 @@
enum buffer_mode_type alloc_mode_out;
enum buffer_mode_type alloc_mode_in;
u32 pixelprocess_capabilities;
+ u32 tme_version;
};
struct vidc_hal_sys_init_done {
@@ -1345,11 +1358,13 @@
int output_height, output_width;
int compression_ratio;
int complexity_factor;
+ int input_cr;
bool use_dpb_read;
unsigned int lcu_size;
enum msm_vidc_power_mode power_mode;
enum hal_work_mode work_mode;
bool use_sys_cache;
+ bool b_frames_enabled;
};
struct vidc_clk_scale_data {
@@ -1409,6 +1424,7 @@
int (*get_core_capabilities)(void *dev);
int (*suspend)(void *dev);
int (*flush_debug_queue)(void *dev);
+ int (*noc_error_info)(void *dev);
enum hal_default_properties (*get_default_properties)(void *dev);
};
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
index a522918..6a239b3 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
@@ -81,6 +81,7 @@
#define HFI_VIDEO_CODEC_VP8 0x00001000
#define HFI_VIDEO_CODEC_HEVC 0x00002000
#define HFI_VIDEO_CODEC_VP9 0x00004000
+#define HFI_VIDEO_CODEC_TME 0x00008000
#define HFI_PROFILE_UNKNOWN 0x00000000
#define HFI_H264_PROFILE_BASELINE 0x00000001
@@ -150,6 +151,13 @@
#define HFI_HEVC_TIER_MAIN 0x1
#define HFI_HEVC_TIER_HIGH0 0x2
+#define HFI_TME_PROFILE_DEFAULT 0x00000001
+#define HFI_TME_PROFILE_FRC 0x00000002
+#define HFI_TME_PROFILE_ASW 0x00000004
+#define HFI_TME_PROFILE_DFS_BOKEH 0x00000008
+
+#define HFI_TME_LEVEL_INTEGER 0x00000001
+
#define HFI_BUFFER_INPUT (HFI_COMMON_BASE + 0x1)
#define HFI_BUFFER_OUTPUT (HFI_COMMON_BASE + 0x2)
#define HFI_BUFFER_OUTPUT2 (HFI_COMMON_BASE + 0x3)
@@ -229,6 +237,8 @@
(HFI_PROPERTY_PARAM_COMMON_START + 0x011)
#define HFI_PROPERTY_PARAM_WORK_MODE \
(HFI_PROPERTY_PARAM_COMMON_START + 0x015)
+#define HFI_PROPERTY_TME_VERSION_SUPPORTED \
+ (HFI_PROPERTY_PARAM_COMMON_START + 0x016)
#define HFI_PROPERTY_CONFIG_COMMON_START \
(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + 0x2000)
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c
index 52dc794..1da2c94 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
@@ -1099,10 +1099,10 @@
struct s5p_jpeg_ctx *ctx)
{
int c, components = 0, notfound, n_dht = 0, n_dqt = 0;
- unsigned int height, width, word, subsampling = 0, sos = 0, sof = 0,
- sof_len = 0;
- unsigned int dht[S5P_JPEG_MAX_MARKER], dht_len[S5P_JPEG_MAX_MARKER],
- dqt[S5P_JPEG_MAX_MARKER], dqt_len[S5P_JPEG_MAX_MARKER];
+ unsigned int height = 0, width = 0, word, subsampling = 0;
+ unsigned int sos = 0, sof = 0, sof_len = 0;
+ unsigned int dht[S5P_JPEG_MAX_MARKER], dht_len[S5P_JPEG_MAX_MARKER];
+ unsigned int dqt[S5P_JPEG_MAX_MARKER], dqt_len[S5P_JPEG_MAX_MARKER];
long length;
struct s5p_jpeg_buffer jpeg_buffer;
diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c
index 86cc70fe25..2d4b836 100644
--- a/drivers/media/rc/imon.c
+++ b/drivers/media/rc/imon.c
@@ -1629,7 +1629,7 @@
if (kc == KEY_KEYBOARD && !ictx->release_code) {
ictx->last_keycode = kc;
if (!nomouse) {
- ictx->pad_mouse = ~(ictx->pad_mouse) & 0x1;
+ ictx->pad_mouse = !ictx->pad_mouse;
dev_dbg(dev, "toggling to %s mode\n",
ictx->pad_mouse ? "mouse" : "keyboard");
spin_unlock_irqrestore(&ictx->kc_lock, flags);
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c
index 283495c..aab8eee 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c
@@ -320,7 +320,7 @@
static int mxl111sf_i2c_send_data(struct mxl111sf_state *state,
u8 index, u8 *wdata)
{
- int ret = mxl111sf_ctrl_msg(state->d, wdata[0],
+ int ret = mxl111sf_ctrl_msg(state, wdata[0],
&wdata[1], 25, NULL, 0);
mxl_fail(ret);
@@ -330,7 +330,7 @@
static int mxl111sf_i2c_get_data(struct mxl111sf_state *state,
u8 index, u8 *wdata, u8 *rdata)
{
- int ret = mxl111sf_ctrl_msg(state->d, wdata[0],
+ int ret = mxl111sf_ctrl_msg(state, wdata[0],
&wdata[1], 25, rdata, 24);
mxl_fail(ret);
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.c b/drivers/media/usb/dvb-usb-v2/mxl111sf.c
index 5d676b5..f1f4486 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf.c
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.c
@@ -24,9 +24,6 @@
#include "lgdt3305.h"
#include "lg2160.h"
-/* Max transfer size done by I2C transfer functions */
-#define MAX_XFER_SIZE 64
-
int dvb_usb_mxl111sf_debug;
module_param_named(debug, dvb_usb_mxl111sf_debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level "
@@ -56,27 +53,34 @@
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-int mxl111sf_ctrl_msg(struct dvb_usb_device *d,
+int mxl111sf_ctrl_msg(struct mxl111sf_state *state,
u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
{
+ struct dvb_usb_device *d = state->d;
int wo = (rbuf == NULL || rlen == 0); /* write-only */
int ret;
- u8 sndbuf[MAX_XFER_SIZE];
- if (1 + wlen > sizeof(sndbuf)) {
+ if (1 + wlen > MXL_MAX_XFER_SIZE) {
pr_warn("%s: len=%d is too big!\n", __func__, wlen);
return -EOPNOTSUPP;
}
pr_debug("%s(wlen = %d, rlen = %d)\n", __func__, wlen, rlen);
- memset(sndbuf, 0, 1+wlen);
+ mutex_lock(&state->msg_lock);
+ memset(state->sndbuf, 0, 1+wlen);
+ memset(state->rcvbuf, 0, rlen);
- sndbuf[0] = cmd;
- memcpy(&sndbuf[1], wbuf, wlen);
+ state->sndbuf[0] = cmd;
+ memcpy(&state->sndbuf[1], wbuf, wlen);
- ret = (wo) ? dvb_usbv2_generic_write(d, sndbuf, 1+wlen) :
- dvb_usbv2_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen);
+ ret = (wo) ? dvb_usbv2_generic_write(d, state->sndbuf, 1+wlen) :
+ dvb_usbv2_generic_rw(d, state->sndbuf, 1+wlen, state->rcvbuf,
+ rlen);
+
+ memcpy(rbuf, state->rcvbuf, rlen);
+ mutex_unlock(&state->msg_lock);
+
mxl_fail(ret);
return ret;
@@ -92,7 +96,7 @@
u8 buf[2];
int ret;
- ret = mxl111sf_ctrl_msg(state->d, MXL_CMD_REG_READ, &addr, 1, buf, 2);
+ ret = mxl111sf_ctrl_msg(state, MXL_CMD_REG_READ, &addr, 1, buf, 2);
if (mxl_fail(ret)) {
mxl_debug("error reading reg: 0x%02x", addr);
goto fail;
@@ -118,7 +122,7 @@
pr_debug("W: (0x%02x, 0x%02x)\n", addr, data);
- ret = mxl111sf_ctrl_msg(state->d, MXL_CMD_REG_WRITE, buf, 2, NULL, 0);
+ ret = mxl111sf_ctrl_msg(state, MXL_CMD_REG_WRITE, buf, 2, NULL, 0);
if (mxl_fail(ret))
pr_err("error writing reg: 0x%02x, val: 0x%02x", addr, data);
return ret;
@@ -922,6 +926,8 @@
static u8 eeprom[256];
struct i2c_client c;
+ mutex_init(&state->msg_lock);
+
ret = get_chip_info(state);
if (mxl_fail(ret))
pr_err("failed to get chip info during probe");
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.h b/drivers/media/usb/dvb-usb-v2/mxl111sf.h
index 846260e..3e6f588 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf.h
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.h
@@ -19,6 +19,9 @@
#include <media/tveeprom.h>
#include <media/media-entity.h>
+/* Max transfer size done by I2C transfer functions */
+#define MXL_MAX_XFER_SIZE 64
+
#define MXL_EP1_REG_READ 1
#define MXL_EP2_REG_WRITE 2
#define MXL_EP3_INTERRUPT 3
@@ -86,6 +89,9 @@
struct mutex fe_lock;
u8 num_frontends;
struct mxl111sf_adap_state adap_state[3];
+ u8 sndbuf[MXL_MAX_XFER_SIZE];
+ u8 rcvbuf[MXL_MAX_XFER_SIZE];
+ struct mutex msg_lock;
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
struct media_entity tuner;
struct media_pad tuner_pads[2];
@@ -108,7 +114,7 @@
/* needed for hardware i2c functions in mxl111sf-i2c.c:
* mxl111sf_i2c_send_data / mxl111sf_i2c_get_data */
-int mxl111sf_ctrl_msg(struct dvb_usb_device *d,
+int mxl111sf_ctrl_msg(struct mxl111sf_state *state,
u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen);
#define mxl_printk(kern, fmt, arg...) \
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index c2ee6e3..252ab99 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -1992,6 +1992,9 @@
if (!found)
return -ENOENT;
+ if (ctrl->info.size < mapping->size)
+ return -EINVAL;
+
if (mutex_lock_interruptible(&chain->ctrl_mutex))
return -ERESTARTSYS;
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 1d1928a..5e7595c 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -1367,6 +1367,8 @@
descr = "HEVC"; break;
case V4L2_PIX_FMT_VP9:
descr = "VP9"; break;
+ case V4L2_PIX_FMT_TME:
+ descr = "TME"; break;
default:
WARN(1, "Unknown pixelformat 0x%08x\n", fmt->pixelformat);
if (fmt->description[0])
diff --git a/drivers/mfd/msm-cdc-pinctrl.c b/drivers/mfd/msm-cdc-pinctrl.c
index 859a75f..938ffd5 100644
--- a/drivers/mfd/msm-cdc-pinctrl.c
+++ b/drivers/mfd/msm-cdc-pinctrl.c
@@ -217,8 +217,14 @@
gpio_data = dev_get_drvdata(&pdev->dev);
- if (gpio_data && gpio_data->pinctrl)
- devm_pinctrl_put(gpio_data->pinctrl);
+ /* to free the requested gpio before exiting */
+ if (gpio_data) {
+ if (gpio_is_valid(gpio_data->gpio))
+ gpio_free(gpio_data->gpio);
+
+ if (gpio_data->pinctrl)
+ devm_pinctrl_put(gpio_data->pinctrl);
+ }
devm_kfree(&pdev->dev, gpio_data);
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index 232c290..a12d5ca 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -1280,6 +1280,10 @@
ret = -EINVAL;
goto err_codec;
}
+
+ if (pdata->has_buck_vsel_gpio)
+ msm_cdc_pinctrl_select_active_state(pdata->buck_vsel_ctl_np);
+
device_id = slim_get_device_id(slim);
if (!device_id) {
dev_err(&slim->dev, "%s: Error, no device id\n", __func__);
diff --git a/drivers/mfd/wcd9xxx-utils.c b/drivers/mfd/wcd9xxx-utils.c
index 8d3d4ad..f72585a 100644
--- a/drivers/mfd/wcd9xxx-utils.c
+++ b/drivers/mfd/wcd9xxx-utils.c
@@ -342,6 +342,19 @@
goto err_parse_dt_prop;
}
+ pdata->has_buck_vsel_gpio = of_property_read_bool(dev->of_node,
+ "qcom,has-buck-vsel-gpio");
+ if (pdata->has_buck_vsel_gpio) {
+ pdata->buck_vsel_ctl_np = of_parse_phandle(dev->of_node,
+ "qcom,buck-vsel-gpio-node", 0);
+ if (!pdata->buck_vsel_ctl_np) {
+ dev_err(dev, "%s No entry for %s property in node %s\n",
+ __func__, "qcom,buck-vsel-gpio-node",
+ dev->of_node->full_name);
+ goto err_parse_dt_prop;
+ }
+ }
+
if (!(wcd9xxx_read_of_property_u32(dev, "qcom,cdc-mclk-clk-rate",
&prop_val)))
pdata->mclk_rate = prop_val;
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index e203ba6..2e5da54 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -479,6 +479,15 @@
the genalloc API. It is supposed to be used for small on-chip SRAM
areas found on many SoCs.
+config HDCP_QSEECOM
+ tristate "QTI High-Bandwidth Digital Content Protection Module"
+ help
+ This module implements HDCP 2.2 features over external interfaces
+ such as the DisplayPort interface. It exposes APIs for the interface
+ driver to communicate with QTI Secure Execution Environment (QSEE)
+ via the QSEECOM Driver and also communicates with the Receiver via
+ APIs exposed by the interface driver.
+
config QSEECOM
tristate "QTI Secure Execution Communicator driver"
help
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index e1c6ae1..cfea4a5 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -49,6 +49,7 @@
obj-$(CONFIG_SRAM) += sram.o
obj-y += mic/
obj-$(CONFIG_GENWQE) += genwqe/
+obj-$(CONFIG_HDCP_QSEECOM) += hdcp.o
obj-$(CONFIG_QSEECOM) += qseecom.o
obj-$(CONFIG_ECHO) += echo/
obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o
diff --git a/drivers/misc/enclosure.c b/drivers/misc/enclosure.c
index 65fed71..cc91f7b 100644
--- a/drivers/misc/enclosure.c
+++ b/drivers/misc/enclosure.c
@@ -375,6 +375,7 @@
struct device *dev)
{
struct enclosure_component *cdev;
+ int err;
if (!edev || component >= edev->components)
return -EINVAL;
@@ -384,12 +385,17 @@
if (cdev->dev == dev)
return -EEXIST;
- if (cdev->dev)
+ if (cdev->dev) {
enclosure_remove_links(cdev);
-
- put_device(cdev->dev);
+ put_device(cdev->dev);
+ }
cdev->dev = get_device(dev);
- return enclosure_add_links(cdev);
+ err = enclosure_add_links(cdev);
+ if (err) {
+ put_device(cdev->dev);
+ cdev->dev = NULL;
+ }
+ return err;
}
EXPORT_SYMBOL_GPL(enclosure_add_device);
diff --git a/drivers/misc/hdcp.c b/drivers/misc/hdcp.c
new file mode 100644
index 0000000..eab93cc
--- /dev/null
+++ b/drivers/misc/hdcp.c
@@ -0,0 +1,2549 @@
+/* Copyright (c) 2015-2017, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+#define pr_fmt(fmt) "[hdcp-lib] %s: " fmt, __func__
+
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/uaccess.h>
+#include <linux/cdev.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+#include <linux/ion.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+#include <linux/errno.h>
+#include <linux/hdcp_qseecom.h>
+#include <linux/kthread.h>
+#include <linux/of.h>
+#include <video/msm_hdmi_hdcp_mgr.h>
+
+#include "qseecom_kernel.h"
+
+#define CLASS_NAME "hdcp"
+#define DRIVER_NAME "msm_hdcp"
+#define TZAPP_NAME "hdcp2p2"
+#define HDCP1_APP_NAME "hdcp1"
+#define QSEECOM_SBUFF_SIZE 0x1000
+
+#define MAX_TX_MESSAGE_SIZE 129
+#define MAX_RX_MESSAGE_SIZE 534
+#define MAX_TOPOLOGY_ELEMS 32
+#define HDCP1_AKSV_SIZE 8
+
+/* parameters related to LC_Init message */
+#define MESSAGE_ID_SIZE 1
+#define LC_INIT_MESSAGE_SIZE (MESSAGE_ID_SIZE+BITS_64_IN_BYTES)
+
+/* parameters related to SKE_Send_EKS message */
+#define SKE_SEND_EKS_MESSAGE_SIZE \
+ (MESSAGE_ID_SIZE+BITS_128_IN_BYTES+BITS_64_IN_BYTES)
+
+/* all message IDs */
+#define INVALID_MESSAGE_ID 0
+#define AKE_INIT_MESSAGE_ID 2
+#define AKE_SEND_CERT_MESSAGE_ID 3
+#define AKE_NO_STORED_KM_MESSAGE_ID 4
+#define AKE_STORED_KM_MESSAGE_ID 5
+#define AKE_SEND_H_PRIME_MESSAGE_ID 7
+#define AKE_SEND_PAIRING_INFO_MESSAGE_ID 8
+#define LC_INIT_MESSAGE_ID 9
+#define LC_SEND_L_PRIME_MESSAGE_ID 10
+#define SKE_SEND_EKS_MESSAGE_ID 11
+#define REPEATER_AUTH_SEND_RECEIVERID_LIST_MESSAGE_ID 12
+#define REPEATER_AUTH_SEND_ACK_MESSAGE_ID 15
+#define REPEATER_AUTH_STREAM_MANAGE_MESSAGE_ID 16
+#define REPEATER_AUTH_STREAM_READY_MESSAGE_ID 17
+#define SKE_SEND_TYPE_ID 18
+#define HDCP2P2_MAX_MESSAGES 19
+
+#define HDCP1_SET_KEY_MESSAGE_ID 202
+#define HDCP1_SET_ENC_MESSAGE_ID 205
+
+#define BITS_40_IN_BYTES 5
+#define BITS_64_IN_BYTES 8
+#define BITS_128_IN_BYTES 16
+#define RXCAPS_SIZE 3
+#define RXINFO_SIZE 2
+#define SEQ_NUM_V_SIZE 3
+
+#define RCVR_ID_SIZE BITS_40_IN_BYTES
+#define MAX_RCVR_IDS_ALLOWED_IN_LIST 31
+#define MAX_RCVR_ID_LIST_SIZE \
+ (RCVR_ID_SIZE * MAX_RCVR_IDS_ALLOWED_IN_LIST)
+/*
+ * Minimum wait as per standard is 200 ms. Keep it 220 ms
+ * to be on safe side.
+ */
+#define SLEEP_SET_HW_KEY_MS 220
+
+/* hdcp command status */
+#define HDCP_SUCCESS 0
+
+/* flags set by tz in response message */
+#define HDCP_TXMTR_SUBSTATE_WAITING_FOR_RECIEVERID_LIST 1
+
+#define HDCP_TXMTR_SERVICE_ID 0x0001000
+#define SERVICE_CREATE_CMD(x) (HDCP_TXMTR_SERVICE_ID | x)
+
+#define HDCP_TXMTR_INIT SERVICE_CREATE_CMD(1)
+#define HDCP_TXMTR_DEINIT SERVICE_CREATE_CMD(2)
+#define HDCP_TXMTR_PROCESS_RECEIVED_MESSAGE SERVICE_CREATE_CMD(3)
+#define HDCP_TXMTR_SEND_MESSAGE_TIMEOUT SERVICE_CREATE_CMD(4)
+#define HDCP_TXMTR_SET_HW_KEY SERVICE_CREATE_CMD(5)
+#define HDCP_TXMTR_QUERY_STREAM_TYPE SERVICE_CREATE_CMD(6)
+#define HDCP_LIB_INIT SERVICE_CREATE_CMD(11)
+#define HDCP_LIB_DEINIT SERVICE_CREATE_CMD(12)
+#define HDCP_TXMTR_GET_VERSION SERVICE_CREATE_CMD(14)
+#define HDCP_TXMTR_VERIFY_KEY SERVICE_CREATE_CMD(15)
+#define HDCP_SESSION_INIT SERVICE_CREATE_CMD(16)
+#define HDCP_SESSION_DEINIT SERVICE_CREATE_CMD(17)
+#define HDCP_TXMTR_START_AUTHENTICATE SERVICE_CREATE_CMD(18)
+
+#define HCDP_TXMTR_GET_MAJOR_VERSION(v) (((v) >> 16) & 0xFF)
+#define HCDP_TXMTR_GET_MINOR_VERSION(v) (((v) >> 8) & 0xFF)
+#define HCDP_TXMTR_GET_PATCH_VERSION(v) ((v) & 0xFF)
+
+#define HDCP_CLIENT_MAJOR_VERSION 2
+#define HDCP_CLIENT_MINOR_VERSION 1
+#define HDCP_CLIENT_PATCH_VERSION 0
+#define HDCP_CLIENT_MAKE_VERSION(maj, min, patch) \
+ ((((maj) & 0xFF) << 16) | (((min) & 0xFF) << 8) | ((patch) & 0xFF))
+
+#define REAUTH_REQ BIT(3)
+#define LINK_INTEGRITY_FAILURE BIT(4)
+
+#define HDCP_LIB_EXECUTE(x) {\
+ kthread_queue_work(&handle->worker, &handle->wk_##x);\
+}
+
+static const struct hdcp_msg_data hdcp_msg_lookup[HDCP2P2_MAX_MESSAGES] = {
+ [AKE_INIT_MESSAGE_ID] = { 2,
+ { {"rtx", 0x69000, 8}, {"TxCaps", 0x69008, 3} },
+ 0 },
+ [AKE_SEND_CERT_MESSAGE_ID] = { 3,
+ { {"cert-rx", 0x6900B, 522}, {"rrx", 0x69215, 8},
+ {"RxCaps", 0x6921D, 3} },
+ 0 },
+ [AKE_NO_STORED_KM_MESSAGE_ID] = { 1,
+ { {"Ekpub_km", 0x69220, 128} },
+ 0 },
+ [AKE_STORED_KM_MESSAGE_ID] = { 2,
+ { {"Ekh_km", 0x692A0, 16}, {"m", 0x692B0, 16} },
+ 0 },
+ [AKE_SEND_H_PRIME_MESSAGE_ID] = { 1,
+ { {"H'", 0x692C0, 32} },
+ (1 << 1) },
+ [AKE_SEND_PAIRING_INFO_MESSAGE_ID] = { 1,
+ { {"Ekh_km", 0x692E0, 16} },
+ (1 << 2) },
+ [LC_INIT_MESSAGE_ID] = { 1,
+ { {"rn", 0x692F0, 8} },
+ 0 },
+ [LC_SEND_L_PRIME_MESSAGE_ID] = { 1,
+ { {"L'", 0x692F8, 32} },
+ 0 },
+ [SKE_SEND_EKS_MESSAGE_ID] = { 2,
+ { {"Edkey_ks", 0x69318, 16}, {"riv", 0x69328, 8} },
+ 0 },
+ [SKE_SEND_TYPE_ID] = { 1,
+ { {"type", 0x69494, 1} },
+ 0 },
+ [REPEATER_AUTH_SEND_RECEIVERID_LIST_MESSAGE_ID] = { 4,
+ { {"RxInfo", 0x69330, 2}, {"seq_num_V", 0x69332, 3},
+ {"V'", 0x69335, 16}, {"ridlist", 0x69345, 155} },
+ (1 << 0) },
+ [REPEATER_AUTH_SEND_ACK_MESSAGE_ID] = { 1,
+ { {"V", 0x693E0, 16} },
+ 0 },
+ [REPEATER_AUTH_STREAM_MANAGE_MESSAGE_ID] = { 3,
+ { {"seq_num_M", 0x693F0, 3}, {"k", 0x693F3, 2},
+ {"streamID_Type", 0x693F5, 126} },
+ 0 },
+ [REPEATER_AUTH_STREAM_READY_MESSAGE_ID] = { 1,
+ { {"M'", 0x69473, 32} },
+ 0 }
+};
+
+enum hdcp_state {
+ HDCP_STATE_INIT = 0x00,
+ HDCP_STATE_APP_LOADED = 0x01,
+ HDCP_STATE_SESSION_INIT = 0x02,
+ HDCP_STATE_TXMTR_INIT = 0x04,
+ HDCP_STATE_AUTHENTICATED = 0x08,
+ HDCP_STATE_ERROR = 0x10
+};
+
+enum hdcp_element {
+ HDCP_TYPE_UNKNOWN,
+ HDCP_TYPE_RECEIVER,
+ HDCP_TYPE_REPEATER,
+};
+
+enum hdcp_version {
+ HDCP_VERSION_UNKNOWN,
+ HDCP_VERSION_2_2,
+ HDCP_VERSION_1_4
+};
+
+struct receiver_info {
+ unsigned char rcvrInfo[RCVR_ID_SIZE];
+ enum hdcp_element elem_type;
+ enum hdcp_version hdcp_version;
+};
+
+struct topology_info {
+ unsigned int nNumRcvrs;
+ struct receiver_info rcvinfo[MAX_TOPOLOGY_ELEMS];
+};
+
+struct __attribute__ ((__packed__)) hdcp1_key_set_req {
+ uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp1_key_set_rsp {
+ uint32_t commandid;
+ uint32_t ret;
+ uint8_t ksv[HDCP1_AKSV_SIZE];
+};
+
+struct __attribute__ ((__packed__)) hdcp_version_req {
+ uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_version_rsp {
+ uint32_t commandid;
+ uint32_t commandId;
+ uint32_t appversion;
+};
+
+struct __attribute__ ((__packed__)) hdcp_verify_key_req {
+ uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_verify_key_rsp {
+ uint32_t status;
+ uint32_t commandId;
+};
+
+struct __attribute__ ((__packed__)) hdcp_lib_init_req_v1 {
+ uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_lib_init_rsp_v1 {
+ uint32_t status;
+ uint32_t commandid;
+ uint32_t ctxhandle;
+ uint32_t timeout;
+ uint32_t msglen;
+ uint8_t message[MAX_TX_MESSAGE_SIZE];
+};
+
+struct __attribute__ ((__packed__)) hdcp_lib_init_req {
+ uint32_t commandid;
+ uint32_t clientversion;
+};
+
+struct __attribute__ ((__packed__)) hdcp_lib_init_rsp {
+ uint32_t status;
+ uint32_t commandid;
+ uint32_t appversion;
+};
+
+struct __attribute__ ((__packed__)) hdcp_lib_deinit_req {
+ uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_lib_deinit_rsp {
+ uint32_t status;
+ uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_lib_session_init_req {
+ uint32_t commandid;
+ uint32_t deviceid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_lib_session_init_rsp {
+ uint32_t status;
+ uint32_t commandid;
+ uint32_t sessionid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_lib_session_deinit_req {
+ uint32_t commandid;
+ uint32_t sessionid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_lib_session_deinit_rsp {
+ uint32_t status;
+ uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_tx_init_req_v1 {
+ uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_tx_init_rsp_v1 {
+ uint32_t status;
+ uint32_t commandid;
+ uint32_t ctxhandle;
+ uint32_t timeout;
+ uint32_t msglen;
+ uint8_t message[MAX_TX_MESSAGE_SIZE];
+};
+
+struct __attribute__ ((__packed__)) hdcp_tx_init_req {
+ uint32_t commandid;
+ uint32_t sessionid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_tx_init_rsp {
+ uint32_t status;
+ uint32_t commandid;
+ uint32_t ctxhandle;
+};
+
+struct __attribute__ ((__packed__)) hdcp_deinit_req {
+ uint32_t commandid;
+ uint32_t ctxhandle;
+};
+
+struct __attribute__ ((__packed__)) hdcp_deinit_rsp {
+ uint32_t status;
+ uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_rcvd_msg_req {
+ uint32_t commandid;
+ uint32_t ctxhandle;
+ uint32_t msglen;
+ uint8_t msg[MAX_RX_MESSAGE_SIZE];
+};
+
+struct __attribute__ ((__packed__)) hdcp_rcvd_msg_rsp {
+ uint32_t status;
+ uint32_t commandid;
+ uint32_t state;
+ uint32_t timeout;
+ uint32_t flag;
+ uint32_t msglen;
+ uint8_t msg[MAX_TX_MESSAGE_SIZE];
+};
+
+struct __attribute__ ((__packed__)) hdcp_set_hw_key_req {
+ uint32_t commandid;
+ uint32_t ctxhandle;
+};
+
+struct __attribute__ ((__packed__)) hdcp_set_hw_key_rsp {
+ uint32_t status;
+ uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_send_timeout_req {
+ uint32_t commandid;
+ uint32_t ctxhandle;
+};
+
+struct __attribute__ ((__packed__)) hdcp_send_timeout_rsp {
+ uint32_t status;
+ uint32_t commandid;
+ uint32_t timeout;
+ uint32_t msglen;
+ uint8_t message[MAX_TX_MESSAGE_SIZE];
+};
+
+struct __attribute__ ((__packed__)) hdcp_query_stream_type_req {
+ uint32_t commandid;
+ uint32_t ctxhandle;
+};
+
+struct __attribute__ ((__packed__)) hdcp_query_stream_type_rsp {
+ uint32_t status;
+ uint32_t commandid;
+ uint32_t timeout;
+ uint32_t msglen;
+ uint8_t msg[MAX_TX_MESSAGE_SIZE];
+};
+
+struct __attribute__ ((__packed__)) hdcp_set_stream_type_req {
+ uint32_t commandid;
+ uint32_t ctxhandle;
+ uint8_t streamtype;
+};
+
+struct __attribute__ ((__packed__)) hdcp_set_stream_type_rsp {
+ uint32_t status;
+ uint32_t commandid;
+ uint32_t timeout;
+ uint32_t msglen;
+ uint8_t message[MAX_TX_MESSAGE_SIZE];
+};
+
+struct __attribute__ ((__packed__)) hdcp_update_srm_req {
+ uint32_t commandid;
+ uint32_t ctxhandle;
+ uint32_t srmoffset;
+ uint32_t srmlength;
+};
+
+struct __attribute__ ((__packed__)) hdcp_update_srm_rsp {
+ uint32_t status;
+ uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_get_topology_req {
+ uint32_t commandid;
+ uint32_t ctxhandle;
+};
+
+struct __attribute__ ((__packed__)) hdcp_get_topology_rsp {
+ uint32_t status;
+ uint32_t commandid;
+ struct topology_info topologyinfo;
+};
+
+struct __attribute__ ((__packed__)) rxvr_info_struct {
+ uint8_t rcvrCert[522];
+ uint8_t rrx[BITS_64_IN_BYTES];
+ uint8_t rxcaps[RXCAPS_SIZE];
+ bool repeater;
+};
+
+struct __attribute__ ((__packed__)) repeater_info_struct {
+ uint8_t RxInfo[RXINFO_SIZE];
+ uint8_t seq_num_V[SEQ_NUM_V_SIZE];
+ bool seq_num_V_Rollover_flag;
+ uint8_t ReceiverIDList[MAX_RCVR_ID_LIST_SIZE];
+ uint32_t ReceiverIDListLen;
+};
+
+struct __attribute__ ((__packed__)) hdcp1_set_enc_req {
+ uint32_t commandid;
+ uint32_t enable;
+};
+
+struct __attribute__ ((__packed__)) hdcp1_set_enc_rsp {
+ uint32_t commandid;
+ uint32_t ret;
+};
+
+struct __attribute__ ((__packed__)) hdcp_start_auth_req {
+ uint32_t commandid;
+ uint32_t ctxHandle;
+};
+
+struct __attribute__ ((__packed__)) hdcp_start_auth_rsp {
+ uint32_t status;
+ uint32_t commandid;
+ uint32_t ctxhandle;
+ uint32_t timeout;
+ uint32_t msglen;
+ uint8_t message[MAX_TX_MESSAGE_SIZE];
+};
+
+struct hdcp_lib_handle {
+ unsigned char *listener_buf;
+ uint32_t msglen;
+ uint32_t tz_ctxhandle;
+ uint32_t hdcp_timeout;
+ uint32_t timeout_left;
+ uint32_t wait_timeout;
+ bool no_stored_km_flag;
+ bool feature_supported;
+ bool authenticated;
+ void *client_ctx;
+ struct hdcp_client_ops *client_ops;
+ struct mutex msg_lock;
+ struct mutex wakeup_mutex;
+ enum hdcp_state hdcp_state;
+ enum hdcp_lib_wakeup_cmd wakeup_cmd;
+ bool repeater_flag;
+ bool update_stream;
+ struct qseecom_handle *qseecom_handle;
+ int last_msg_sent;
+ int last_msg;
+ char *last_msg_recvd_buf;
+ uint32_t last_msg_recvd_len;
+ atomic_t hdcp_off;
+ uint32_t session_id;
+ enum hdcp_device_type device_type;
+
+ struct task_struct *thread;
+ struct completion poll_wait;
+
+ struct kthread_worker worker;
+ struct kthread_work wk_init;
+ struct kthread_work wk_msg_sent;
+ struct kthread_work wk_msg_recvd;
+ struct kthread_work wk_timeout;
+ struct kthread_work wk_clean;
+ struct kthread_work wk_wait;
+ struct kthread_work wk_stream;
+
+ int (*hdcp_app_init)(struct hdcp_lib_handle *handle);
+ int (*hdcp_txmtr_init)(struct hdcp_lib_handle *handle);
+};
+
+struct hdcp_lib_message_map {
+ int msg_id;
+ const char *msg_name;
+};
+
+struct msm_hdcp_mgr {
+ struct platform_device *pdev;
+ dev_t dev_num;
+ struct cdev cdev;
+ struct class *class;
+ struct device *device;
+ struct HDCP_V2V1_MSG_TOPOLOGY cached_tp;
+ u32 tp_msgid;
+ void *client_ctx;
+ struct hdcp_lib_handle *handle;
+};
+
+static struct msm_hdcp_mgr *hdcp_drv_mgr;
+static struct hdcp_lib_handle *drv_client_handle;
+
+static void hdcp_lib_clean(struct hdcp_lib_handle *handle);
+static void hdcp_lib_init(struct hdcp_lib_handle *handle);
+static void hdcp_lib_msg_sent(struct hdcp_lib_handle *handle);
+static void hdcp_lib_msg_recvd(struct hdcp_lib_handle *handle);
+static void hdcp_lib_timeout(struct hdcp_lib_handle *handle);
+static void hdcp_lib_stream(struct hdcp_lib_handle *handle);
+static int hdcp_lib_txmtr_init(struct hdcp_lib_handle *handle);
+
+static struct qseecom_handle *hdcp1_handle;
+static bool hdcp1_supported = true;
+static bool hdcp1_enc_enabled;
+static struct mutex hdcp1_ta_cmd_lock;
+
+static const char *hdcp_lib_message_name(int msg_id)
+{
+ /*
+ * Message ID map. The first number indicates the message number
+ * assigned to the message by the HDCP 2.2 spec. This is also the first
+ * byte of every HDCP 2.2 authentication protocol message.
+ */
+ static struct hdcp_lib_message_map hdcp_lib_msg_map[] = {
+ {2, "AKE_INIT"},
+ {3, "AKE_SEND_CERT"},
+ {4, "AKE_NO_STORED_KM"},
+ {5, "AKE_STORED_KM"},
+ {7, "AKE_SEND_H_PRIME"},
+ {8, "AKE_SEND_PAIRING_INFO"},
+ {9, "LC_INIT"},
+ {10, "LC_SEND_L_PRIME"},
+ {11, "SKE_SEND_EKS"},
+ {12, "REPEATER_AUTH_SEND_RECEIVERID_LIST"},
+ {15, "REPEATER_AUTH_SEND_ACK"},
+ {16, "REPEATER_AUTH_STREAM_MANAGE"},
+ {17, "REPEATER_AUTH_STREAM_READY"},
+ {18, "SKE_SEND_TYPE_ID"},
+ };
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(hdcp_lib_msg_map); i++) {
+ if (msg_id == hdcp_lib_msg_map[i].msg_id)
+ return hdcp_lib_msg_map[i].msg_name;
+ }
+ return "UNKNOWN";
+}
+
+static int hdcp_lib_get_next_message(struct hdcp_lib_handle *handle,
+ struct hdcp_wakeup_data *data)
+{
+ switch (handle->last_msg) {
+ case INVALID_MESSAGE_ID:
+ return AKE_INIT_MESSAGE_ID;
+ case AKE_INIT_MESSAGE_ID:
+ return AKE_SEND_CERT_MESSAGE_ID;
+ case AKE_SEND_CERT_MESSAGE_ID:
+ if (handle->no_stored_km_flag)
+ return AKE_NO_STORED_KM_MESSAGE_ID;
+ else
+ return AKE_STORED_KM_MESSAGE_ID;
+ case AKE_STORED_KM_MESSAGE_ID:
+ case AKE_NO_STORED_KM_MESSAGE_ID:
+ return AKE_SEND_H_PRIME_MESSAGE_ID;
+ case AKE_SEND_H_PRIME_MESSAGE_ID:
+ if (handle->no_stored_km_flag)
+ return AKE_SEND_PAIRING_INFO_MESSAGE_ID;
+ else
+ return LC_INIT_MESSAGE_ID;
+ case AKE_SEND_PAIRING_INFO_MESSAGE_ID:
+ return LC_INIT_MESSAGE_ID;
+ case LC_INIT_MESSAGE_ID:
+ return LC_SEND_L_PRIME_MESSAGE_ID;
+ case LC_SEND_L_PRIME_MESSAGE_ID:
+ return SKE_SEND_EKS_MESSAGE_ID;
+ case SKE_SEND_EKS_MESSAGE_ID:
+ if (!handle->repeater_flag)
+ return SKE_SEND_TYPE_ID;
+ case SKE_SEND_TYPE_ID:
+ case REPEATER_AUTH_STREAM_READY_MESSAGE_ID:
+ case REPEATER_AUTH_SEND_ACK_MESSAGE_ID:
+ if (!handle->repeater_flag)
+ return INVALID_MESSAGE_ID;
+
+ if (data->cmd == HDCP_WKUP_CMD_SEND_MESSAGE)
+ return REPEATER_AUTH_STREAM_MANAGE_MESSAGE_ID;
+ else
+ return REPEATER_AUTH_SEND_RECEIVERID_LIST_MESSAGE_ID;
+ case REPEATER_AUTH_SEND_RECEIVERID_LIST_MESSAGE_ID:
+ return REPEATER_AUTH_SEND_ACK_MESSAGE_ID;
+ case REPEATER_AUTH_STREAM_MANAGE_MESSAGE_ID:
+ return REPEATER_AUTH_STREAM_READY_MESSAGE_ID;
+ default:
+ pr_err("Uknown message ID (%d)", handle->last_msg);
+ return -EINVAL;
+ }
+}
+
+static void hdcp_lib_wait_for_response(struct hdcp_lib_handle *handle,
+ struct hdcp_wakeup_data *data)
+{
+ switch (handle->last_msg) {
+ case AKE_SEND_H_PRIME_MESSAGE_ID:
+ if (handle->no_stored_km_flag)
+ handle->wait_timeout = HZ;
+ else
+ handle->wait_timeout = HZ / 4;
+ break;
+ case AKE_SEND_PAIRING_INFO_MESSAGE_ID:
+ handle->wait_timeout = HZ / 4;
+ break;
+ case REPEATER_AUTH_SEND_RECEIVERID_LIST_MESSAGE_ID:
+ if (!handle->authenticated)
+ handle->wait_timeout = HZ * 3;
+ else
+ handle->wait_timeout = 0;
+ break;
+ default:
+ handle->wait_timeout = 0;
+ }
+
+ if (handle->wait_timeout)
+ kthread_queue_work(&handle->worker, &handle->wk_wait);
+}
+
+static void hdcp_lib_wakeup_client(struct hdcp_lib_handle *handle,
+ struct hdcp_wakeup_data *data)
+{
+ int rc = 0, i;
+
+ if (!handle || !handle->client_ops || !handle->client_ops->wakeup ||
+ !data || (data->cmd == HDCP_WKUP_CMD_INVALID))
+ return;
+
+ data->abort_mask = REAUTH_REQ | LINK_INTEGRITY_FAILURE;
+
+ if (data->cmd == HDCP_WKUP_CMD_RECV_MESSAGE ||
+ data->cmd == HDCP_WKUP_CMD_LINK_POLL)
+ handle->last_msg = hdcp_lib_get_next_message(handle, data);
+
+ if (handle->last_msg != INVALID_MESSAGE_ID &&
+ data->cmd != HDCP_WKUP_CMD_STATUS_SUCCESS &&
+ data->cmd != HDCP_WKUP_CMD_STATUS_FAILED) {
+ u32 msg_num, rx_status;
+ const struct hdcp_msg_part *msg;
+
+ pr_debug("lib->client: %s (%s)\n",
+ hdcp_cmd_to_str(data->cmd),
+ hdcp_lib_message_name(handle->last_msg));
+
+ data->message_data = &hdcp_msg_lookup[handle->last_msg];
+
+ msg_num = data->message_data->num_messages;
+ msg = data->message_data->messages;
+ rx_status = data->message_data->rx_status;
+
+ pr_debug("%10s | %6s | %4s\n", "name", "offset", "len");
+
+ for (i = 0; i < msg_num; i++)
+ pr_debug("%10s | %6x | %4d\n",
+ msg[i].name, msg[i].offset,
+ msg[i].length);
+ } else {
+ pr_debug("lib->client: %s\n", hdcp_cmd_to_str(data->cmd));
+ }
+
+ rc = handle->client_ops->wakeup(data);
+ if (rc)
+ pr_err("error sending %s to client\n",
+ hdcp_cmd_to_str(data->cmd));
+
+ hdcp_lib_wait_for_response(handle, data);
+}
+
+static inline void hdcp_lib_send_message(struct hdcp_lib_handle *handle)
+{
+ char msg_name[50];
+ struct hdcp_wakeup_data cdata = {
+ HDCP_WKUP_CMD_SEND_MESSAGE
+ };
+
+ cdata.context = handle->client_ctx;
+ cdata.send_msg_buf = handle->listener_buf;
+ cdata.send_msg_len = handle->msglen;
+ cdata.timeout = handle->hdcp_timeout;
+
+ snprintf(msg_name, sizeof(msg_name), "%s: ",
+ hdcp_lib_message_name((int)cdata.send_msg_buf[0]));
+
+ print_hex_dump(KERN_DEBUG, msg_name,
+ DUMP_PREFIX_NONE, 16, 1, cdata.send_msg_buf,
+ cdata.send_msg_len, false);
+
+ hdcp_lib_wakeup_client(handle, &cdata);
+}
+
+static int hdcp_lib_enable_encryption(struct hdcp_lib_handle *handle)
+{
+ int rc = 0;
+ struct hdcp_set_hw_key_req *req_buf;
+ struct hdcp_set_hw_key_rsp *rsp_buf;
+
+ if (!handle || !handle->qseecom_handle ||
+ !handle->qseecom_handle->sbuf) {
+ pr_err("invalid handle\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ /*
+ * wait at least 200ms before enabling encryption
+ * as per hdcp2p2 sepcifications.
+ */
+ msleep(SLEEP_SET_HW_KEY_MS);
+
+ req_buf = (struct hdcp_set_hw_key_req *)(handle->qseecom_handle->sbuf);
+ req_buf->commandid = HDCP_TXMTR_SET_HW_KEY;
+ req_buf->ctxhandle = handle->tz_ctxhandle;
+
+ rsp_buf = (struct hdcp_set_hw_key_rsp *)
+ (handle->qseecom_handle->sbuf +
+ QSEECOM_ALIGN(sizeof(struct hdcp_set_hw_key_req)));
+
+ rc = qseecom_send_command(handle->qseecom_handle, req_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp_set_hw_key_req)),
+ rsp_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp_set_hw_key_rsp)));
+
+ if ((rc < 0) || (rsp_buf->status < 0)) {
+ pr_err("qseecom cmd failed with err = %d status = %d\n",
+ rc, rsp_buf->status);
+ rc = -EINVAL;
+ goto error;
+ }
+
+ /* reached an authenticated state */
+ handle->hdcp_state |= HDCP_STATE_AUTHENTICATED;
+
+ pr_debug("success\n");
+ return 0;
+error:
+ if (handle && !atomic_read(&handle->hdcp_off))
+ HDCP_LIB_EXECUTE(clean);
+
+ return rc;
+}
+
+static int hdcp_lib_get_version(struct hdcp_lib_handle *handle)
+{
+ int rc = 0;
+ struct hdcp_version_req *req_buf;
+ struct hdcp_version_rsp *rsp_buf;
+ uint32_t app_major_version = 0;
+
+ if (!handle) {
+ pr_err("invalid input\n");
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
+ pr_err("library not loaded\n");
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ /* get the TZ hdcp2p2 app version */
+ req_buf = (struct hdcp_version_req *)handle->qseecom_handle->sbuf;
+ req_buf->commandid = HDCP_TXMTR_GET_VERSION;
+
+ rsp_buf = (struct hdcp_version_rsp *)
+ (handle->qseecom_handle->sbuf +
+ QSEECOM_ALIGN(sizeof(struct hdcp_version_req)));
+
+ rc = qseecom_send_command(handle->qseecom_handle,
+ req_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp_lib_init_req)),
+ rsp_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp_lib_init_rsp)));
+
+ if (rc < 0) {
+ pr_err("qseecom cmd failed err = %d\n", rc);
+ goto exit;
+ }
+
+ app_major_version = HCDP_TXMTR_GET_MAJOR_VERSION(rsp_buf->appversion);
+
+ pr_debug("hdcp2p2 app major version %d, app version %d\n",
+ app_major_version, rsp_buf->appversion);
+
+exit:
+ return rc;
+}
+
+static int hdcp_lib_verify_keys(struct hdcp_lib_handle *handle)
+{
+ int rc = -EINVAL;
+ struct hdcp_verify_key_req *req_buf;
+ struct hdcp_verify_key_rsp *rsp_buf;
+
+ if (!handle) {
+ pr_err("invalid input\n");
+ goto exit;
+ }
+
+ if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
+ pr_err("app not loaded\n");
+ goto exit;
+ }
+
+ req_buf = (struct hdcp_verify_key_req *)handle->qseecom_handle->sbuf;
+ req_buf->commandid = HDCP_TXMTR_VERIFY_KEY;
+
+ rsp_buf = (struct hdcp_verify_key_rsp *)
+ (handle->qseecom_handle->sbuf +
+ QSEECOM_ALIGN(sizeof(struct hdcp_verify_key_req)));
+
+ rc = qseecom_send_command(handle->qseecom_handle,
+ req_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp_verify_key_req)),
+ rsp_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp_verify_key_rsp)));
+
+ if (rc < 0) {
+ pr_err("qseecom cmd failed err = %d\n", rc);
+ goto exit;
+ }
+
+ return rsp_buf->status;
+exit:
+ return rc;
+}
+
+static int hdcp_app_init(struct hdcp_lib_handle *handle)
+{
+ int rc = 0;
+ struct hdcp_lib_init_req *req_buf;
+ struct hdcp_lib_init_rsp *rsp_buf;
+ uint32_t app_minor_version = 0;
+
+ if (!handle) {
+ pr_err("invalid input\n");
+ goto exit;
+ }
+
+ if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
+ pr_err("library not loaded\n");
+ goto exit;
+ }
+
+ /* now load the app by sending hdcp_lib_init */
+ req_buf = (struct hdcp_lib_init_req *)handle->qseecom_handle->sbuf;
+ req_buf->commandid = HDCP_LIB_INIT;
+ req_buf->clientversion =
+ HDCP_CLIENT_MAKE_VERSION(HDCP_CLIENT_MAJOR_VERSION,
+ HDCP_CLIENT_MINOR_VERSION,
+ HDCP_CLIENT_PATCH_VERSION);
+ rsp_buf = (struct hdcp_lib_init_rsp *)
+ (handle->qseecom_handle->sbuf +
+ QSEECOM_ALIGN(sizeof(struct hdcp_lib_init_req)));
+
+ rc = qseecom_send_command(handle->qseecom_handle,
+ req_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp_lib_init_req)),
+ rsp_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp_lib_init_rsp)));
+
+ if (rc < 0) {
+ pr_err("qseecom cmd failed err = %d\n", rc);
+ goto exit;
+ }
+
+ app_minor_version = HCDP_TXMTR_GET_MINOR_VERSION(rsp_buf->appversion);
+ if (app_minor_version != HDCP_CLIENT_MINOR_VERSION) {
+ pr_err
+ ("client-app minor version mismatch app(%d), client(%d)\n",
+ app_minor_version, HDCP_CLIENT_MINOR_VERSION);
+ rc = -1;
+ goto exit;
+ }
+ pr_debug("success\n");
+ pr_debug("client version major(%d), minor(%d), patch(%d)\n",
+ HDCP_CLIENT_MAJOR_VERSION, HDCP_CLIENT_MINOR_VERSION,
+ HDCP_CLIENT_PATCH_VERSION);
+ pr_debug("app version major(%d), minor(%d), patch(%d)\n",
+ HCDP_TXMTR_GET_MAJOR_VERSION(rsp_buf->appversion),
+ HCDP_TXMTR_GET_MINOR_VERSION(rsp_buf->appversion),
+ HCDP_TXMTR_GET_PATCH_VERSION(rsp_buf->appversion));
+
+exit:
+ return rc;
+}
+
+static int hdcp_lib_library_load(struct hdcp_lib_handle *handle)
+{
+ int rc = 0;
+
+ if (!handle) {
+ pr_err("invalid input\n");
+ goto exit;
+ }
+
+ if (handle->hdcp_state & HDCP_STATE_APP_LOADED) {
+ pr_err("library already loaded\n");
+ goto exit;
+ }
+
+ /*
+ * allocating resource for qseecom handle
+ * the app is not loaded here
+ */
+ rc = qseecom_start_app(&(handle->qseecom_handle),
+ TZAPP_NAME, QSEECOM_SBUFF_SIZE);
+ if (rc) {
+ pr_err("qseecom_start_app failed %d\n", rc);
+ goto exit;
+ }
+
+ handle->hdcp_state |= HDCP_STATE_APP_LOADED;
+ pr_debug("qseecom_start_app success\n");
+
+ rc = hdcp_lib_get_version(handle);
+ if (rc) {
+ pr_err("library get version failed\n");
+ goto exit;
+ }
+
+ handle->hdcp_app_init = hdcp_app_init;
+ handle->hdcp_txmtr_init = hdcp_lib_txmtr_init;
+
+ if (handle->hdcp_app_init == NULL) {
+ pr_err("invalid app init function pointer\n");
+ goto exit;
+ }
+
+ rc = handle->hdcp_app_init(handle);
+ if (rc) {
+ pr_err("app init failed\n");
+ goto exit;
+ }
+exit:
+ return rc;
+}
+
+static int hdcp_lib_library_unload(struct hdcp_lib_handle *handle)
+{
+ int rc = 0;
+ struct hdcp_lib_deinit_req *req_buf;
+ struct hdcp_lib_deinit_rsp *rsp_buf;
+
+ if (!handle || !handle->qseecom_handle ||
+ !handle->qseecom_handle->sbuf) {
+ pr_err("invalid handle\n");
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
+ pr_err("library not loaded\n");
+ return rc;
+ }
+
+ /* unloading app by sending hdcp_lib_deinit cmd */
+ req_buf = (struct hdcp_lib_deinit_req *)handle->qseecom_handle->sbuf;
+ req_buf->commandid = HDCP_LIB_DEINIT;
+ rsp_buf = (struct hdcp_lib_deinit_rsp *)
+ (handle->qseecom_handle->sbuf +
+ QSEECOM_ALIGN(sizeof(struct hdcp_lib_deinit_req)));
+
+ rc = qseecom_send_command(handle->qseecom_handle,
+ req_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp_lib_deinit_req)),
+ rsp_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp_lib_deinit_rsp)));
+
+ if (rc < 0) {
+ pr_err("qseecom cmd failed err = %d\n", rc);
+ goto exit;
+ }
+
+ /* deallocate the resources for qseecom handle */
+ rc = qseecom_shutdown_app(&handle->qseecom_handle);
+ if (rc) {
+ pr_err("qseecom_shutdown_app failed err: %d\n", rc);
+ goto exit;
+ }
+
+ handle->hdcp_state &= ~HDCP_STATE_APP_LOADED;
+ pr_debug("success\n");
+exit:
+ return rc;
+}
+
+static int hdcp_lib_session_init(struct hdcp_lib_handle *handle)
+{
+ int rc = 0;
+ struct hdcp_lib_session_init_req *req_buf;
+ struct hdcp_lib_session_init_rsp *rsp_buf;
+
+ if (!handle || !handle->qseecom_handle ||
+ !handle->qseecom_handle->sbuf) {
+ pr_err("invalid handle\n");
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
+ pr_err("app not loaded\n");
+ goto exit;
+ }
+
+ if (handle->hdcp_state & HDCP_STATE_SESSION_INIT) {
+ pr_err("session already initialized\n");
+ goto exit;
+ }
+
+ /* send HDCP_Session_Init command to TZ */
+ req_buf =
+ (struct hdcp_lib_session_init_req *)handle->qseecom_handle->sbuf;
+ req_buf->commandid = HDCP_SESSION_INIT;
+ req_buf->deviceid = handle->device_type;
+ rsp_buf = (struct hdcp_lib_session_init_rsp *)
+ (handle->qseecom_handle->sbuf +
+ QSEECOM_ALIGN(sizeof(struct hdcp_lib_session_init_req)));
+
+ rc = qseecom_send_command(handle->qseecom_handle, req_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct
+ hdcp_lib_session_init_req)),
+ rsp_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct
+ hdcp_lib_session_init_rsp)));
+
+ if ((rc < 0) || (rsp_buf->status != HDCP_SUCCESS) ||
+ (rsp_buf->commandid != HDCP_SESSION_INIT)) {
+ pr_err("qseecom cmd failed with err = %d, status = %d\n",
+ rc, rsp_buf->status);
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ pr_debug("session id %d\n", rsp_buf->sessionid);
+
+ handle->session_id = rsp_buf->sessionid;
+ handle->hdcp_state |= HDCP_STATE_SESSION_INIT;
+
+ pr_debug("success\n");
+exit:
+ return rc;
+}
+
+static int hdcp_lib_session_deinit(struct hdcp_lib_handle *handle)
+{
+ int rc = 0;
+ struct hdcp_lib_session_deinit_req *req_buf;
+ struct hdcp_lib_session_deinit_rsp *rsp_buf;
+
+ if (!handle || !handle->qseecom_handle ||
+ !handle->qseecom_handle->sbuf) {
+ pr_err("invalid handle\n");
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
+ pr_err("app not loaded\n");
+ goto exit;
+ }
+
+ if (!(handle->hdcp_state & HDCP_STATE_SESSION_INIT)) {
+ /* unload library here */
+ pr_err("session not initialized\n");
+ goto exit;
+ }
+
+ /* send command to TZ */
+ req_buf =
+ (struct hdcp_lib_session_deinit_req *)handle->qseecom_handle->sbuf;
+ req_buf->commandid = HDCP_SESSION_DEINIT;
+ req_buf->sessionid = handle->session_id;
+ rsp_buf = (struct hdcp_lib_session_deinit_rsp *)
+ (handle->qseecom_handle->sbuf +
+ QSEECOM_ALIGN(sizeof(struct hdcp_lib_session_deinit_req)));
+
+ rc = qseecom_send_command(handle->qseecom_handle, req_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct
+ hdcp_lib_session_deinit_req)),
+ rsp_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct
+ hdcp_lib_session_deinit_rsp)));
+
+ if ((rc < 0) || (rsp_buf->status < 0) ||
+ (rsp_buf->commandid != HDCP_SESSION_DEINIT)) {
+ pr_err("qseecom cmd failed with err = %d status = %d\n",
+ rc, rsp_buf->status);
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ handle->hdcp_state &= ~HDCP_STATE_SESSION_INIT;
+ pr_debug("success\n");
+exit:
+ return rc;
+}
+
+static int hdcp_lib_txmtr_init(struct hdcp_lib_handle *handle)
+{
+ int rc = 0;
+ struct hdcp_tx_init_req *req_buf;
+ struct hdcp_tx_init_rsp *rsp_buf;
+
+ if (!handle || !handle->qseecom_handle ||
+ !handle->qseecom_handle->sbuf) {
+ pr_err("invalid handle\n");
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ if (!(handle->hdcp_state & HDCP_STATE_SESSION_INIT)) {
+ pr_err("session not initialized\n");
+ goto exit;
+ }
+
+ if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
+ pr_err("library not loaded\n");
+ goto exit;
+ }
+
+ /* send HDCP_Txmtr_Init command to TZ */
+ req_buf = (struct hdcp_tx_init_req *)handle->qseecom_handle->sbuf;
+ req_buf->commandid = HDCP_TXMTR_INIT;
+ req_buf->sessionid = handle->session_id;
+ rsp_buf = (struct hdcp_tx_init_rsp *)
+ (handle->qseecom_handle->sbuf +
+ QSEECOM_ALIGN(sizeof(struct hdcp_tx_init_req)));
+
+ rc = qseecom_send_command(handle->qseecom_handle, req_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp_tx_init_req)),
+ rsp_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp_tx_init_rsp)));
+
+ if ((rc < 0) || (rsp_buf->status != HDCP_SUCCESS) ||
+ (rsp_buf->commandid != HDCP_TXMTR_INIT)) {
+ pr_err("qseecom cmd failed with err = %d, status = %d\n",
+ rc, rsp_buf->status);
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ handle->tz_ctxhandle = rsp_buf->ctxhandle;
+ handle->hdcp_state |= HDCP_STATE_TXMTR_INIT;
+
+ pr_debug("success\n");
+exit:
+ return rc;
+}
+
+static int hdcp_lib_txmtr_deinit(struct hdcp_lib_handle *handle)
+{
+ int rc = 0;
+ struct hdcp_deinit_req *req_buf;
+ struct hdcp_deinit_rsp *rsp_buf;
+
+ if (!handle || !handle->qseecom_handle ||
+ !handle->qseecom_handle->sbuf) {
+ pr_err("invalid handle\n");
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
+ pr_err("app not loaded\n");
+ goto exit;
+ }
+
+ if (!(handle->hdcp_state & HDCP_STATE_TXMTR_INIT)) {
+ /* unload library here */
+ pr_err("txmtr not initialized\n");
+ goto exit;
+ }
+
+ /* send command to TZ */
+ req_buf = (struct hdcp_deinit_req *)handle->qseecom_handle->sbuf;
+ req_buf->commandid = HDCP_TXMTR_DEINIT;
+ req_buf->ctxhandle = handle->tz_ctxhandle;
+ rsp_buf = (struct hdcp_deinit_rsp *)
+ (handle->qseecom_handle->sbuf +
+ QSEECOM_ALIGN(sizeof(struct hdcp_deinit_req)));
+
+ rc = qseecom_send_command(handle->qseecom_handle, req_buf,
+ QSEECOM_ALIGN(sizeof(struct hdcp_deinit_req)),
+ rsp_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp_deinit_rsp)));
+
+ if ((rc < 0) || (rsp_buf->status < 0) ||
+ (rsp_buf->commandid != HDCP_TXMTR_DEINIT)) {
+ pr_err("qseecom cmd failed with err = %d status = %d\n",
+ rc, rsp_buf->status);
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ handle->hdcp_state &= ~HDCP_STATE_TXMTR_INIT;
+ pr_debug("success\n");
+exit:
+ return rc;
+}
+
+static int hdcp_lib_start_auth(struct hdcp_lib_handle *handle)
+{
+ int rc = 0;
+ struct hdcp_start_auth_req *req_buf;
+ struct hdcp_start_auth_rsp *rsp_buf;
+
+ if (!handle || !handle->qseecom_handle ||
+ !handle->qseecom_handle->sbuf) {
+ pr_err("invalid handle\n");
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ if (!(handle->hdcp_state & HDCP_STATE_SESSION_INIT)) {
+ pr_err("session not initialized\n");
+ goto exit;
+ }
+
+ if (!(handle->hdcp_state & HDCP_STATE_TXMTR_INIT)) {
+ pr_err("txmtr not initialized\n");
+ goto exit;
+ }
+
+ /* send HDCP_Txmtr_Start_Auth command to TZ */
+ req_buf = (struct hdcp_start_auth_req *)handle->qseecom_handle->sbuf;
+ req_buf->commandid = HDCP_TXMTR_START_AUTHENTICATE;
+ req_buf->ctxHandle = handle->tz_ctxhandle;
+ rsp_buf = (struct hdcp_start_auth_rsp *)
+ (handle->qseecom_handle->sbuf +
+ QSEECOM_ALIGN(sizeof(struct hdcp_start_auth_req)));
+
+ rc = qseecom_send_command(handle->qseecom_handle, req_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp_start_auth_req)),
+ rsp_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp_start_auth_rsp)));
+
+ if ((rc < 0) || (rsp_buf->status != HDCP_SUCCESS) ||
+ (rsp_buf->commandid != HDCP_TXMTR_START_AUTHENTICATE) ||
+ (rsp_buf->msglen <= 0) || (rsp_buf->message == NULL)) {
+ pr_err("qseecom cmd failed with err = %d, status = %d\n",
+ rc, rsp_buf->status);
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ pr_debug("recvd %s from TZ at %dms\n",
+ hdcp_lib_message_name((int)rsp_buf->message[0]),
+ jiffies_to_msecs(jiffies));
+
+ handle->last_msg = (int)rsp_buf->message[0];
+
+ /* send the response to HDMI driver */
+ memset(handle->listener_buf, 0, MAX_TX_MESSAGE_SIZE);
+ memcpy(handle->listener_buf, (unsigned char *)rsp_buf->message,
+ rsp_buf->msglen);
+ handle->msglen = rsp_buf->msglen;
+ handle->hdcp_timeout = rsp_buf->timeout;
+
+ handle->tz_ctxhandle = rsp_buf->ctxhandle;
+
+ pr_debug("success\n");
+exit:
+ return rc;
+}
+
+static void hdcp_lib_stream(struct hdcp_lib_handle *handle)
+{
+ int rc = 0;
+ struct hdcp_query_stream_type_req *req_buf;
+ struct hdcp_query_stream_type_rsp *rsp_buf;
+
+ if (!handle || !handle->qseecom_handle ||
+ !handle->qseecom_handle->sbuf) {
+ pr_err("invalid handle\n");
+ return;
+ }
+
+ if (atomic_read(&handle->hdcp_off)) {
+ pr_debug("invalid state, hdcp off\n");
+ return;
+ }
+
+ if (!handle->repeater_flag) {
+ pr_debug("invalid state, not a repeater\n");
+ return;
+ }
+
+ /* send command to TZ */
+ req_buf =
+ (struct hdcp_query_stream_type_req *)handle->qseecom_handle->sbuf;
+ req_buf->commandid = HDCP_TXMTR_QUERY_STREAM_TYPE;
+ req_buf->ctxhandle = handle->tz_ctxhandle;
+ rsp_buf = (struct hdcp_query_stream_type_rsp *)
+ (handle->qseecom_handle->sbuf +
+ QSEECOM_ALIGN(sizeof(struct hdcp_query_stream_type_req)));
+
+ rc = qseecom_send_command(handle->qseecom_handle, req_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct
+ hdcp_query_stream_type_req)),
+ rsp_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct
+ hdcp_query_stream_type_rsp)));
+
+ if ((rc < 0) || (rsp_buf->status < 0) || (rsp_buf->msglen <= 0) ||
+ (rsp_buf->commandid != HDCP_TXMTR_QUERY_STREAM_TYPE) ||
+ (rsp_buf->msg == NULL)) {
+ pr_err("qseecom cmd failed with err=%d status=%d\n",
+ rc, rsp_buf->status);
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ pr_debug("message received from TZ: %s\n",
+ hdcp_lib_message_name((int)rsp_buf->msg[0]));
+
+ handle->last_msg = (int)rsp_buf->msg[0];
+
+ memset(handle->listener_buf, 0, MAX_TX_MESSAGE_SIZE);
+ memcpy(handle->listener_buf, (unsigned char *)rsp_buf->msg,
+ rsp_buf->msglen);
+ handle->hdcp_timeout = rsp_buf->timeout;
+ handle->msglen = rsp_buf->msglen;
+exit:
+ if (!rc && !atomic_read(&handle->hdcp_off))
+ hdcp_lib_send_message(handle);
+}
+
+static void hdcp_lib_query_stream_work(struct kthread_work *work)
+{
+ struct hdcp_lib_handle *handle = container_of(work,
+ struct hdcp_lib_handle,
+ wk_stream);
+
+ hdcp_lib_stream(handle);
+}
+
+static bool hdcp_lib_client_feature_supported(void *phdcpcontext)
+{
+ int rc = 0;
+ bool supported = false;
+ struct hdcp_lib_handle *handle = phdcpcontext;
+
+ if (!handle) {
+ pr_err("invalid input\n");
+ goto exit;
+ }
+
+ if (handle->feature_supported) {
+ supported = true;
+ goto exit;
+ }
+
+ rc = hdcp_lib_library_load(handle);
+ if (!rc) {
+ if (!hdcp_lib_verify_keys(handle)) {
+ pr_debug("HDCP2p2 supported\n");
+ handle->feature_supported = true;
+ supported = true;
+ }
+ hdcp_lib_library_unload(handle);
+ }
+exit:
+ return supported;
+}
+
+static void hdcp_lib_check_worker_status(struct hdcp_lib_handle *handle)
+{
+ if (!list_empty(&handle->wk_init.node))
+ pr_debug("init work queued\n");
+
+ if (handle->worker.current_work == &handle->wk_init)
+ pr_debug("init work executing\n");
+
+ if (!list_empty(&handle->wk_msg_sent.node))
+ pr_debug("msg_sent work queued\n");
+
+ if (handle->worker.current_work == &handle->wk_msg_sent)
+ pr_debug("msg_sent work executing\n");
+
+ if (!list_empty(&handle->wk_msg_recvd.node))
+ pr_debug("msg_recvd work queued\n");
+
+ if (handle->worker.current_work == &handle->wk_msg_recvd)
+ pr_debug("msg_recvd work executing\n");
+
+ if (!list_empty(&handle->wk_timeout.node))
+ pr_debug("timeout work queued\n");
+
+ if (handle->worker.current_work == &handle->wk_timeout)
+ pr_debug("timeout work executing\n");
+
+ if (!list_empty(&handle->wk_clean.node))
+ pr_debug("clean work queued\n");
+
+ if (handle->worker.current_work == &handle->wk_clean)
+ pr_debug("clean work executing\n");
+
+ if (!list_empty(&handle->wk_wait.node))
+ pr_debug("wait work queued\n");
+
+ if (handle->worker.current_work == &handle->wk_wait)
+ pr_debug("wait work executing\n");
+
+ if (!list_empty(&handle->wk_stream.node))
+ pr_debug("stream work queued\n");
+
+ if (handle->worker.current_work == &handle->wk_stream)
+ pr_debug("stream work executing\n");
+}
+
+static int hdcp_lib_check_valid_state(struct hdcp_lib_handle *handle)
+{
+ int rc = 0;
+
+ if (!list_empty(&handle->worker.work_list))
+ hdcp_lib_check_worker_status(handle);
+
+ if (handle->wakeup_cmd == HDCP_LIB_WKUP_CMD_START) {
+ if (!list_empty(&handle->worker.work_list)) {
+ pr_debug("error: queue not empty\n");
+ rc = -EBUSY;
+ goto exit;
+ }
+
+ if (handle->hdcp_state & HDCP_STATE_APP_LOADED) {
+ pr_debug("library already loaded\n");
+ rc = -EBUSY;
+ goto exit;
+ }
+ } else {
+ if (atomic_read(&handle->hdcp_off)) {
+ pr_debug("hdcp2.2 session tearing down\n");
+ goto exit;
+ }
+
+ if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
+ pr_debug("hdcp 2.2 app not loaded\n");
+ goto exit;
+ }
+ }
+exit:
+ return rc;
+}
+
+static int hdcp_lib_wakeup_thread(struct hdcp_lib_wakeup_data *data)
+{
+ struct hdcp_lib_handle *handle;
+ int rc = 0;
+
+ if (!data)
+ return -EINVAL;
+
+ handle = data->context;
+ if (!handle)
+ return -EINVAL;
+
+ mutex_lock(&handle->wakeup_mutex);
+
+ handle->wakeup_cmd = data->cmd;
+ handle->timeout_left = data->timeout;
+
+ pr_debug("client->lib: %s (%s)\n",
+ hdcp_lib_cmd_to_str(data->cmd),
+ hdcp_lib_message_name(handle->last_msg));
+
+ rc = hdcp_lib_check_valid_state(handle);
+ if (rc)
+ goto exit;
+
+ mutex_lock(&handle->msg_lock);
+ if (data->recvd_msg_len) {
+ kzfree(handle->last_msg_recvd_buf);
+
+ handle->last_msg_recvd_len = data->recvd_msg_len;
+ handle->last_msg_recvd_buf = kzalloc(data->recvd_msg_len,
+ GFP_KERNEL);
+ if (!handle->last_msg_recvd_buf) {
+ rc = -ENOMEM;
+ mutex_unlock(&handle->msg_lock);
+ goto exit;
+ }
+
+ memcpy(handle->last_msg_recvd_buf, data->recvd_msg_buf,
+ data->recvd_msg_len);
+ }
+ mutex_unlock(&handle->msg_lock);
+
+ if (!completion_done(&handle->poll_wait))
+ complete_all(&handle->poll_wait);
+
+ switch (handle->wakeup_cmd) {
+ case HDCP_LIB_WKUP_CMD_START:
+ handle->no_stored_km_flag = 0;
+ handle->repeater_flag = false;
+ handle->update_stream = false;
+ handle->last_msg_sent = 0;
+ handle->last_msg = INVALID_MESSAGE_ID;
+ handle->hdcp_timeout = 0;
+ handle->timeout_left = 0;
+ atomic_set(&handle->hdcp_off, 0);
+ handle->hdcp_state = HDCP_STATE_INIT;
+
+ HDCP_LIB_EXECUTE(init);
+ break;
+ case HDCP_LIB_WKUP_CMD_STOP:
+ atomic_set(&handle->hdcp_off, 1);
+
+ HDCP_LIB_EXECUTE(clean);
+ break;
+ case HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS:
+ handle->last_msg_sent = handle->listener_buf[0];
+
+ HDCP_LIB_EXECUTE(msg_sent);
+ break;
+ case HDCP_LIB_WKUP_CMD_MSG_SEND_FAILED:
+ case HDCP_LIB_WKUP_CMD_MSG_RECV_FAILED:
+ case HDCP_LIB_WKUP_CMD_LINK_FAILED:
+ handle->hdcp_state |= HDCP_STATE_ERROR;
+ HDCP_LIB_EXECUTE(clean);
+ break;
+ case HDCP_LIB_WKUP_CMD_MSG_RECV_SUCCESS:
+ HDCP_LIB_EXECUTE(msg_recvd);
+ break;
+ case HDCP_LIB_WKUP_CMD_MSG_RECV_TIMEOUT:
+ HDCP_LIB_EXECUTE(timeout);
+ break;
+ case HDCP_LIB_WKUP_CMD_QUERY_STREAM_TYPE:
+ HDCP_LIB_EXECUTE(stream);
+ break;
+ default:
+ pr_err("invalid wakeup command %d\n", handle->wakeup_cmd);
+ }
+exit:
+ mutex_unlock(&handle->wakeup_mutex);
+
+ return rc;
+}
+
+static void hdcp_lib_msg_sent(struct hdcp_lib_handle *handle)
+{
+ struct hdcp_wakeup_data cdata = { HDCP_WKUP_CMD_INVALID };
+
+ if (!handle) {
+ pr_err("invalid handle\n");
+ return;
+ }
+
+ cdata.context = handle->client_ctx;
+
+ switch (handle->last_msg_sent) {
+ case SKE_SEND_TYPE_ID:
+ if (!hdcp_lib_enable_encryption(handle)) {
+ handle->authenticated = true;
+
+ cdata.cmd = HDCP_WKUP_CMD_STATUS_SUCCESS;
+ hdcp_lib_wakeup_client(handle, &cdata);
+ }
+
+ /* poll for link check */
+ cdata.cmd = HDCP_WKUP_CMD_LINK_POLL;
+ break;
+ case SKE_SEND_EKS_MESSAGE_ID:
+ if (handle->repeater_flag) {
+ /* poll for link check */
+ cdata.cmd = HDCP_WKUP_CMD_LINK_POLL;
+ } else {
+ memset(handle->listener_buf, 0, MAX_TX_MESSAGE_SIZE);
+ handle->listener_buf[0] = SKE_SEND_TYPE_ID;
+ handle->msglen = 2;
+ cdata.cmd = HDCP_WKUP_CMD_SEND_MESSAGE;
+ cdata.send_msg_buf = handle->listener_buf;
+ cdata.send_msg_len = handle->msglen;
+ handle->last_msg = hdcp_lib_get_next_message(handle,
+ &cdata);
+ }
+ break;
+ case REPEATER_AUTH_SEND_ACK_MESSAGE_ID:
+ pr_debug("Repeater authentication successful\n");
+
+ if (handle->update_stream) {
+ HDCP_LIB_EXECUTE(stream);
+ handle->update_stream = false;
+ } else {
+ cdata.cmd = HDCP_WKUP_CMD_LINK_POLL;
+ }
+ break;
+ default:
+ cdata.cmd = HDCP_WKUP_CMD_RECV_MESSAGE;
+ cdata.timeout = handle->timeout_left;
+ }
+
+ hdcp_lib_wakeup_client(handle, &cdata);
+}
+
+static void hdcp_lib_msg_sent_work(struct kthread_work *work)
+{
+ struct hdcp_lib_handle *handle = container_of(work,
+ struct hdcp_lib_handle,
+ wk_msg_sent);
+
+ if (handle->wakeup_cmd != HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS) {
+ pr_err("invalid wakeup command %d\n", handle->wakeup_cmd);
+ return;
+ }
+
+ hdcp_lib_msg_sent(handle);
+}
+
+static void hdcp_lib_init(struct hdcp_lib_handle *handle)
+{
+ int rc = 0;
+
+ if (!handle) {
+ pr_err("invalid handle\n");
+ return;
+ }
+
+ if (handle->wakeup_cmd != HDCP_LIB_WKUP_CMD_START) {
+ pr_err("invalid wakeup command %d\n", handle->wakeup_cmd);
+ return;
+ }
+
+ rc = hdcp_lib_library_load(handle);
+ if (rc)
+ goto exit;
+
+ rc = hdcp_lib_session_init(handle);
+ if (rc)
+ goto exit;
+
+ if (handle->hdcp_txmtr_init == NULL) {
+ pr_err("invalid txmtr init function pointer\n");
+ return;
+ }
+
+ rc = handle->hdcp_txmtr_init(handle);
+ if (rc)
+ goto exit;
+
+ rc = hdcp_lib_start_auth(handle);
+ if (rc)
+ goto exit;
+
+ hdcp_lib_send_message(handle);
+
+ return;
+exit:
+ HDCP_LIB_EXECUTE(clean);
+}
+
+static void hdcp_lib_init_work(struct kthread_work *work)
+{
+ struct hdcp_lib_handle *handle = container_of(work,
+ struct hdcp_lib_handle,
+ wk_init);
+
+ hdcp_lib_init(handle);
+}
+
+static void hdcp_lib_timeout(struct hdcp_lib_handle *handle)
+{
+ int rc = 0;
+ struct hdcp_send_timeout_req *req_buf;
+ struct hdcp_send_timeout_rsp *rsp_buf;
+
+ if (!handle || !handle->qseecom_handle ||
+ !handle->qseecom_handle->sbuf) {
+ pr_debug("invalid handle\n");
+ return;
+ }
+
+ if (atomic_read(&handle->hdcp_off)) {
+ pr_debug("invalid state, hdcp off\n");
+ return;
+ }
+
+ req_buf = (struct hdcp_send_timeout_req *)
+ (handle->qseecom_handle->sbuf);
+ req_buf->commandid = HDCP_TXMTR_SEND_MESSAGE_TIMEOUT;
+ req_buf->ctxhandle = handle->tz_ctxhandle;
+
+ rsp_buf = (struct hdcp_send_timeout_rsp *)
+ (handle->qseecom_handle->sbuf +
+ QSEECOM_ALIGN(sizeof(struct hdcp_send_timeout_req)));
+
+ rc = qseecom_send_command(handle->qseecom_handle, req_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp_send_timeout_req)),
+ rsp_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct
+ hdcp_send_timeout_rsp)));
+
+ if ((rc < 0) || (rsp_buf->status != HDCP_SUCCESS)) {
+ pr_err("qseecom cmd failed for with err = %d status = %d\n",
+ rc, rsp_buf->status);
+ rc = -EINVAL;
+ goto error;
+ }
+
+ if (rsp_buf->commandid == HDCP_TXMTR_SEND_MESSAGE_TIMEOUT) {
+ pr_err("HDCP_TXMTR_SEND_MESSAGE_TIMEOUT\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ /*
+ * if the response contains LC_Init message
+ * send the message again to TZ
+ */
+ if ((rsp_buf->commandid == HDCP_TXMTR_PROCESS_RECEIVED_MESSAGE) &&
+ ((int)rsp_buf->message[0] == LC_INIT_MESSAGE_ID) &&
+ (rsp_buf->msglen == LC_INIT_MESSAGE_SIZE)) {
+ if (!atomic_read(&handle->hdcp_off)) {
+ /* keep local copy of TZ response */
+ memset(handle->listener_buf, 0, MAX_TX_MESSAGE_SIZE);
+ memcpy(handle->listener_buf,
+ (unsigned char *)rsp_buf->message,
+ rsp_buf->msglen);
+ handle->hdcp_timeout = rsp_buf->timeout;
+ handle->msglen = rsp_buf->msglen;
+
+ hdcp_lib_send_message(handle);
+ }
+ }
+
+ return;
+error:
+ if (!atomic_read(&handle->hdcp_off))
+ HDCP_LIB_EXECUTE(clean);
+}
+
+static void hdcp_lib_manage_timeout_work(struct kthread_work *work)
+{
+ struct hdcp_lib_handle *handle = container_of(work,
+ struct hdcp_lib_handle,
+ wk_timeout);
+
+ hdcp_lib_timeout(handle);
+}
+
+static void hdcp_lib_clean(struct hdcp_lib_handle *handle)
+{
+ struct hdcp_wakeup_data cdata = { HDCP_WKUP_CMD_INVALID };
+
+ if (!handle) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ handle->authenticated = false;
+
+ hdcp_lib_txmtr_deinit(handle);
+ hdcp_lib_session_deinit(handle);
+ hdcp_lib_library_unload(handle);
+
+ cdata.context = handle->client_ctx;
+ cdata.cmd = HDCP_WKUP_CMD_STATUS_FAILED;
+
+ if (!atomic_read(&handle->hdcp_off))
+ hdcp_lib_wakeup_client(handle, &cdata);
+
+ atomic_set(&handle->hdcp_off, 1);
+}
+
+static void hdcp_lib_cleanup_work(struct kthread_work *work)
+{
+
+ struct hdcp_lib_handle *handle = container_of(work,
+ struct hdcp_lib_handle,
+ wk_clean);
+
+ hdcp_lib_clean(handle);
+}
+
+static void hdcp_lib_msg_recvd(struct hdcp_lib_handle *handle)
+{
+ int rc = 0;
+ struct hdcp_wakeup_data cdata = { HDCP_WKUP_CMD_INVALID };
+ struct hdcp_rcvd_msg_req *req_buf;
+ struct hdcp_rcvd_msg_rsp *rsp_buf;
+ uint32_t msglen;
+ char *msg = NULL;
+ char msg_name[50];
+ uint32_t message_id_bytes = 0;
+
+ if (!handle || !handle->qseecom_handle ||
+ !handle->qseecom_handle->sbuf) {
+ pr_err("invalid handle\n");
+ return;
+ }
+
+ if (atomic_read(&handle->hdcp_off)) {
+ pr_debug("invalid state, hdcp off\n");
+ return;
+ }
+
+ cdata.context = handle->client_ctx;
+
+ mutex_lock(&handle->msg_lock);
+ msglen = handle->last_msg_recvd_len;
+
+ if (msglen <= 0) {
+ pr_err("invalid msg len\n");
+ mutex_unlock(&handle->msg_lock);
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ /* If the client is DP then allocate extra byte for message ID. */
+ if (handle->device_type == HDCP_TXMTR_DP)
+ message_id_bytes = 1;
+
+ msglen += message_id_bytes;
+
+ msg = kzalloc(msglen, GFP_KERNEL);
+ if (!msg) {
+ mutex_unlock(&handle->msg_lock);
+ rc = -ENOMEM;
+ goto exit;
+ }
+
+ /* copy the message id if needed */
+ if (message_id_bytes)
+ memcpy(msg, &handle->last_msg, message_id_bytes);
+
+ memcpy(msg + message_id_bytes,
+ handle->last_msg_recvd_buf,
+ handle->last_msg_recvd_len);
+
+ mutex_unlock(&handle->msg_lock);
+
+ snprintf(msg_name, sizeof(msg_name), "%s: ",
+ hdcp_lib_message_name((int)msg[0]));
+
+ print_hex_dump(KERN_DEBUG, msg_name,
+ DUMP_PREFIX_NONE, 16, 1, msg, msglen, false);
+
+ /* send the message to QSEECOM */
+ req_buf = (struct hdcp_rcvd_msg_req *)(handle->qseecom_handle->sbuf);
+ req_buf->commandid = HDCP_TXMTR_PROCESS_RECEIVED_MESSAGE;
+ memcpy(req_buf->msg, msg, msglen);
+ req_buf->msglen = msglen;
+ req_buf->ctxhandle = handle->tz_ctxhandle;
+
+ rsp_buf =
+ (struct hdcp_rcvd_msg_rsp *)(handle->qseecom_handle->sbuf +
+ QSEECOM_ALIGN(sizeof
+ (struct
+ hdcp_rcvd_msg_req)));
+
+ pr_debug("writing %s to TZ at %dms\n",
+ hdcp_lib_message_name((int)msg[0]), jiffies_to_msecs(jiffies));
+
+ rc = qseecom_send_command(handle->qseecom_handle, req_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp_rcvd_msg_req)),
+ rsp_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp_rcvd_msg_rsp)));
+
+ /* get next message from sink if we receive H PRIME on no store km */
+ if ((msg[0] == AKE_SEND_H_PRIME_MESSAGE_ID) &&
+ handle->no_stored_km_flag) {
+ handle->hdcp_timeout = rsp_buf->timeout;
+
+ cdata.cmd = HDCP_WKUP_CMD_RECV_MESSAGE;
+ cdata.timeout = handle->hdcp_timeout;
+
+ goto exit;
+ }
+
+ if ((msg[0] == REPEATER_AUTH_STREAM_READY_MESSAGE_ID) &&
+ (rc == 0) && (rsp_buf->status == 0)) {
+ pr_debug("Got Auth_Stream_Ready, nothing sent to rx\n");
+
+ if (!handle->authenticated &&
+ !hdcp_lib_enable_encryption(handle)) {
+ handle->authenticated = true;
+
+ cdata.cmd = HDCP_WKUP_CMD_STATUS_SUCCESS;
+ hdcp_lib_wakeup_client(handle, &cdata);
+ }
+
+ cdata.cmd = HDCP_WKUP_CMD_LINK_POLL;
+ goto exit;
+ }
+
+ if ((rc < 0) || (rsp_buf->status != 0) || (rsp_buf->msglen <= 0) ||
+ (rsp_buf->commandid != HDCP_TXMTR_PROCESS_RECEIVED_MESSAGE) ||
+ (rsp_buf->msg == NULL)) {
+ pr_err("qseecom cmd failed with err=%d status=%d\n",
+ rc, rsp_buf->status);
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ pr_debug("recvd %s from TZ at %dms\n",
+ hdcp_lib_message_name((int)rsp_buf->msg[0]),
+ jiffies_to_msecs(jiffies));
+
+ handle->last_msg = (int)rsp_buf->msg[0];
+
+ /* set the flag if response is AKE_No_Stored_km */
+ if (((int)rsp_buf->msg[0] == AKE_NO_STORED_KM_MESSAGE_ID)) {
+ pr_debug("Setting no_stored_km_flag\n");
+ handle->no_stored_km_flag = 1;
+ } else {
+ handle->no_stored_km_flag = 0;
+ }
+
+ /* check if it's a repeater */
+ if ((rsp_buf->msg[0] == SKE_SEND_EKS_MESSAGE_ID) &&
+ (rsp_buf->msglen == SKE_SEND_EKS_MESSAGE_SIZE)) {
+ if ((rsp_buf->flag ==
+ HDCP_TXMTR_SUBSTATE_WAITING_FOR_RECIEVERID_LIST) &&
+ (rsp_buf->timeout > 0))
+ handle->repeater_flag = true;
+ handle->update_stream = true;
+ }
+
+ memset(handle->listener_buf, 0, MAX_TX_MESSAGE_SIZE);
+ memcpy(handle->listener_buf, (unsigned char *)rsp_buf->msg,
+ rsp_buf->msglen);
+ handle->hdcp_timeout = rsp_buf->timeout;
+ handle->msglen = rsp_buf->msglen;
+
+ if (!atomic_read(&handle->hdcp_off))
+ hdcp_lib_send_message(handle);
+exit:
+ kzfree(msg);
+
+ hdcp_lib_wakeup_client(handle, &cdata);
+
+ if (rc && !atomic_read(&handle->hdcp_off))
+ HDCP_LIB_EXECUTE(clean);
+}
+
+static void hdcp_lib_msg_recvd_work(struct kthread_work *work)
+{
+ struct hdcp_lib_handle *handle = container_of(work,
+ struct hdcp_lib_handle,
+ wk_msg_recvd);
+
+ hdcp_lib_msg_recvd(handle);
+}
+
+static void hdcp_lib_wait_work(struct kthread_work *work)
+{
+ u32 timeout;
+ struct hdcp_lib_handle *handle = container_of(work,
+ struct hdcp_lib_handle, wk_wait);
+
+ if (!handle) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ if (atomic_read(&handle->hdcp_off)) {
+ pr_debug("invalid state: hdcp off\n");
+ return;
+ }
+
+ if (handle->hdcp_state & HDCP_STATE_ERROR) {
+ pr_debug("invalid state: hdcp error\n");
+ return;
+ }
+
+ reinit_completion(&handle->poll_wait);
+ timeout = wait_for_completion_timeout(&handle->poll_wait,
+ handle->wait_timeout);
+ if (!timeout) {
+ pr_err("wait timeout\n");
+
+ if (!atomic_read(&handle->hdcp_off))
+ HDCP_LIB_EXECUTE(clean);
+ }
+
+ handle->wait_timeout = 0;
+}
+
+bool hdcp1_check_if_supported_load_app(void)
+{
+ int rc = 0;
+
+ /* start hdcp1 app */
+ if (hdcp1_supported && !hdcp1_handle) {
+ rc = qseecom_start_app(&hdcp1_handle, HDCP1_APP_NAME,
+ QSEECOM_SBUFF_SIZE);
+ if (rc) {
+ pr_err("qseecom_start_app failed %d\n", rc);
+ hdcp1_supported = false;
+ } else {
+ mutex_init(&hdcp1_ta_cmd_lock);
+ }
+ }
+
+ pr_debug("hdcp1 app %s loaded\n",
+ hdcp1_supported ? "successfully" : "not");
+
+ return hdcp1_supported;
+}
+
+/* APIs exposed to all clients */
+int hdcp1_set_keys(uint32_t *aksv_msb, uint32_t *aksv_lsb)
+{
+ int rc = 0;
+ struct hdcp1_key_set_req *key_set_req;
+ struct hdcp1_key_set_rsp *key_set_rsp;
+
+ if (aksv_msb == NULL || aksv_lsb == NULL)
+ return -EINVAL;
+
+ if (!hdcp1_supported || !hdcp1_handle)
+ return -EINVAL;
+
+ /* set keys and request aksv */
+ key_set_req = (struct hdcp1_key_set_req *)hdcp1_handle->sbuf;
+ key_set_req->commandid = HDCP1_SET_KEY_MESSAGE_ID;
+ key_set_rsp = (struct hdcp1_key_set_rsp *)(hdcp1_handle->sbuf +
+ QSEECOM_ALIGN(sizeof(struct hdcp1_key_set_req)));
+ rc = qseecom_send_command(hdcp1_handle, key_set_req,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp1_key_set_req)),
+ key_set_rsp,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp1_key_set_rsp)));
+
+ if (rc < 0) {
+ pr_err("qseecom cmd failed err=%d\n", rc);
+ return -ENOKEY;
+ }
+
+ rc = key_set_rsp->ret;
+ if (rc) {
+ pr_err("set key cmd failed, rsp=%d\n", key_set_rsp->ret);
+ return -ENOKEY;
+ }
+
+ /* copy bytes into msb and lsb */
+ *aksv_msb = key_set_rsp->ksv[0] << 24;
+ *aksv_msb |= key_set_rsp->ksv[1] << 16;
+ *aksv_msb |= key_set_rsp->ksv[2] << 8;
+ *aksv_msb |= key_set_rsp->ksv[3];
+ *aksv_lsb = key_set_rsp->ksv[4] << 24;
+ *aksv_lsb |= key_set_rsp->ksv[5] << 16;
+ *aksv_lsb |= key_set_rsp->ksv[6] << 8;
+ *aksv_lsb |= key_set_rsp->ksv[7];
+
+ return 0;
+}
+
+int hdcp1_set_enc(bool enable)
+{
+ int rc = 0;
+ struct hdcp1_set_enc_req *set_enc_req;
+ struct hdcp1_set_enc_rsp *set_enc_rsp;
+
+ mutex_lock(&hdcp1_ta_cmd_lock);
+
+ if (!hdcp1_supported || !hdcp1_handle) {
+ rc = -EINVAL;
+ goto end;
+ }
+
+ if (hdcp1_enc_enabled == enable) {
+ pr_info("already %s\n", enable ? "enabled" : "disabled");
+ goto end;
+ }
+
+ /* set keys and request aksv */
+ set_enc_req = (struct hdcp1_set_enc_req *)hdcp1_handle->sbuf;
+ set_enc_req->commandid = HDCP1_SET_ENC_MESSAGE_ID;
+ set_enc_req->enable = enable;
+ set_enc_rsp = (struct hdcp1_set_enc_rsp *)(hdcp1_handle->sbuf +
+ QSEECOM_ALIGN(sizeof(struct hdcp1_set_enc_req)));
+ rc = qseecom_send_command(hdcp1_handle, set_enc_req,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp1_set_enc_req)),
+ set_enc_rsp,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp1_set_enc_rsp)));
+
+ if (rc < 0) {
+ pr_err("qseecom cmd failed err=%d\n", rc);
+ goto end;
+ }
+
+ rc = set_enc_rsp->ret;
+ if (rc) {
+ pr_err("enc cmd failed, rsp=%d\n", set_enc_rsp->ret);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ hdcp1_enc_enabled = enable;
+ pr_info("%s success\n", enable ? "enable" : "disable");
+end:
+ mutex_unlock(&hdcp1_ta_cmd_lock);
+ return rc;
+}
+
+int hdcp_library_register(struct hdcp_register_data *data)
+{
+ int rc = 0;
+ struct hdcp_lib_handle *handle = NULL;
+
+ if (!data) {
+ pr_err("invalid input\n");
+ return -EINVAL;
+ }
+
+ if (!data->txmtr_ops) {
+ pr_err("invalid input: txmtr context\n");
+ return -EINVAL;
+ }
+
+ if (!data->client_ops) {
+ pr_err("invalid input: client_ops\n");
+ return -EINVAL;
+ }
+
+ if (!data->hdcp_ctx) {
+ pr_err("invalid input: hdcp_ctx\n");
+ return -EINVAL;
+ }
+
+ /* populate ops to be called by client */
+ data->txmtr_ops->feature_supported = hdcp_lib_client_feature_supported;
+ data->txmtr_ops->wakeup = hdcp_lib_wakeup_thread;
+
+ handle = kzalloc(sizeof(*handle), GFP_KERNEL);
+ if (!handle) {
+ rc = -ENOMEM;
+ goto unlock;
+ }
+
+ handle->client_ctx = data->client_ctx;
+ handle->client_ops = data->client_ops;
+ handle->hdcp_app_init = NULL;
+ handle->hdcp_txmtr_init = NULL;
+ handle->device_type = data->device_type;
+
+ atomic_set(&handle->hdcp_off, 0);
+
+ mutex_init(&handle->msg_lock);
+ mutex_init(&handle->wakeup_mutex);
+
+ kthread_init_worker(&handle->worker);
+
+ kthread_init_work(&handle->wk_init, hdcp_lib_init_work);
+ kthread_init_work(&handle->wk_msg_sent, hdcp_lib_msg_sent_work);
+ kthread_init_work(&handle->wk_msg_recvd, hdcp_lib_msg_recvd_work);
+ kthread_init_work(&handle->wk_timeout, hdcp_lib_manage_timeout_work);
+ kthread_init_work(&handle->wk_clean, hdcp_lib_cleanup_work);
+ kthread_init_work(&handle->wk_wait, hdcp_lib_wait_work);
+ kthread_init_work(&handle->wk_stream, hdcp_lib_query_stream_work);
+
+ init_completion(&handle->poll_wait);
+
+ handle->listener_buf = kzalloc(MAX_TX_MESSAGE_SIZE, GFP_KERNEL);
+ if (!(handle->listener_buf)) {
+ rc = -ENOMEM;
+ goto error;
+ }
+
+ *data->hdcp_ctx = handle;
+ /* Cache the client ctx to be used later
+ * HDCP driver probe happens earlier than
+ * SDE driver probe hence caching it to
+ * be used later.
+ */
+
+ drv_client_handle = handle;
+ handle->thread = kthread_run(kthread_worker_fn,
+ &handle->worker, "hdcp_tz_lib");
+
+ if (IS_ERR(handle->thread)) {
+ pr_err("unable to start lib thread\n");
+ rc = PTR_ERR(handle->thread);
+ handle->thread = NULL;
+ goto error;
+ }
+
+ return 0;
+error:
+ kzfree(handle->listener_buf);
+ handle->listener_buf = NULL;
+ kzfree(handle);
+ handle = NULL;
+unlock:
+ return rc;
+}
+EXPORT_SYMBOL(hdcp_library_register);
+
+void hdcp_library_deregister(void *phdcpcontext)
+{
+ struct hdcp_lib_handle *handle = phdcpcontext;
+
+ if (!handle)
+ return;
+
+ kthread_stop(handle->thread);
+
+ kzfree(handle->qseecom_handle);
+ kzfree(handle->last_msg_recvd_buf);
+
+ mutex_destroy(&handle->wakeup_mutex);
+
+ kzfree(handle->listener_buf);
+ kzfree(handle);
+}
+EXPORT_SYMBOL(hdcp_library_deregister);
+
+void hdcp1_notify_topology(void)
+{
+ char *envp[4];
+ char *a;
+ char *b;
+
+ if (!hdcp_drv_mgr) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ a = kzalloc(SZ_16, GFP_KERNEL);
+
+ if (!a)
+ return;
+
+ b = kzalloc(SZ_16, GFP_KERNEL);
+
+ if (!b) {
+ kfree(a);
+ return;
+ }
+
+ envp[0] = "HDCP_MGR_EVENT=MSG_READY";
+ envp[1] = a;
+ envp[2] = b;
+ envp[3] = NULL;
+
+ snprintf(envp[1], 16, "%d", (int)DOWN_CHECK_TOPOLOGY);
+ snprintf(envp[2], 16, "%d", (int)HDCP_V1_TX);
+
+ kobject_uevent_env(&hdcp_drv_mgr->device->kobj, KOBJ_CHANGE, envp);
+ kfree(a);
+ kfree(b);
+}
+
+static ssize_t msm_hdcp_1x_sysfs_rda_tp(struct device *dev,
+struct device_attribute *attr, char *buf)
+{
+ ssize_t ret = 0;
+
+ if (!hdcp_drv_mgr) {
+ pr_err("invalid input\n");
+ return -EINVAL;
+ }
+
+ switch (hdcp_drv_mgr->tp_msgid) {
+ case DOWN_CHECK_TOPOLOGY:
+ case DOWN_REQUEST_TOPOLOGY:
+ buf[MSG_ID_IDX] = hdcp_drv_mgr->tp_msgid;
+ buf[RET_CODE_IDX] = HDCP_AUTHED;
+ ret = HEADER_LEN;
+
+ memcpy(buf + HEADER_LEN, &hdcp_drv_mgr->cached_tp,
+ sizeof(struct HDCP_V2V1_MSG_TOPOLOGY));
+
+ ret += sizeof(struct HDCP_V2V1_MSG_TOPOLOGY);
+
+ /* clear the flag once data is read back to user space*/
+ hdcp_drv_mgr->tp_msgid = -1;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static ssize_t msm_hdcp_1x_sysfs_wta_tp(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int msgid = 0;
+ ssize_t ret = count;
+
+ if (!hdcp_drv_mgr || !buf) {
+ pr_err("invalid input\n");
+ return -EINVAL;
+ }
+
+ msgid = buf[0];
+
+ switch (msgid) {
+ case DOWN_CHECK_TOPOLOGY:
+ case DOWN_REQUEST_TOPOLOGY:
+ hdcp_drv_mgr->tp_msgid = msgid;
+ break;
+ /* more cases added here */
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static ssize_t hdcp2p2_sysfs_wta_min_level_change(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int rc;
+ int min_enc_lvl;
+ struct hdcp_lib_handle *handle;
+ ssize_t ret = count;
+
+ if (!hdcp_drv_mgr) {
+ pr_err("invalid input\n");
+ return -EINVAL;
+ }
+
+ handle = hdcp_drv_mgr->handle;
+
+ rc = kstrtoint(buf, 10, &min_enc_lvl);
+ if (rc) {
+ pr_err("%s: kstrtoint failed. rc=%d\n", __func__, rc);
+ return -EINVAL;
+ }
+
+ if (handle && handle->client_ops->notify_lvl_change) {
+ handle->client_ops->notify_lvl_change(handle->client_ctx,
+ min_enc_lvl);
+ }
+
+ return ret;
+}
+
+static DEVICE_ATTR(tp, 0644, msm_hdcp_1x_sysfs_rda_tp,
+ msm_hdcp_1x_sysfs_wta_tp);
+
+static DEVICE_ATTR(min_level_change, 0200, NULL,
+ hdcp2p2_sysfs_wta_min_level_change);
+
+void hdcp1_cache_repeater_topology(void *hdcp1_cached_tp)
+{
+ if (!hdcp_drv_mgr) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ memcpy((void *)&hdcp_drv_mgr->cached_tp,
+ hdcp1_cached_tp,
+ sizeof(struct HDCP_V2V1_MSG_TOPOLOGY));
+}
+
+static struct attribute *msm_hdcp_fs_attrs[] = {
+ &dev_attr_tp.attr,
+ &dev_attr_min_level_change.attr,
+ NULL
+};
+
+static struct attribute_group msm_hdcp_fs_attr_group = {
+ .attrs = msm_hdcp_fs_attrs
+};
+
+static int msm_hdcp_open(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static int msm_hdcp_close(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static const struct file_operations msm_hdcp_fops = {
+ .owner = THIS_MODULE,
+ .open = msm_hdcp_open,
+ .release = msm_hdcp_close,
+};
+
+static const struct of_device_id msm_hdcp_dt_match[] = {
+ { .compatible = "qcom,msm-hdcp",},
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, msm_hdcp_dt_match);
+
+static int msm_hdcp_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ hdcp_drv_mgr = devm_kzalloc(&pdev->dev, sizeof(struct msm_hdcp_mgr),
+ GFP_KERNEL);
+ if (!hdcp_drv_mgr)
+ return -ENOMEM;
+
+ hdcp_drv_mgr->pdev = pdev;
+
+ platform_set_drvdata(pdev, hdcp_drv_mgr);
+
+ ret = alloc_chrdev_region(&hdcp_drv_mgr->dev_num, 0, 1, DRIVER_NAME);
+ if (ret < 0) {
+ pr_err("alloc_chrdev_region failed ret = %d\n", ret);
+ goto error_get_dev_num;
+ }
+
+ hdcp_drv_mgr->class = class_create(THIS_MODULE, CLASS_NAME);
+ if (IS_ERR(hdcp_drv_mgr->class)) {
+ ret = PTR_ERR(hdcp_drv_mgr->class);
+ pr_err("couldn't create class rc = %d\n", ret);
+ goto error_class_create;
+ }
+
+ hdcp_drv_mgr->device = device_create(hdcp_drv_mgr->class, NULL,
+ hdcp_drv_mgr->dev_num, NULL, DRIVER_NAME);
+ if (IS_ERR(hdcp_drv_mgr->device)) {
+ ret = PTR_ERR(hdcp_drv_mgr->device);
+ pr_err("device_create failed %d\n", ret);
+ goto error_class_device_create;
+ }
+
+ cdev_init(&hdcp_drv_mgr->cdev, &msm_hdcp_fops);
+ ret = cdev_add(&hdcp_drv_mgr->cdev,
+ MKDEV(MAJOR(hdcp_drv_mgr->dev_num), 0), 1);
+ if (ret < 0) {
+ pr_err("cdev_add failed %d\n", ret);
+ goto error_cdev_add;
+ }
+
+ ret = sysfs_create_group(&hdcp_drv_mgr->device->kobj,
+ &msm_hdcp_fs_attr_group);
+ if (ret)
+ pr_err("unable to register rotator sysfs nodes\n");
+
+ /* Store the handle in the hdcp drv mgr
+ * to be used for the sysfs notifications
+ */
+ hdcp_drv_mgr->handle = drv_client_handle;
+
+ return 0;
+error_cdev_add:
+ device_destroy(hdcp_drv_mgr->class, hdcp_drv_mgr->dev_num);
+error_class_device_create:
+ class_destroy(hdcp_drv_mgr->class);
+error_class_create:
+ unregister_chrdev_region(hdcp_drv_mgr->dev_num, 1);
+error_get_dev_num:
+ devm_kfree(&pdev->dev, hdcp_drv_mgr);
+ hdcp_drv_mgr = NULL;
+ return ret;
+}
+
+static int msm_hdcp_remove(struct platform_device *pdev)
+{
+ struct msm_hdcp_mgr *mgr;
+
+ mgr = (struct msm_hdcp_mgr *)platform_get_drvdata(pdev);
+ if (!mgr)
+ return -ENODEV;
+
+ sysfs_remove_group(&hdcp_drv_mgr->device->kobj,
+ &msm_hdcp_fs_attr_group);
+ cdev_del(&hdcp_drv_mgr->cdev);
+ device_destroy(hdcp_drv_mgr->class, hdcp_drv_mgr->dev_num);
+ class_destroy(hdcp_drv_mgr->class);
+ unregister_chrdev_region(hdcp_drv_mgr->dev_num, 1);
+
+ devm_kfree(&pdev->dev, hdcp_drv_mgr);
+ hdcp_drv_mgr = NULL;
+ return 0;
+}
+
+static struct platform_driver msm_hdcp_driver = {
+ .probe = msm_hdcp_probe,
+ .remove = msm_hdcp_remove,
+ .driver = {
+ .name = "msm_hdcp",
+ .of_match_table = msm_hdcp_dt_match,
+ .pm = NULL,
+ }
+};
+
+static int __init msm_hdcp_init(void)
+{
+ return platform_driver_register(&msm_hdcp_driver);
+}
+
+static void __exit msm_hdcp_exit(void)
+{
+ return platform_driver_unregister(&msm_hdcp_driver);
+}
+
+module_init(msm_hdcp_init);
+module_exit(msm_hdcp_exit);
+
+MODULE_DESCRIPTION("MSM HDCP driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/lkdtm.h b/drivers/misc/lkdtm.h
index fdf954c..cfa1039 100644
--- a/drivers/misc/lkdtm.h
+++ b/drivers/misc/lkdtm.h
@@ -21,6 +21,8 @@
void lkdtm_HUNG_TASK(void);
void lkdtm_ATOMIC_UNDERFLOW(void);
void lkdtm_ATOMIC_OVERFLOW(void);
+void lkdtm_CORRUPT_LIST_ADD(void);
+void lkdtm_CORRUPT_LIST_DEL(void);
/* lkdtm_heap.c */
void lkdtm_OVERWRITE_ALLOCATION(void);
diff --git a/drivers/misc/lkdtm_bugs.c b/drivers/misc/lkdtm_bugs.c
index 182ae18..bb3bb8e 100644
--- a/drivers/misc/lkdtm_bugs.c
+++ b/drivers/misc/lkdtm_bugs.c
@@ -5,8 +5,13 @@
* test source files.
*/
#include "lkdtm.h"
+#include <linux/list.h>
#include <linux/sched.h>
+struct lkdtm_list {
+ struct list_head node;
+};
+
/*
* Make sure our attempts to over run the kernel stack doesn't trigger
* a compiler warning when CONFIG_FRAME_WARN is set. Then make sure we
@@ -75,12 +80,18 @@
(void) recursive_loop(recur_count);
}
+static noinline void __lkdtm_CORRUPT_STACK(void *stack)
+{
+ memset(stack, 'a', 64);
+}
+
noinline void lkdtm_CORRUPT_STACK(void)
{
/* Use default char array length that triggers stack protection. */
char data[8];
+ __lkdtm_CORRUPT_STACK(&data);
- memset((void *)data, 0, 64);
+ pr_info("Corrupted stack with '%16s'...\n", data);
}
void lkdtm_UNALIGNED_LOAD_STORE_WRITE(void)
@@ -146,3 +157,66 @@
pr_info("attempting bad atomic overflow\n");
atomic_inc(&over);
}
+
+void lkdtm_CORRUPT_LIST_ADD(void)
+{
+ /*
+ * Initially, an empty list via LIST_HEAD:
+ * test_head.next = &test_head
+ * test_head.prev = &test_head
+ */
+ LIST_HEAD(test_head);
+ struct lkdtm_list good, bad;
+ void *target[2] = { };
+ void *redirection = ⌖
+
+ pr_info("attempting good list addition\n");
+
+ /*
+ * Adding to the list performs these actions:
+ * test_head.next->prev = &good.node
+ * good.node.next = test_head.next
+ * good.node.prev = test_head
+ * test_head.next = good.node
+ */
+ list_add(&good.node, &test_head);
+
+ pr_info("attempting corrupted list addition\n");
+ /*
+ * In simulating this "write what where" primitive, the "what" is
+ * the address of &bad.node, and the "where" is the address held
+ * by "redirection".
+ */
+ test_head.next = redirection;
+ list_add(&bad.node, &test_head);
+
+ if (target[0] == NULL && target[1] == NULL)
+ pr_err("Overwrite did not happen, but no BUG?!\n");
+ else
+ pr_err("list_add() corruption not detected!\n");
+}
+
+void lkdtm_CORRUPT_LIST_DEL(void)
+{
+ LIST_HEAD(test_head);
+ struct lkdtm_list item;
+ void *target[2] = { };
+ void *redirection = ⌖
+
+ list_add(&item.node, &test_head);
+
+ pr_info("attempting good list removal\n");
+ list_del(&item.node);
+
+ pr_info("attempting corrupted list removal\n");
+ list_add(&item.node, &test_head);
+
+ /* As with the list_add() test above, this corrupts "next". */
+ item.node.next = redirection;
+ list_del(&item.node);
+
+ if (target[0] == NULL && target[1] == NULL)
+ pr_err("Overwrite did not happen, but no BUG?!\n");
+ else
+ pr_err("list_del() corruption not detected!\n");
+}
diff --git a/drivers/misc/lkdtm_core.c b/drivers/misc/lkdtm_core.c
index f9154b8..7eeb71a 100644
--- a/drivers/misc/lkdtm_core.c
+++ b/drivers/misc/lkdtm_core.c
@@ -197,6 +197,8 @@
CRASHTYPE(EXCEPTION),
CRASHTYPE(LOOP),
CRASHTYPE(OVERFLOW),
+ CRASHTYPE(CORRUPT_LIST_ADD),
+ CRASHTYPE(CORRUPT_LIST_DEL),
CRASHTYPE(CORRUPT_STACK),
CRASHTYPE(UNALIGNED_LOAD_STORE_WRITE),
CRASHTYPE(OVERWRITE_ALLOCATION),
diff --git a/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c b/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c
index 80f6e57..501d4a4 100644
--- a/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c
+++ b/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c
@@ -26,11 +26,14 @@
#include <linux/debugfs.h>
#include <linux/msm_audio_ion.h>
#include <linux/compat.h>
+#include <linux/mutex.h>
#include "audio_utils_aio.h"
#ifdef CONFIG_USE_DEV_CTRL_VOLUME
#include <linux/qdsp6v2/audio_dev_ctl.h>
#endif /*CONFIG_USE_DEV_CTRL_VOLUME*/
+static DEFINE_MUTEX(lock);
#ifdef CONFIG_DEBUG_FS
+
int audio_aio_debug_open(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
@@ -43,29 +46,37 @@
const int debug_bufmax = 4096;
static char buffer[4096];
int n = 0;
- struct q6audio_aio *audio = file->private_data;
+ struct q6audio_aio *audio;
- mutex_lock(&audio->lock);
- n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
- n += scnprintf(buffer + n, debug_bufmax - n,
- "enabled %d\n", audio->enabled);
- n += scnprintf(buffer + n, debug_bufmax - n,
- "stopped %d\n", audio->stopped);
- n += scnprintf(buffer + n, debug_bufmax - n,
- "feedback %d\n", audio->feedback);
- mutex_unlock(&audio->lock);
- /* Following variables are only useful for debugging when
- * when playback halts unexpectedly. Thus, no mutual exclusion
- * enforced
- */
- n += scnprintf(buffer + n, debug_bufmax - n,
- "wflush %d\n", audio->wflush);
- n += scnprintf(buffer + n, debug_bufmax - n,
- "rflush %d\n", audio->rflush);
- n += scnprintf(buffer + n, debug_bufmax - n,
- "inqueue empty %d\n", list_empty(&audio->in_queue));
- n += scnprintf(buffer + n, debug_bufmax - n,
- "outqueue empty %d\n", list_empty(&audio->out_queue));
+ mutex_lock(&lock);
+ if (file->private_data != NULL) {
+ audio = file->private_data;
+ mutex_lock(&audio->lock);
+ n = scnprintf(buffer, debug_bufmax, "opened %d\n",
+ audio->opened);
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "enabled %d\n", audio->enabled);
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "stopped %d\n", audio->stopped);
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "feedback %d\n", audio->feedback);
+ mutex_unlock(&audio->lock);
+ /* Following variables are only useful for debugging when
+ * when playback halts unexpectedly. Thus, no mutual exclusion
+ * enforced
+ */
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "wflush %d\n", audio->wflush);
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "rflush %d\n", audio->rflush);
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "inqueue empty %d\n",
+ list_empty(&audio->in_queue));
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "outqueue empty %d\n",
+ list_empty(&audio->out_queue));
+ }
+ mutex_unlock(&lock);
buffer[n] = 0;
return simple_read_from_buffer(buf, count, ppos, buffer, n);
}
@@ -580,6 +591,7 @@
struct q6audio_aio *audio = file->private_data;
pr_debug("%s[%pK]\n", __func__, audio);
+ mutex_lock(&lock);
mutex_lock(&audio->lock);
mutex_lock(&audio->read_lock);
mutex_lock(&audio->write_lock);
@@ -622,6 +634,8 @@
#endif
kfree(audio->codec_cfg);
kfree(audio);
+ file->private_data = NULL;
+ mutex_unlock(&lock);
return 0;
}
@@ -1054,6 +1068,8 @@
struct audio_client *ac;
struct audio_aio_write_param param;
+ memset(¶m, 0, sizeof(param));
+
if (!audio || !buf_node) {
pr_err("%s NULL pointer audio=[0x%pK], buf_node=[0x%pK]\n",
__func__, audio, buf_node);
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index c6f3496..120fd54 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -4589,6 +4589,10 @@
dev_set_drvdata(&card->dev, md);
+#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
+ mmc_set_bus_resume_policy(card->host, 1);
+#endif
+
if (mmc_add_disk(md))
goto out;
@@ -4632,6 +4636,9 @@
pm_runtime_put_noidle(&card->dev);
mmc_blk_remove_req(md);
dev_set_drvdata(&card->dev, NULL);
+#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
+ mmc_set_bus_resume_policy(card->host, 0);
+#endif
}
static int _mmc_blk_suspend(struct mmc_card *card, bool wait)
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 0bf89b4..978dd9a 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -4472,7 +4472,7 @@
BUG_ON(host->card);
- mmc_register_extcon(host);
+ mmc_unregister_extcon(host);
mmc_claim_host(host);
mmc_power_off(host);
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 3184dcd..409718b 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -2944,6 +2944,7 @@
return -EBUSY;
}
+ MMC_TRACE(host, "%s\n", __func__);
err = _mmc_suspend(host, true);
if (err)
pr_err("%s: error %d doing aggressive suspend\n",
@@ -2962,6 +2963,7 @@
int err;
ktime_t start = ktime_get();
+ MMC_TRACE(host, "%s\n", __func__);
err = _mmc_resume(host);
if (err && err != -ENOMEDIUM)
pr_err("%s: error %d doing runtime resume\n",
diff --git a/drivers/mmc/host/sdhci-msm-ice.c b/drivers/mmc/host/sdhci-msm-ice.c
index acc4ae0..d624b48 100644
--- a/drivers/mmc/host/sdhci-msm-ice.c
+++ b/drivers/mmc/host/sdhci-msm-ice.c
@@ -212,6 +212,38 @@
}
static
+int sdhci_msm_ice_get_cfg(struct sdhci_msm_host *msm_host, struct request *req,
+ unsigned int *bypass, short *key_index)
+{
+ int err = 0;
+ struct ice_data_setting ice_set;
+
+ memset(&ice_set, 0, sizeof(struct ice_data_setting));
+ if (msm_host->ice.vops->config_start) {
+ err = msm_host->ice.vops->config_start(
+ msm_host->ice.pdev,
+ req, &ice_set, false);
+ if (err) {
+ pr_err("%s: ice config failed %d\n",
+ mmc_hostname(msm_host->mmc), err);
+ return err;
+ }
+ }
+ /* if writing data command */
+ if (rq_data_dir(req) == WRITE)
+ *bypass = ice_set.encr_bypass ?
+ SDHCI_MSM_ICE_ENABLE_BYPASS :
+ SDHCI_MSM_ICE_DISABLE_BYPASS;
+ /* if reading data command */
+ else if (rq_data_dir(req) == READ)
+ *bypass = ice_set.decr_bypass ?
+ SDHCI_MSM_ICE_ENABLE_BYPASS :
+ SDHCI_MSM_ICE_DISABLE_BYPASS;
+ *key_index = ice_set.crypto_data.key_index;
+ return err;
+}
+
+static
void sdhci_msm_ice_update_cfg(struct sdhci_host *host, u64 lba,
u32 slot, unsigned int bypass, short key_index)
{
@@ -250,7 +282,7 @@
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = pltfm_host->priv;
int err = 0;
- struct ice_data_setting ice_set;
+ short key_index = 0;
sector_t lba = 0;
unsigned int bypass = SDHCI_MSM_ICE_ENABLE_BYPASS;
struct request *req;
@@ -261,41 +293,22 @@
return -EINVAL;
}
- BUG_ON(!mrq);
- memset(&ice_set, 0, sizeof(struct ice_data_setting));
+ WARN_ON(!mrq);
+ if (!mrq)
+ return -EINVAL;
req = mrq->req;
if (req) {
lba = req->__sector;
- if (msm_host->ice.vops->config_start) {
- err = msm_host->ice.vops->config_start(
- msm_host->ice.pdev,
- req, &ice_set, false);
- if (err) {
- pr_err("%s: ice config failed %d\n",
- mmc_hostname(host->mmc), err);
- return err;
- }
- }
- /* if writing data command */
- if (rq_data_dir(req) == WRITE)
- bypass = ice_set.encr_bypass ?
- SDHCI_MSM_ICE_ENABLE_BYPASS :
- SDHCI_MSM_ICE_DISABLE_BYPASS;
- /* if reading data command */
- else if (rq_data_dir(req) == READ)
- bypass = ice_set.decr_bypass ?
- SDHCI_MSM_ICE_ENABLE_BYPASS :
- SDHCI_MSM_ICE_DISABLE_BYPASS;
- pr_debug("%s: %s: slot %d encr_bypass %d bypass %d decr_bypass %d key_index %d\n",
+ err = sdhci_msm_ice_get_cfg(msm_host, req, &bypass, &key_index);
+ if (err)
+ return err;
+ pr_debug("%s: %s: slot %d bypass %d key_index %d\n",
mmc_hostname(host->mmc),
(rq_data_dir(req) == WRITE) ? "WRITE" : "READ",
- slot, ice_set.encr_bypass, bypass,
- ice_set.decr_bypass,
- ice_set.crypto_data.key_index);
+ slot, bypass, key_index);
}
- sdhci_msm_ice_update_cfg(host, lba, slot, bypass,
- ice_set.crypto_data.key_index);
+ sdhci_msm_ice_update_cfg(host, lba, slot, bypass, key_index);
return 0;
}
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index b6c17ec0..1e25b31 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -691,7 +691,7 @@
mclk_freq = 5;
else if (host->clock <= 187000000)
mclk_freq = 6;
- else if (host->clock <= 200000000)
+ else if (host->clock <= 208000000)
mclk_freq = 7;
writel_relaxed(((readl_relaxed(host->ioaddr +
@@ -2492,15 +2492,31 @@
struct sdhci_msm_host *msm_host = pltfm_host->priv;
const struct sdhci_msm_offset *msm_host_offset =
msm_host->offset;
+ unsigned int irq_flags = 0;
+ struct irq_desc *pwr_irq_desc = irq_to_desc(msm_host->pwr_irq);
- pr_err("%s: PWRCTL_STATUS: 0x%08x | PWRCTL_MASK: 0x%08x | PWRCTL_CTL: 0x%08x\n",
+ if (pwr_irq_desc)
+ irq_flags = ACCESS_PRIVATE(pwr_irq_desc->irq_data.common,
+ state_use_accessors);
+
+ pr_err("%s: PWRCTL_STATUS: 0x%08x | PWRCTL_MASK: 0x%08x | PWRCTL_CTL: 0x%08x, pwr isr state=0x%x\n",
mmc_hostname(host->mmc),
sdhci_msm_readl_relaxed(host,
msm_host_offset->CORE_PWRCTL_STATUS),
sdhci_msm_readl_relaxed(host,
msm_host_offset->CORE_PWRCTL_MASK),
sdhci_msm_readl_relaxed(host,
- msm_host_offset->CORE_PWRCTL_CTL));
+ msm_host_offset->CORE_PWRCTL_CTL), irq_flags);
+
+ MMC_TRACE(host->mmc,
+ "%s: Sts: 0x%08x | Mask: 0x%08x | Ctrl: 0x%08x, pwr isr state=0x%x\n",
+ __func__,
+ sdhci_msm_readb_relaxed(host,
+ msm_host_offset->CORE_PWRCTL_STATUS),
+ sdhci_msm_readb_relaxed(host,
+ msm_host_offset->CORE_PWRCTL_MASK),
+ sdhci_msm_readb_relaxed(host,
+ msm_host_offset->CORE_PWRCTL_CTL), irq_flags);
}
static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data)
@@ -2772,10 +2788,14 @@
if (done)
init_completion(&msm_host->pwr_irq_completion);
else if (!wait_for_completion_timeout(&msm_host->pwr_irq_completion,
- msecs_to_jiffies(MSM_PWR_IRQ_TIMEOUT_MS)))
+ msecs_to_jiffies(MSM_PWR_IRQ_TIMEOUT_MS))) {
__WARN_printf("%s: request(%d) timed out waiting for pwr_irq\n",
mmc_hostname(host->mmc), req_type);
-
+ MMC_TRACE(host->mmc,
+ "%s: request(%d) timed out waiting for pwr_irq\n",
+ __func__, req_type);
+ sdhci_msm_dump_pwr_ctrl_regs(host);
+ }
pr_debug("%s: %s: request %d done\n", mmc_hostname(host->mmc),
__func__, req_type);
}
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 3eada3b..68e49bb 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -245,6 +245,8 @@
if (timeout == 0) {
pr_err("%s: Reset 0x%x never completed.\n",
mmc_hostname(host->mmc), (int)mask);
+ MMC_TRACE(host->mmc, "%s: Reset 0x%x never completed\n",
+ __func__, (int)mask);
if ((host->quirks2 & SDHCI_QUIRK2_USE_RESET_WORKAROUND)
&& host->ops->reset_workaround) {
if (!host->reset_wa_applied) {
@@ -1244,6 +1246,9 @@
if (timeout == 0) {
pr_err("%s: Controller never released inhibit bit(s).\n",
mmc_hostname(host->mmc));
+ MMC_TRACE(host->mmc,
+ "%s :Controller never released inhibit bit(s)\n",
+ __func__);
sdhci_dumpregs(host);
cmd->error = -EIO;
sdhci_finish_mrq(host, cmd->mrq);
@@ -1302,12 +1307,12 @@
if (cmd->data)
host->data_start_time = ktime_get();
trace_mmc_cmd_rw_start(cmd->opcode, cmd->arg, cmd->flags);
+ sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND);
MMC_TRACE(host->mmc,
"%s: updated 0x8=0x%08x 0xC=0x%08x 0xE=0x%08x\n", __func__,
sdhci_readl(host, SDHCI_ARGUMENT),
sdhci_readw(host, SDHCI_TRANSFER_MODE),
sdhci_readw(host, SDHCI_COMMAND));
- sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND);
}
EXPORT_SYMBOL_GPL(sdhci_send_command);
@@ -1533,6 +1538,8 @@
if (timeout == 0) {
pr_err("%s: Internal clock never stabilised.\n",
mmc_hostname(host->mmc));
+ MMC_TRACE(host->mmc,
+ "%s: Internal clock never stabilised.\n", __func__);
sdhci_dumpregs(host);
return;
}
@@ -2917,6 +2924,7 @@
(host->cmd && sdhci_data_line_cmd(host->cmd))) {
pr_err("%s: Timeout waiting for hardware interrupt.\n",
mmc_hostname(host->mmc));
+ MMC_TRACE(host->mmc, "Timeout waiting for h/w interrupt\n");
sdhci_dumpregs(host);
if (host->data) {
@@ -2959,6 +2967,9 @@
return;
pr_err("%s: Got command interrupt 0x%08x even though no command operation was in progress.\n",
mmc_hostname(host->mmc), (unsigned)intmask);
+ MMC_TRACE(host->mmc,
+ "Got command interrupt 0x%08x even though no command operation was in progress.\n",
+ (unsigned int)intmask);
sdhci_dumpregs(host);
return;
}
@@ -3111,6 +3122,9 @@
pr_err("%s: Got data interrupt 0x%08x even though no data operation was in progress.\n",
mmc_hostname(host->mmc), (unsigned)intmask);
+ MMC_TRACE(host->mmc,
+ "Got data interrupt 0x%08x even though no data operation was in progress.\n",
+ (unsigned int)intmask);
sdhci_dumpregs(host);
return;
@@ -3146,6 +3160,11 @@
mmc_hostname(host->mmc), intmask,
host->data->error, ktime_to_ms(ktime_sub(
ktime_get(), host->data_start_time)));
+ MMC_TRACE(host->mmc,
+ "data txfr (0x%08x) error: %d after %lld ms\n",
+ intmask, host->data->error,
+ ktime_to_ms(ktime_sub(ktime_get(),
+ host->data_start_time)));
if (!host->mmc->sdr104_wa ||
(host->mmc->ios.timing != MMC_TIMING_UHS_SDR104))
@@ -3399,6 +3418,8 @@
if (unexpected) {
pr_err("%s: Unexpected interrupt 0x%08x.\n",
mmc_hostname(host->mmc), unexpected);
+ MMC_TRACE(host->mmc, "Unexpected interrupt 0x%08x.\n",
+ unexpected);
sdhci_dumpregs(host);
}
diff --git a/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c b/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c
index 380a641..258bc8d 100644
--- a/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c
+++ b/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c
@@ -230,7 +230,7 @@
/* Wait for 100ms as Octeon resets. */
mdelay(100);
- if (octeon_read_csr64(oct, CN23XX_SLI_SCRATCH1) == 0x1234ULL) {
+ if (octeon_read_csr64(oct, CN23XX_SLI_SCRATCH1)) {
dev_err(&oct->pci_dev->dev, "OCTEON[%d]: Soft reset failed\n",
oct->octeon_id);
return 1;
diff --git a/drivers/net/ethernet/cavium/liquidio/cn66xx_device.c b/drivers/net/ethernet/cavium/liquidio/cn66xx_device.c
index e779af8..cda32d5 100644
--- a/drivers/net/ethernet/cavium/liquidio/cn66xx_device.c
+++ b/drivers/net/ethernet/cavium/liquidio/cn66xx_device.c
@@ -48,7 +48,7 @@
/* Wait for 10ms as Octeon resets. */
mdelay(100);
- if (octeon_read_csr64(oct, CN6XXX_SLI_SCRATCH1) == 0x1234ULL) {
+ if (octeon_read_csr64(oct, CN6XXX_SLI_SCRATCH1)) {
dev_err(&oct->pci_dev->dev, "Soft reset failed\n");
return 1;
}
diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c
index a61447f..1264a36 100644
--- a/drivers/net/ethernet/intel/igb/e1000_82575.c
+++ b/drivers/net/ethernet/intel/igb/e1000_82575.c
@@ -246,6 +246,7 @@
E1000_STATUS_FUNC_SHIFT;
/* Set phy->phy_addr and phy->id. */
+ igb_write_phy_reg_82580(hw, I347AT4_PAGE_SELECT, 0);
ret_val = igb_get_phy_id_82575(hw);
if (ret_val)
return ret_val;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index ea58234..9d37229 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -2671,8 +2671,6 @@
PPORT_802_3_GET(pstats, a_frame_check_sequence_errors);
stats->rx_frame_errors = PPORT_802_3_GET(pstats, a_alignment_errors);
stats->tx_aborted_errors = PPORT_2863_GET(pstats, if_out_discards);
- stats->tx_carrier_errors =
- PPORT_802_3_GET(pstats, a_symbol_error_during_carrier);
stats->rx_errors = stats->rx_length_errors + stats->rx_crc_errors +
stats->rx_frame_errors;
stats->tx_errors = stats->tx_aborted_errors + stats->tx_carrier_errors;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/health.c b/drivers/net/ethernet/mellanox/mlx5/core/health.c
index 2115c8a..8beecd6 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/health.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/health.c
@@ -67,6 +67,7 @@
enum {
MLX5_DROP_NEW_HEALTH_WORK,
+ MLX5_DROP_NEW_RECOVERY_WORK,
};
static u8 get_nic_state(struct mlx5_core_dev *dev)
@@ -193,7 +194,7 @@
mlx5_handle_bad_state(dev);
spin_lock(&health->wq_lock);
- if (!test_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags))
+ if (!test_bit(MLX5_DROP_NEW_RECOVERY_WORK, &health->flags))
schedule_delayed_work(&health->recover_work, recover_delay);
else
dev_err(&dev->pdev->dev,
@@ -328,6 +329,7 @@
init_timer(&health->timer);
health->sick = 0;
clear_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags);
+ clear_bit(MLX5_DROP_NEW_RECOVERY_WORK, &health->flags);
health->health = &dev->iseg->health;
health->health_counter = &dev->iseg->health_counter;
@@ -350,11 +352,22 @@
spin_lock(&health->wq_lock);
set_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags);
+ set_bit(MLX5_DROP_NEW_RECOVERY_WORK, &health->flags);
spin_unlock(&health->wq_lock);
cancel_delayed_work_sync(&health->recover_work);
cancel_work_sync(&health->work);
}
+void mlx5_drain_health_recovery(struct mlx5_core_dev *dev)
+{
+ struct mlx5_core_health *health = &dev->priv.health;
+
+ spin_lock(&health->wq_lock);
+ set_bit(MLX5_DROP_NEW_RECOVERY_WORK, &health->flags);
+ spin_unlock(&health->wq_lock);
+ cancel_delayed_work_sync(&dev->priv.health.recover_work);
+}
+
void mlx5_health_cleanup(struct mlx5_core_dev *dev)
{
struct mlx5_core_health *health = &dev->priv.health;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c
index 5bea0bf..b3309f2 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c
@@ -1169,7 +1169,7 @@
int err = 0;
if (cleanup)
- mlx5_drain_health_wq(dev);
+ mlx5_drain_health_recovery(dev);
mutex_lock(&dev->intf_state_mutex);
if (test_bit(MLX5_INTERFACE_STATE_DOWN, &dev->intf_state)) {
diff --git a/drivers/net/ethernet/rocker/rocker_ofdpa.c b/drivers/net/ethernet/rocker/rocker_ofdpa.c
index 4ca4613..b1af7cd 100644
--- a/drivers/net/ethernet/rocker/rocker_ofdpa.c
+++ b/drivers/net/ethernet/rocker/rocker_ofdpa.c
@@ -1505,8 +1505,8 @@
*index = entry->index;
resolved = false;
} else if (removing) {
- ofdpa_neigh_del(trans, found);
*index = found->index;
+ ofdpa_neigh_del(trans, found);
} else if (updating) {
ofdpa_neigh_update(found, trans, NULL, false);
resolved = !is_zero_ether_addr(found->eth_dst);
diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c
index 00279da..c4ada72 100644
--- a/drivers/net/ethernet/sfc/ef10.c
+++ b/drivers/net/ethernet/sfc/ef10.c
@@ -4399,12 +4399,9 @@
struct efx_ef10_filter_table *table = efx->filter_state;
struct net_device *net_dev = efx->net_dev;
struct netdev_hw_addr *uc;
- int addr_count;
unsigned int i;
- addr_count = netdev_uc_count(net_dev);
table->uc_promisc = !!(net_dev->flags & IFF_PROMISC);
- table->dev_uc_count = 1 + addr_count;
ether_addr_copy(table->dev_uc_list[0].addr, net_dev->dev_addr);
i = 1;
netdev_for_each_uc_addr(uc, net_dev) {
@@ -4415,6 +4412,8 @@
ether_addr_copy(table->dev_uc_list[i].addr, uc->addr);
i++;
}
+
+ table->dev_uc_count = i;
}
static void efx_ef10_filter_mc_addr_list(struct efx_nic *efx)
@@ -4422,11 +4421,10 @@
struct efx_ef10_filter_table *table = efx->filter_state;
struct net_device *net_dev = efx->net_dev;
struct netdev_hw_addr *mc;
- unsigned int i, addr_count;
+ unsigned int i;
table->mc_promisc = !!(net_dev->flags & (IFF_PROMISC | IFF_ALLMULTI));
- addr_count = netdev_mc_count(net_dev);
i = 0;
netdev_for_each_mc_addr(mc, net_dev) {
if (i >= EFX_EF10_FILTER_DEV_MC_MAX) {
diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c
index 4865221..b88f7d6 100644
--- a/drivers/net/phy/dp83640.c
+++ b/drivers/net/phy/dp83640.c
@@ -908,7 +908,7 @@
if (overflow) {
pr_debug("tx timestamp queue overflow, count %d\n", overflow);
while (skb) {
- skb_complete_tx_timestamp(skb, NULL);
+ kfree_skb(skb);
skb = skb_dequeue(&dp83640->tx_queue);
}
return;
diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
index fab56c9..2229188 100644
--- a/drivers/net/phy/micrel.c
+++ b/drivers/net/phy/micrel.c
@@ -622,6 +622,8 @@
if ((regval & 0xFF) == 0xFF) {
phy_init_hw(phydev);
phydev->link = 0;
+ if (phydev->drv->config_intr && phy_interrupt_is_valid(phydev))
+ phydev->drv->config_intr(phydev);
}
return 0;
diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c
index 642df93..578bd50 100644
--- a/drivers/net/vrf.c
+++ b/drivers/net/vrf.c
@@ -787,15 +787,10 @@
static void vrf_dev_uninit(struct net_device *dev)
{
struct net_vrf *vrf = netdev_priv(dev);
- struct net_device *port_dev;
- struct list_head *iter;
vrf_rtable_release(dev, vrf);
vrf_rt6_release(dev, vrf);
- netdev_for_each_lower_dev(dev, port_dev, iter)
- vrf_del_slave(dev, port_dev);
-
free_percpu(dev->dstats);
dev->dstats = NULL;
}
@@ -1232,6 +1227,12 @@
static void vrf_dellink(struct net_device *dev, struct list_head *head)
{
+ struct net_device *port_dev;
+ struct list_head *iter;
+
+ netdev_for_each_lower_dev(dev, port_dev, iter)
+ vrf_del_slave(dev, port_dev);
+
unregister_netdevice_queue(dev, head);
}
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index 963e533..983e941 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -227,15 +227,15 @@
static struct vxlan_dev *vxlan_vs_find_vni(struct vxlan_sock *vs, __be32 vni)
{
- struct vxlan_dev *vxlan;
+ struct vxlan_dev_node *node;
/* For flow based devices, map all packets to VNI 0 */
if (vs->flags & VXLAN_F_COLLECT_METADATA)
vni = 0;
- hlist_for_each_entry_rcu(vxlan, vni_head(vs, vni), hlist) {
- if (vxlan->default_dst.remote_vni == vni)
- return vxlan;
+ hlist_for_each_entry_rcu(node, vni_head(vs, vni), hlist) {
+ if (node->vxlan->default_dst.remote_vni == vni)
+ return node->vxlan;
}
return NULL;
@@ -2309,17 +2309,22 @@
struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id);
spin_lock(&vn->sock_lock);
- hlist_del_init_rcu(&vxlan->hlist);
+ hlist_del_init_rcu(&vxlan->hlist4.hlist);
+#if IS_ENABLED(CONFIG_IPV6)
+ hlist_del_init_rcu(&vxlan->hlist6.hlist);
+#endif
spin_unlock(&vn->sock_lock);
}
-static void vxlan_vs_add_dev(struct vxlan_sock *vs, struct vxlan_dev *vxlan)
+static void vxlan_vs_add_dev(struct vxlan_sock *vs, struct vxlan_dev *vxlan,
+ struct vxlan_dev_node *node)
{
struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id);
__be32 vni = vxlan->default_dst.remote_vni;
+ node->vxlan = vxlan;
spin_lock(&vn->sock_lock);
- hlist_add_head_rcu(&vxlan->hlist, vni_head(vs, vni));
+ hlist_add_head_rcu(&node->hlist, vni_head(vs, vni));
spin_unlock(&vn->sock_lock);
}
@@ -2778,6 +2783,7 @@
{
struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id);
struct vxlan_sock *vs = NULL;
+ struct vxlan_dev_node *node;
if (!vxlan->cfg.no_share) {
spin_lock(&vn->sock_lock);
@@ -2795,12 +2801,16 @@
if (IS_ERR(vs))
return PTR_ERR(vs);
#if IS_ENABLED(CONFIG_IPV6)
- if (ipv6)
+ if (ipv6) {
rcu_assign_pointer(vxlan->vn6_sock, vs);
- else
+ node = &vxlan->hlist6;
+ } else
#endif
+ {
rcu_assign_pointer(vxlan->vn4_sock, vs);
- vxlan_vs_add_dev(vs, vxlan);
+ node = &vxlan->hlist4;
+ }
+ vxlan_vs_add_dev(vs, vxlan, node);
return 0;
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
index ae304355..fe5102c 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
@@ -1821,8 +1821,6 @@
static void ar9003_hw_tx99_start(struct ath_hw *ah, u32 qnum)
{
REG_SET_BIT(ah, AR_PHY_TEST, PHY_AGC_CLR);
- REG_SET_BIT(ah, 0x9864, 0x7f000);
- REG_SET_BIT(ah, 0x9924, 0x7f00fe);
REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS);
REG_WRITE(ah, AR_CR, AR_CR_RXD);
REG_WRITE(ah, AR_DLCL_IFS(qnum), 0);
diff --git a/drivers/net/wireless/ath/ath9k/rng.c b/drivers/net/wireless/ath/ath9k/rng.c
index d38e50f..e0374eb 100644
--- a/drivers/net/wireless/ath/ath9k/rng.c
+++ b/drivers/net/wireless/ath/ath9k/rng.c
@@ -120,6 +120,8 @@
void ath9k_rng_stop(struct ath_softc *sc)
{
- if (sc->rng_task)
+ if (sc->rng_task) {
kthread_stop(sc->rng_task);
+ sc->rng_task = NULL;
+ }
}
diff --git a/drivers/net/wireless/ath/ath9k/tx99.c b/drivers/net/wireless/ath/ath9k/tx99.c
index 16aca9e..1fa7f84 100644
--- a/drivers/net/wireless/ath/ath9k/tx99.c
+++ b/drivers/net/wireless/ath/ath9k/tx99.c
@@ -189,22 +189,27 @@
if (strtobool(buf, &start))
return -EINVAL;
+ mutex_lock(&sc->mutex);
+
if (start == sc->tx99_state) {
if (!start)
- return count;
+ goto out;
ath_dbg(common, XMIT, "Resetting TX99\n");
ath9k_tx99_deinit(sc);
}
if (!start) {
ath9k_tx99_deinit(sc);
- return count;
+ goto out;
}
r = ath9k_tx99_init(sc);
- if (r)
+ if (r) {
+ mutex_unlock(&sc->mutex);
return r;
-
+ }
+out:
+ mutex_unlock(&sc->mutex);
return count;
}
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index bb36fe5..70379c8 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -965,6 +965,9 @@
wil_hex_dump_misc("mgmt tx frame ", DUMP_PREFIX_OFFSET, 16, 1, buf,
len, true);
+ if (len < sizeof(struct ieee80211_hdr_3addr))
+ return -EINVAL;
+
cmd = kmalloc(sizeof(*cmd) + len, GFP_KERNEL);
if (!cmd) {
rc = -ENOMEM;
diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c
index 0ac657d..a0a676b 100644
--- a/drivers/net/wireless/ath/wil6210/debugfs.c
+++ b/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -799,8 +799,12 @@
struct wireless_dev *wdev = wil_to_wdev(wil);
struct cfg80211_mgmt_tx_params params;
int rc;
- void *frame = kmalloc(len, GFP_KERNEL);
+ void *frame;
+ if (!len)
+ return -EINVAL;
+
+ frame = kmalloc(len, GFP_KERNEL);
if (!frame)
return -ENOMEM;
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index ae0952f..3028f18 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -592,7 +592,8 @@
cfg80211_connect_bss(ndev, evt->bssid, wil->bss,
assoc_req_ie, assoc_req_ielen,
assoc_resp_ie, assoc_resp_ielen,
- WLAN_STATUS_SUCCESS, GFP_KERNEL);
+ WLAN_STATUS_SUCCESS, GFP_KERNEL,
+ NL80211_TIMEOUT_UNSPECIFIED);
}
wil->bss = NULL;
} else if ((wdev->iftype == NL80211_IFTYPE_AP) ||
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
index 72139b5..746f8c9 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
@@ -705,7 +705,7 @@
int brcmf_sdiod_recv_chain(struct brcmf_sdio_dev *sdiodev,
struct sk_buff_head *pktq, uint totlen)
{
- struct sk_buff *glom_skb;
+ struct sk_buff *glom_skb = NULL;
struct sk_buff *skb;
u32 addr = sdiodev->sbwad;
int err = 0;
@@ -726,10 +726,8 @@
return -ENOMEM;
err = brcmf_sdiod_buffrw(sdiodev, SDIO_FUNC_2, false, addr,
glom_skb);
- if (err) {
- brcmu_pkt_buf_free_skb(glom_skb);
+ if (err)
goto done;
- }
skb_queue_walk(pktq, skb) {
memcpy(skb->data, glom_skb->data, skb->len);
@@ -740,6 +738,7 @@
pktq);
done:
+ brcmu_pkt_buf_free_skb(glom_skb);
return err;
}
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index 01d44f9..b85398c 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -4930,6 +4930,11 @@
cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true,
GFP_KERNEL);
} else if (ieee80211_is_action(mgmt->frame_control)) {
+ if (len > BRCMF_FIL_ACTION_FRAME_SIZE + DOT11_MGMT_HDR_LEN) {
+ brcmf_err("invalid action frame length\n");
+ err = -EINVAL;
+ goto exit;
+ }
af_params = kzalloc(sizeof(*af_params), GFP_KERNEL);
if (af_params == NULL) {
brcmf_err("unable to allocate frame\n");
@@ -6873,7 +6878,7 @@
wiphy = wiphy_new(ops, sizeof(struct brcmf_cfg80211_info));
if (!wiphy) {
brcmf_err("Could not allocate wiphy device\n");
- return NULL;
+ goto ops_out;
}
memcpy(wiphy->perm_addr, drvr->mac, ETH_ALEN);
set_wiphy_dev(wiphy, busdev);
@@ -7007,6 +7012,7 @@
ifp->vif = NULL;
wiphy_out:
brcmf_free_wiphy(wiphy);
+ops_out:
kfree(ops);
return NULL;
}
diff --git a/drivers/net/wireless/ti/wlcore/spi.c b/drivers/net/wireless/ti/wlcore/spi.c
index f949ad2b..fa3547e 100644
--- a/drivers/net/wireless/ti/wlcore/spi.c
+++ b/drivers/net/wireless/ti/wlcore/spi.c
@@ -70,10 +70,10 @@
#define WSPI_MAX_CHUNK_SIZE 4092
/*
- * wl18xx driver aggregation buffer size is (13 * PAGE_SIZE) compared to
- * (4 * PAGE_SIZE) for wl12xx, so use the larger buffer needed for wl18xx
+ * wl18xx driver aggregation buffer size is (13 * 4K) compared to
+ * (4 * 4K) for wl12xx, so use the larger buffer needed for wl18xx
*/
-#define SPI_AGGR_BUFFER_SIZE (13 * PAGE_SIZE)
+#define SPI_AGGR_BUFFER_SIZE (13 * SZ_4K)
/* Maximum number of SPI write chunks */
#define WSPI_MAX_NUM_OF_CHUNKS \
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index 599cf50..cd442e4 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -281,6 +281,7 @@
{
RING_IDX req_prod = queue->rx.req_prod_pvt;
int notify;
+ int err = 0;
if (unlikely(!netif_carrier_ok(queue->info->netdev)))
return;
@@ -295,8 +296,10 @@
struct xen_netif_rx_request *req;
skb = xennet_alloc_one_rx_buffer(queue);
- if (!skb)
+ if (!skb) {
+ err = -ENOMEM;
break;
+ }
id = xennet_rxidx(req_prod);
@@ -320,8 +323,13 @@
queue->rx.req_prod_pvt = req_prod;
- /* Not enough requests? Try again later. */
- if (req_prod - queue->rx.sring->req_prod < NET_RX_SLOTS_MIN) {
+ /* Try again later if there are not enough requests or skb allocation
+ * failed.
+ * Enough requests is quantified as the sum of newly created slots and
+ * the unconsumed slots at the backend.
+ */
+ if (req_prod - queue->rx.rsp_cons < NET_RX_SLOTS_MIN ||
+ unlikely(err)) {
mod_timer(&queue->rx_refill_timer, jiffies + (HZ/10));
return;
}
diff --git a/drivers/nfc/nfcmrvl/fw_dnld.c b/drivers/nfc/nfcmrvl/fw_dnld.c
index f8dcdf4..af62c4c 100644
--- a/drivers/nfc/nfcmrvl/fw_dnld.c
+++ b/drivers/nfc/nfcmrvl/fw_dnld.c
@@ -459,7 +459,7 @@
INIT_WORK(&priv->fw_dnld.rx_work, fw_dnld_rx_work);
snprintf(name, sizeof(name), "%s_nfcmrvl_fw_dnld_rx_wq",
- dev_name(priv->dev));
+ dev_name(&priv->ndev->nfc_dev->dev));
priv->fw_dnld.rx_wq = create_singlethread_workqueue(name);
if (!priv->fw_dnld.rx_wq)
return -ENOMEM;
@@ -496,6 +496,7 @@
{
struct nfcmrvl_private *priv = nci_get_drvdata(ndev);
struct nfcmrvl_fw_dnld *fw_dnld = &priv->fw_dnld;
+ int res;
if (!priv->support_fw_dnld)
return -ENOTSUPP;
@@ -511,7 +512,9 @@
*/
/* Retrieve FW binary */
- if (request_firmware(&fw_dnld->fw, firmware_name, priv->dev) < 0) {
+ res = request_firmware(&fw_dnld->fw, firmware_name,
+ &ndev->nfc_dev->dev);
+ if (res < 0) {
nfc_err(priv->dev, "failed to retrieve FW %s", firmware_name);
return -ENOENT;
}
diff --git a/drivers/nfc/nfcmrvl/main.c b/drivers/nfc/nfcmrvl/main.c
index 51c8240..a446590 100644
--- a/drivers/nfc/nfcmrvl/main.c
+++ b/drivers/nfc/nfcmrvl/main.c
@@ -124,12 +124,13 @@
memcpy(&priv->config, pdata, sizeof(*pdata));
if (priv->config.reset_n_io) {
- rc = devm_gpio_request_one(dev,
- priv->config.reset_n_io,
- GPIOF_OUT_INIT_LOW,
- "nfcmrvl_reset_n");
- if (rc < 0)
+ rc = gpio_request_one(priv->config.reset_n_io,
+ GPIOF_OUT_INIT_LOW,
+ "nfcmrvl_reset_n");
+ if (rc < 0) {
+ priv->config.reset_n_io = 0;
nfc_err(dev, "failed to request reset_n io\n");
+ }
}
if (phy == NFCMRVL_PHY_SPI) {
@@ -154,32 +155,36 @@
if (!priv->ndev) {
nfc_err(dev, "nci_allocate_device failed\n");
rc = -ENOMEM;
- goto error;
+ goto error_free_gpio;
}
- nci_set_drvdata(priv->ndev, priv);
-
- rc = nci_register_device(priv->ndev);
- if (rc) {
- nfc_err(dev, "nci_register_device failed %d\n", rc);
- goto error_free_dev;
- }
-
- /* Ensure that controller is powered off */
- nfcmrvl_chip_halt(priv);
-
rc = nfcmrvl_fw_dnld_init(priv);
if (rc) {
nfc_err(dev, "failed to initialize FW download %d\n", rc);
goto error_free_dev;
}
+ nci_set_drvdata(priv->ndev, priv);
+
+ rc = nci_register_device(priv->ndev);
+ if (rc) {
+ nfc_err(dev, "nci_register_device failed %d\n", rc);
+ goto error_fw_dnld_deinit;
+ }
+
+ /* Ensure that controller is powered off */
+ nfcmrvl_chip_halt(priv);
+
nfc_info(dev, "registered with nci successfully\n");
return priv;
+error_fw_dnld_deinit:
+ nfcmrvl_fw_dnld_deinit(priv);
error_free_dev:
nci_free_device(priv->ndev);
-error:
+error_free_gpio:
+ if (priv->config.reset_n_io)
+ gpio_free(priv->config.reset_n_io);
kfree(priv);
return ERR_PTR(rc);
}
@@ -195,7 +200,7 @@
nfcmrvl_fw_dnld_deinit(priv);
if (priv->config.reset_n_io)
- devm_gpio_free(priv->dev, priv->config.reset_n_io);
+ gpio_free(priv->config.reset_n_io);
nci_unregister_device(ndev);
nci_free_device(ndev);
diff --git a/drivers/nfc/nfcmrvl/uart.c b/drivers/nfc/nfcmrvl/uart.c
index 83a99e3..6c0c301 100644
--- a/drivers/nfc/nfcmrvl/uart.c
+++ b/drivers/nfc/nfcmrvl/uart.c
@@ -109,6 +109,7 @@
struct nfcmrvl_private *priv;
struct nfcmrvl_platform_data *pdata = NULL;
struct nfcmrvl_platform_data config;
+ struct device *dev = nu->tty->dev;
/*
* Platform data cannot be used here since usually it is already used
@@ -116,9 +117,8 @@
* and check if DT entries were added.
*/
- if (nu->tty->dev->parent && nu->tty->dev->parent->of_node)
- if (nfcmrvl_uart_parse_dt(nu->tty->dev->parent->of_node,
- &config) == 0)
+ if (dev && dev->parent && dev->parent->of_node)
+ if (nfcmrvl_uart_parse_dt(dev->parent->of_node, &config) == 0)
pdata = &config;
if (!pdata) {
@@ -131,7 +131,7 @@
}
priv = nfcmrvl_nci_register_dev(NFCMRVL_PHY_UART, nu, &uart_ops,
- nu->tty->dev, pdata);
+ dev, pdata);
if (IS_ERR(priv))
return PTR_ERR(priv);
diff --git a/drivers/nvdimm/btt.c b/drivers/nvdimm/btt.c
index 368795a..94733f7 100644
--- a/drivers/nvdimm/btt.c
+++ b/drivers/nvdimm/btt.c
@@ -1203,10 +1203,13 @@
struct page *page, bool is_write)
{
struct btt *btt = bdev->bd_disk->private_data;
+ int rc;
- btt_do_bvec(btt, NULL, page, PAGE_SIZE, 0, is_write, sector);
- page_endio(page, is_write, 0);
- return 0;
+ rc = btt_do_bvec(btt, NULL, page, PAGE_SIZE, 0, is_write, sector);
+ if (rc == 0)
+ page_endio(page, is_write, 0);
+
+ return rc;
}
diff --git a/drivers/nvdimm/core.c b/drivers/nvdimm/core.c
index 7ceba08..18a0bea 100644
--- a/drivers/nvdimm/core.c
+++ b/drivers/nvdimm/core.c
@@ -450,14 +450,15 @@
static void __add_badblock_range(struct badblocks *bb, u64 ns_offset, u64 len)
{
const unsigned int sector_size = 512;
- sector_t start_sector;
+ sector_t start_sector, end_sector;
u64 num_sectors;
u32 rem;
start_sector = div_u64(ns_offset, sector_size);
- num_sectors = div_u64_rem(len, sector_size, &rem);
+ end_sector = div_u64_rem(ns_offset + len, sector_size, &rem);
if (rem)
- num_sectors++;
+ end_sector++;
+ num_sectors = end_sector - start_sector;
if (unlikely(num_sectors > (u64)INT_MAX)) {
u64 remaining = num_sectors;
diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
index 3222f3e..286fda4 100644
--- a/drivers/nvme/host/rdma.c
+++ b/drivers/nvme/host/rdma.c
@@ -88,7 +88,7 @@
struct nvme_rdma_queue {
struct nvme_rdma_qe *rsp_ring;
- u8 sig_count;
+ atomic_t sig_count;
int queue_size;
size_t cmnd_capsule_len;
struct nvme_rdma_ctrl *ctrl;
@@ -555,6 +555,7 @@
queue->cmnd_capsule_len = sizeof(struct nvme_command);
queue->queue_size = queue_size;
+ atomic_set(&queue->sig_count, 0);
queue->cm_id = rdma_create_id(&init_net, nvme_rdma_cm_handler, queue,
RDMA_PS_TCP, IB_QPT_RC);
@@ -1011,17 +1012,16 @@
nvme_rdma_wr_error(cq, wc, "SEND");
}
-static inline int nvme_rdma_queue_sig_limit(struct nvme_rdma_queue *queue)
+/*
+ * We want to signal completion at least every queue depth/2. This returns the
+ * largest power of two that is not above half of (queue size + 1) to optimize
+ * (avoid divisions).
+ */
+static inline bool nvme_rdma_queue_sig_limit(struct nvme_rdma_queue *queue)
{
- int sig_limit;
+ int limit = 1 << ilog2((queue->queue_size + 1) / 2);
- /*
- * We signal completion every queue depth/2 and also handle the
- * degenerated case of a device with queue_depth=1, where we
- * would need to signal every message.
- */
- sig_limit = max(queue->queue_size / 2, 1);
- return (++queue->sig_count % sig_limit) == 0;
+ return (atomic_inc_return(&queue->sig_count) & (limit - 1)) == 0;
}
static int nvme_rdma_post_send(struct nvme_rdma_queue *queue,
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index 965911d..1b4d93e 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -488,21 +488,24 @@
rval = device_add(&nvmem->dev);
if (rval)
- goto out;
+ goto err_put_device;
if (config->compat) {
rval = nvmem_setup_compat(nvmem, config);
if (rval)
- goto out;
+ goto err_device_del;
}
if (config->cells)
nvmem_add_cells(nvmem, config);
return nvmem;
-out:
- ida_simple_remove(&nvmem_ida, nvmem->id);
- kfree(nvmem);
+
+err_device_del:
+ device_del(&nvmem->dev);
+err_put_device:
+ put_device(&nvmem->dev);
+
return ERR_PTR(rval);
}
EXPORT_SYMBOL_GPL(nvmem_register);
diff --git a/drivers/of/device.c b/drivers/of/device.c
index fd5cfad..f7a9701 100644
--- a/drivers/of/device.c
+++ b/drivers/of/device.c
@@ -225,6 +225,7 @@
return tsize;
}
+EXPORT_SYMBOL_GPL(of_device_get_modalias);
/**
* of_device_uevent - Display OF related uevent information
@@ -287,3 +288,4 @@
return 0;
}
+EXPORT_SYMBOL_GPL(of_device_uevent_modalias);
diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c
index 3ed6238..c4953ec 100644
--- a/drivers/parisc/ccio-dma.c
+++ b/drivers/parisc/ccio-dma.c
@@ -741,6 +741,8 @@
BUG_ON(!dev);
ioc = GET_IOC(dev);
+ if (!ioc)
+ return DMA_ERROR_CODE;
BUG_ON(size <= 0);
@@ -814,6 +816,10 @@
BUG_ON(!dev);
ioc = GET_IOC(dev);
+ if (!ioc) {
+ WARN_ON(!ioc);
+ return;
+ }
DBG_RUN("%s() iovp 0x%lx/%x\n",
__func__, (long)iova, size);
@@ -918,6 +924,8 @@
BUG_ON(!dev);
ioc = GET_IOC(dev);
+ if (!ioc)
+ return 0;
DBG_RUN_SG("%s() START %d entries\n", __func__, nents);
@@ -990,6 +998,10 @@
BUG_ON(!dev);
ioc = GET_IOC(dev);
+ if (!ioc) {
+ WARN_ON(!ioc);
+ return;
+ }
DBG_RUN_SG("%s() START %d entries, %p,%x\n",
__func__, nents, sg_virt(sglist), sglist->length);
diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c
index 1133b5c..5c63b92 100644
--- a/drivers/parisc/dino.c
+++ b/drivers/parisc/dino.c
@@ -154,7 +154,10 @@
};
/* Looks nice and keeps the compiler happy */
-#define DINO_DEV(d) ((struct dino_device *) d)
+#define DINO_DEV(d) ({ \
+ void *__pdata = d; \
+ BUG_ON(!__pdata); \
+ (struct dino_device *)__pdata; })
/*
diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c
index 2ec2aef..bc286cb 100644
--- a/drivers/parisc/lba_pci.c
+++ b/drivers/parisc/lba_pci.c
@@ -111,8 +111,10 @@
/* Looks nice and keeps the compiler happy */
-#define LBA_DEV(d) ((struct lba_device *) (d))
-
+#define LBA_DEV(d) ({ \
+ void *__pdata = d; \
+ BUG_ON(!__pdata); \
+ (struct lba_device *)__pdata; })
/*
** Only allow 8 subsidiary busses per LBA
diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c
index 151b86b..56918d1 100644
--- a/drivers/parisc/sba_iommu.c
+++ b/drivers/parisc/sba_iommu.c
@@ -691,6 +691,8 @@
return 0;
ioc = GET_IOC(dev);
+ if (!ioc)
+ return 0;
/*
* check if mask is >= than the current max IO Virt Address
@@ -722,6 +724,8 @@
int pide;
ioc = GET_IOC(dev);
+ if (!ioc)
+ return DMA_ERROR_CODE;
/* save offset bits */
offset = ((dma_addr_t) (long) addr) & ~IOVP_MASK;
@@ -813,6 +817,10 @@
DBG_RUN("%s() iovp 0x%lx/%x\n", __func__, (long) iova, size);
ioc = GET_IOC(dev);
+ if (!ioc) {
+ WARN_ON(!ioc);
+ return;
+ }
offset = iova & ~IOVP_MASK;
iova ^= offset; /* clear offset bits */
size += offset;
@@ -952,6 +960,8 @@
DBG_RUN_SG("%s() START %d entries\n", __func__, nents);
ioc = GET_IOC(dev);
+ if (!ioc)
+ return 0;
/* Fast path single entry scatterlists. */
if (nents == 1) {
@@ -1037,6 +1047,10 @@
__func__, nents, sg_virt(sglist), sglist->length);
ioc = GET_IOC(dev);
+ if (!ioc) {
+ WARN_ON(!ioc);
+ return;
+ }
#ifdef SBA_COLLECT_STATS
ioc->usg_calls++;
diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c
index 3452983..03ebfd5 100644
--- a/drivers/pci/host/pcie-rockchip.c
+++ b/drivers/pci/host/pcie-rockchip.c
@@ -131,6 +131,7 @@
PCIE_CORE_INT_CT | PCIE_CORE_INT_UTC | \
PCIE_CORE_INT_MMVC)
+#define PCIE_RC_CONFIG_NORMAL_BASE 0x800000
#define PCIE_RC_CONFIG_BASE 0xa00000
#define PCIE_RC_CONFIG_VENDOR (PCIE_RC_CONFIG_BASE + 0x00)
#define PCIE_RC_CONFIG_RID_CCR (PCIE_RC_CONFIG_BASE + 0x08)
@@ -267,7 +268,9 @@
static int rockchip_pcie_rd_own_conf(struct rockchip_pcie *rockchip,
int where, int size, u32 *val)
{
- void __iomem *addr = rockchip->apb_base + PCIE_RC_CONFIG_BASE + where;
+ void __iomem *addr;
+
+ addr = rockchip->apb_base + PCIE_RC_CONFIG_NORMAL_BASE + where;
if (!IS_ALIGNED((uintptr_t)addr, size)) {
*val = 0;
@@ -291,11 +294,13 @@
int where, int size, u32 val)
{
u32 mask, tmp, offset;
+ void __iomem *addr;
offset = where & ~0x3;
+ addr = rockchip->apb_base + PCIE_RC_CONFIG_NORMAL_BASE + offset;
if (size == 4) {
- writel(val, rockchip->apb_base + PCIE_RC_CONFIG_BASE + offset);
+ writel(val, addr);
return PCIBIOS_SUCCESSFUL;
}
@@ -306,9 +311,9 @@
* corrupt RW1C bits in adjacent registers. But the hardware
* doesn't support smaller writes.
*/
- tmp = readl(rockchip->apb_base + PCIE_RC_CONFIG_BASE + offset) & mask;
+ tmp = readl(addr) & mask;
tmp |= val << ((where & 0x3) * 8);
- writel(tmp, rockchip->apb_base + PCIE_RC_CONFIG_BASE + offset);
+ writel(tmp, addr);
return PCIBIOS_SUCCESSFUL;
}
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 1ccce1c..8a68e2b 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -954,6 +954,7 @@
return pci_legacy_resume_early(dev);
pci_update_current_state(pci_dev, PCI_D0);
+ pci_restore_state(pci_dev);
if (drv && drv->pm && drv->pm->thaw_noirq)
error = drv->pm->thaw_noirq(dev);
diff --git a/drivers/pinctrl/qcom/pinctrl-lpi.c b/drivers/pinctrl/qcom/pinctrl-lpi.c
index 11f954e..39c35b7 100644
--- a/drivers/pinctrl/qcom/pinctrl-lpi.c
+++ b/drivers/pinctrl/qcom/pinctrl-lpi.c
@@ -26,7 +26,7 @@
#include "../core.h"
#include "../pinctrl-utils.h"
-#define LPI_ADDRESS_SIZE 0xC000
+#define LPI_ADDRESS_SIZE 0x20000
#define LPI_GPIO_REG_VAL_CTL 0x00
#define LPI_GPIO_REG_DIR_CTL 0x04
@@ -109,35 +109,35 @@
0x00000000,
0x00001000,
0x00002000,
- 0x00002010,
0x00003000,
- 0x00003010,
0x00004000,
- 0x00004010,
0x00005000,
- 0x00005010,
- 0x00005020,
- 0x00005030,
0x00006000,
- 0x00006010,
0x00007000,
- 0x00007010,
- 0x00005040,
- 0x00005050,
0x00008000,
- 0x00008010,
- 0x00008020,
- 0x00008030,
- 0x00008040,
- 0x00008050,
- 0x00008060,
- 0x00008070,
0x00009000,
- 0x00009010,
0x0000A000,
- 0x0000A010,
0x0000B000,
- 0x0000B010,
+ 0x0000C000,
+ 0x0000D000,
+ 0x0000E000,
+ 0x0000F000,
+ 0x00010000,
+ 0x00011000,
+ 0x00012000,
+ 0x00013000,
+ 0x00014000,
+ 0x00015000,
+ 0x00016000,
+ 0x00017000,
+ 0x00018000,
+ 0x00019000,
+ 0x0001A000,
+ 0x0001B000,
+ 0x0001C000,
+ 0x0001D000,
+ 0x0001E000,
+ 0x0001F000,
};
static const char *const lpi_gpio_functions[] = {
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c
index 9520166..c6a5d29 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.c
+++ b/drivers/pinctrl/qcom/pinctrl-msm.c
@@ -40,6 +40,7 @@
#define MAX_NR_GPIO 300
#define PS_HOLD_OFFSET 0x820
+#define STATUS_OFFSET 0x10
/**
* struct msm_pinctrl - state for a pinctrl-msm device
@@ -74,6 +75,35 @@
static struct msm_pinctrl *msm_pinctrl_data;
+static u32 msm_pinctrl_find_base(const struct msm_pinctrl_soc_data *soc_data,
+ u32 gpio_id)
+{
+ int i;
+ u32 val;
+
+ if (gpio_id >= soc_data->ngpios || !soc_data->pin_base)
+ return 0;
+
+ if (soc_data->pin_base[gpio_id])
+ return soc_data->pin_base[gpio_id];
+
+ for (i = 0; i < soc_data->n_tile_offsets; i++) {
+ val = readl_relaxed(msm_pinctrl_data->regs +
+ soc_data->tile_offsets[i] + STATUS_OFFSET
+ + soc_data->reg_size * gpio_id);
+ if (val) {
+ soc_data->pin_base[gpio_id] = soc_data->tile_offsets[i];
+ return soc_data->tile_offsets[i];
+ }
+ }
+
+ /* In the case that the soc_data does not support dynamic base
+ * detection, we return 0 here.
+ */
+ WARN_ONCE(1, "%s:Dynamic base detection is not supported\n", __func__);
+ return 0;
+}
+
static int msm_get_groups_count(struct pinctrl_dev *pctldev)
{
struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
@@ -143,10 +173,11 @@
struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
const struct msm_pingroup *g;
unsigned long flags;
- u32 val, mask;
+ u32 val, mask, base;
int i;
g = &pctrl->soc->groups[group];
+ base = msm_pinctrl_find_base(pctrl->soc, group);
mask = GENMASK(g->mux_bit + order_base_2(g->nfuncs) - 1, g->mux_bit);
for (i = 0; i < g->nfuncs; i++) {
@@ -159,10 +190,10 @@
spin_lock_irqsave(&pctrl->lock, flags);
- val = readl(pctrl->regs + g->ctl_reg);
+ val = readl(pctrl->regs + base + g->ctl_reg);
val &= ~mask;
val |= i << g->mux_bit;
- writel(val, pctrl->regs + g->ctl_reg);
+ writel(val, pctrl->regs + base + g->ctl_reg);
spin_unlock_irqrestore(&pctrl->lock, flags);
@@ -227,15 +258,16 @@
unsigned arg;
unsigned bit;
int ret;
- u32 val;
+ u32 val, base;
g = &pctrl->soc->groups[group];
+ base = msm_pinctrl_find_base(pctrl->soc, group);
ret = msm_config_reg(pctrl, g, param, &mask, &bit);
if (ret < 0)
return ret;
- val = readl(pctrl->regs + g->ctl_reg);
+ val = readl(pctrl->regs + base + g->ctl_reg);
arg = (val >> bit) & mask;
/* Convert register value to pinconf value */
@@ -260,7 +292,7 @@
if (!arg)
return -EINVAL;
- val = readl(pctrl->regs + g->io_reg);
+ val = readl(pctrl->regs + base + g->io_reg);
arg = !!(val & BIT(g->in_bit));
break;
case PIN_CONFIG_INPUT_ENABLE:
@@ -291,11 +323,12 @@
unsigned arg;
unsigned bit;
int ret;
- u32 val;
+ u32 val, base;
int i;
g = &pctrl->soc->groups[group];
+ base = msm_pinctrl_find_base(pctrl->soc, group);
for (i = 0; i < num_configs; i++) {
param = pinconf_to_config_param(configs[i]);
arg = pinconf_to_config_argument(configs[i]);
@@ -328,12 +361,12 @@
case PIN_CONFIG_OUTPUT:
/* set output value */
spin_lock_irqsave(&pctrl->lock, flags);
- val = readl(pctrl->regs + g->io_reg);
+ val = readl(pctrl->regs + base + g->io_reg);
if (arg)
val |= BIT(g->out_bit);
else
val &= ~BIT(g->out_bit);
- writel(val, pctrl->regs + g->io_reg);
+ writel(val, pctrl->regs + base + g->io_reg);
spin_unlock_irqrestore(&pctrl->lock, flags);
/* enable output */
@@ -356,10 +389,10 @@
}
spin_lock_irqsave(&pctrl->lock, flags);
- val = readl(pctrl->regs + g->ctl_reg);
+ val = readl(pctrl->regs + base + g->ctl_reg);
val &= ~(mask << bit);
val |= arg << bit;
- writel(val, pctrl->regs + g->ctl_reg);
+ writel(val, pctrl->regs + base + g->ctl_reg);
spin_unlock_irqrestore(&pctrl->lock, flags);
}
@@ -384,15 +417,16 @@
const struct msm_pingroup *g;
struct msm_pinctrl *pctrl = gpiochip_get_data(chip);
unsigned long flags;
- u32 val;
+ u32 val, base;
g = &pctrl->soc->groups[offset];
+ base = msm_pinctrl_find_base(pctrl->soc, offset);
spin_lock_irqsave(&pctrl->lock, flags);
- val = readl(pctrl->regs + g->ctl_reg);
+ val = readl(pctrl->regs + base + g->ctl_reg);
val &= ~BIT(g->oe_bit);
- writel(val, pctrl->regs + g->ctl_reg);
+ writel(val, pctrl->regs + base + g->ctl_reg);
spin_unlock_irqrestore(&pctrl->lock, flags);
@@ -404,22 +438,23 @@
const struct msm_pingroup *g;
struct msm_pinctrl *pctrl = gpiochip_get_data(chip);
unsigned long flags;
- u32 val;
+ u32 val, base;
g = &pctrl->soc->groups[offset];
+ base = msm_pinctrl_find_base(pctrl->soc, offset);
spin_lock_irqsave(&pctrl->lock, flags);
- val = readl(pctrl->regs + g->io_reg);
+ val = readl(pctrl->regs + base + g->io_reg);
if (value)
val |= BIT(g->out_bit);
else
val &= ~BIT(g->out_bit);
- writel(val, pctrl->regs + g->io_reg);
+ writel(val, pctrl->regs + base + g->io_reg);
- val = readl(pctrl->regs + g->ctl_reg);
+ val = readl(pctrl->regs + base + g->ctl_reg);
val |= BIT(g->oe_bit);
- writel(val, pctrl->regs + g->ctl_reg);
+ writel(val, pctrl->regs + base + g->ctl_reg);
spin_unlock_irqrestore(&pctrl->lock, flags);
@@ -430,11 +465,12 @@
{
const struct msm_pingroup *g;
struct msm_pinctrl *pctrl = gpiochip_get_data(chip);
- u32 val;
+ u32 val, base;
g = &pctrl->soc->groups[offset];
+ base = msm_pinctrl_find_base(pctrl->soc, offset);
- val = readl(pctrl->regs + g->io_reg);
+ val = readl(pctrl->regs + base + g->io_reg);
return !!(val & BIT(g->in_bit));
}
@@ -443,18 +479,19 @@
const struct msm_pingroup *g;
struct msm_pinctrl *pctrl = gpiochip_get_data(chip);
unsigned long flags;
- u32 val;
+ u32 val, base;
g = &pctrl->soc->groups[offset];
+ base = msm_pinctrl_find_base(pctrl->soc, offset);
spin_lock_irqsave(&pctrl->lock, flags);
- val = readl(pctrl->regs + g->io_reg);
+ val = readl(pctrl->regs + base + g->io_reg);
if (value)
val |= BIT(g->out_bit);
else
val &= ~BIT(g->out_bit);
- writel(val, pctrl->regs + g->io_reg);
+ writel(val, pctrl->regs + base + g->io_reg);
spin_unlock_irqrestore(&pctrl->lock, flags);
}
@@ -474,7 +511,7 @@
int is_out;
int drive;
int pull;
- u32 ctl_reg;
+ u32 ctl_reg, base;
static const char * const pulls[] = {
"no pull",
@@ -484,7 +521,9 @@
};
g = &pctrl->soc->groups[offset];
- ctl_reg = readl(pctrl->regs + g->ctl_reg);
+ base = msm_pinctrl_find_base(pctrl->soc, offset);
+
+ ctl_reg = readl(pctrl->regs + base + g->ctl_reg);
is_out = !!(ctl_reg & BIT(g->oe_bit));
func = (ctl_reg >> g->mux_bit) & 7;
@@ -543,21 +582,21 @@
*/
static void msm_gpio_update_dual_edge_pos(struct msm_pinctrl *pctrl,
const struct msm_pingroup *g,
- struct irq_data *d)
+ struct irq_data *d, u32 base)
{
int loop_limit = 100;
unsigned val, val2, intstat;
unsigned pol;
do {
- val = readl(pctrl->regs + g->io_reg) & BIT(g->in_bit);
+ val = readl(pctrl->regs + base + g->io_reg) & BIT(g->in_bit);
- pol = readl(pctrl->regs + g->intr_cfg_reg);
+ pol = readl(pctrl->regs + base + g->intr_cfg_reg);
pol ^= BIT(g->intr_polarity_bit);
- writel(pol, pctrl->regs + g->intr_cfg_reg);
+ writel(pol, pctrl->regs + base + g->intr_cfg_reg);
- val2 = readl(pctrl->regs + g->io_reg) & BIT(g->in_bit);
- intstat = readl(pctrl->regs + g->intr_status_reg);
+ val2 = readl(pctrl->regs + base + g->io_reg) & BIT(g->in_bit);
+ intstat = readl(pctrl->regs + base + g->intr_status_reg);
if (intstat || (val == val2))
return;
} while (loop_limit-- > 0);
@@ -571,15 +610,16 @@
struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
const struct msm_pingroup *g;
unsigned long flags;
- u32 val;
+ u32 val, base;
g = &pctrl->soc->groups[d->hwirq];
+ base = msm_pinctrl_find_base(pctrl->soc, d->hwirq);
spin_lock_irqsave(&pctrl->lock, flags);
- val = readl(pctrl->regs + g->intr_cfg_reg);
+ val = readl(pctrl->regs + base + g->intr_cfg_reg);
val &= ~BIT(g->intr_enable_bit);
- writel(val, pctrl->regs + g->intr_cfg_reg);
+ writel(val, pctrl->regs + base + g->intr_cfg_reg);
clear_bit(d->hwirq, pctrl->enabled_irqs);
@@ -592,15 +632,16 @@
struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
const struct msm_pingroup *g;
unsigned long flags;
- u32 val;
+ u32 val, base;
g = &pctrl->soc->groups[d->hwirq];
+ base = msm_pinctrl_find_base(pctrl->soc, d->hwirq);
spin_lock_irqsave(&pctrl->lock, flags);
- val = readl(pctrl->regs + g->intr_cfg_reg);
+ val = readl(pctrl->regs + base + g->intr_cfg_reg);
val |= BIT(g->intr_enable_bit);
- writel(val, pctrl->regs + g->intr_cfg_reg);
+ writel(val, pctrl->regs + base + g->intr_cfg_reg);
set_bit(d->hwirq, pctrl->enabled_irqs);
@@ -613,21 +654,22 @@
struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
const struct msm_pingroup *g;
unsigned long flags;
- u32 val;
+ u32 val, base;
g = &pctrl->soc->groups[d->hwirq];
+ base = msm_pinctrl_find_base(pctrl->soc, d->hwirq);
spin_lock_irqsave(&pctrl->lock, flags);
- val = readl(pctrl->regs + g->intr_status_reg);
+ val = readl(pctrl->regs + base + g->intr_status_reg);
if (g->intr_ack_high)
val |= BIT(g->intr_status_bit);
else
val &= ~BIT(g->intr_status_bit);
- writel(val, pctrl->regs + g->intr_status_reg);
+ writel(val, pctrl->regs + base + g->intr_status_reg);
if (test_bit(d->hwirq, pctrl->dual_edge_irqs))
- msm_gpio_update_dual_edge_pos(pctrl, g, d);
+ msm_gpio_update_dual_edge_pos(pctrl, g, d, base);
spin_unlock_irqrestore(&pctrl->lock, flags);
}
@@ -638,10 +680,10 @@
struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
const struct msm_pingroup *g;
unsigned long flags;
- u32 val;
+ u32 val, base;
g = &pctrl->soc->groups[d->hwirq];
-
+ base = msm_pinctrl_find_base(pctrl->soc, d->hwirq);
spin_lock_irqsave(&pctrl->lock, flags);
/*
@@ -653,17 +695,17 @@
clear_bit(d->hwirq, pctrl->dual_edge_irqs);
/* Route interrupts to application cpu */
- val = readl(pctrl->regs + g->intr_target_reg);
+ val = readl(pctrl->regs + base + g->intr_target_reg);
val &= ~(7 << g->intr_target_bit);
val |= g->intr_target_kpss_val << g->intr_target_bit;
- writel(val, pctrl->regs + g->intr_target_reg);
+ writel(val, pctrl->regs + base + g->intr_target_reg);
/* Update configuration for gpio.
* RAW_STATUS_EN is left on for all gpio irqs. Due to the
* internal circuitry of TLMM, toggling the RAW_STATUS
* could cause the INTR_STATUS to be set for EDGE interrupts.
*/
- val = readl(pctrl->regs + g->intr_cfg_reg);
+ val = readl(pctrl->regs + base + g->intr_cfg_reg);
val |= BIT(g->intr_raw_status_bit);
if (g->intr_detection_width == 2) {
val &= ~(3 << g->intr_detection_bit);
@@ -711,10 +753,10 @@
} else {
BUG();
}
- writel(val, pctrl->regs + g->intr_cfg_reg);
+ writel(val, pctrl->regs + base + g->intr_cfg_reg);
if (test_bit(d->hwirq, pctrl->dual_edge_irqs))
- msm_gpio_update_dual_edge_pos(pctrl, g, d);
+ msm_gpio_update_dual_edge_pos(pctrl, g, d, base);
spin_unlock_irqrestore(&pctrl->lock, flags);
@@ -843,7 +885,7 @@
struct irq_chip *chip = irq_desc_get_chip(desc);
int irq_pin;
int handled = 0;
- u32 val;
+ u32 val, base;
int i;
chained_irq_enter(chip, desc);
@@ -854,7 +896,8 @@
*/
for_each_set_bit(i, pctrl->enabled_irqs, pctrl->chip.ngpio) {
g = &pctrl->soc->groups[i];
- val = readl(pctrl->regs + g->intr_status_reg);
+ base = msm_pinctrl_find_base(pctrl->soc, i);
+ val = readl(pctrl->regs + base + g->intr_status_reg);
if (val & BIT(g->intr_status_bit)) {
irq_pin = irq_find_mapping(gc->irqdomain, i);
generic_handle_irq(irq_pin);
@@ -951,7 +994,7 @@
ret = gpiochip_irqchip_add(chip,
&msm_gpio_irq_chip,
0,
- handle_edge_irq,
+ handle_fasteoi_irq,
IRQ_TYPE_NONE);
if (ret) {
dev_err(pctrl->dev, "Failed to add irqchip to gpiochip\n");
@@ -1016,6 +1059,7 @@
const struct msm_pingroup *g;
const char *name = "null";
struct msm_pinctrl *pctrl = msm_pinctrl_data;
+ u32 base;
if (!msm_show_resume_irq_mask)
return;
@@ -1023,7 +1067,8 @@
spin_lock_irqsave(&pctrl->lock, flags);
for_each_set_bit(i, pctrl->enabled_irqs, pctrl->chip.ngpio) {
g = &pctrl->soc->groups[i];
- val = readl_relaxed(pctrl->regs + g->intr_status_reg);
+ base = msm_pinctrl_find_base(pctrl->soc, i);
+ val = readl_relaxed(pctrl->regs + base + g->intr_status_reg);
if (val & BIT(g->intr_status_bit)) {
irq = irq_find_mapping(pctrl->chip.irqdomain, i);
desc = irq_to_desc(irq);
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.h b/drivers/pinctrl/qcom/pinctrl-msm.h
index 0e223e0..375a962 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.h
+++ b/drivers/pinctrl/qcom/pinctrl-msm.h
@@ -129,6 +129,10 @@
unsigned ngpios;
const struct msm_dir_conn *dir_conn;
unsigned int n_dir_conns;
+ const u32 *tile_offsets;
+ unsigned int n_tile_offsets;
+ u32 *pin_base;
+ unsigned int reg_size;
};
int msm_pinctrl_probe(struct platform_device *pdev,
diff --git a/drivers/pinctrl/qcom/pinctrl-sdm670.c b/drivers/pinctrl/qcom/pinctrl-sdm670.c
index 1f742f8..b454cc442 100644
--- a/drivers/pinctrl/qcom/pinctrl-sdm670.c
+++ b/drivers/pinctrl/qcom/pinctrl-sdm670.c
@@ -25,12 +25,8 @@
.ngroups = ARRAY_SIZE(fname##_groups), \
}
-#define NORTH 0x00500000
-#define SOUTH 0x00900000
-#define WEST 0x00100000
-#define DUMMY 0x0
#define REG_SIZE 0x1000
-#define PINGROUP(id, base, f1, f2, f3, f4, f5, f6, f7, f8, f9) \
+#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9) \
{ \
.name = "gpio" #id, \
.pins = gpio##id##_pins, \
@@ -48,11 +44,11 @@
msm_mux_##f9 \
}, \
.nfuncs = 10, \
- .ctl_reg = base + REG_SIZE * id, \
- .io_reg = base + 0x4 + REG_SIZE * id, \
- .intr_cfg_reg = base + 0x8 + REG_SIZE * id, \
- .intr_status_reg = base + 0xc + REG_SIZE * id, \
- .intr_target_reg = base + 0x8 + REG_SIZE * id, \
+ .ctl_reg = REG_SIZE * id, \
+ .io_reg = 0x4 + REG_SIZE * id, \
+ .intr_cfg_reg = 0x8 + REG_SIZE * id, \
+ .intr_status_reg = 0xc + REG_SIZE * id, \
+ .intr_target_reg = 0x8 + REG_SIZE * id, \
.mux_bit = 2, \
.pull_bit = 0, \
.drv_bit = 6, \
@@ -118,6 +114,10 @@
.intr_detection_bit = -1, \
.intr_detection_width = -1, \
}
+
+static const u32 sdm670_tile_offsets[] = {0x100000, 0x500000, 0x900000};
+static u32 sdm670_pin_base[150];
+
static const struct pinctrl_pin_desc sdm670_pins[] = {
PINCTRL_PIN(0, "GPIO_0"),
PINCTRL_PIN(1, "GPIO_1"),
@@ -1332,249 +1332,249 @@
* Clients would not be able to request these dummy pin groups.
*/
static const struct msm_pingroup sdm670_groups[] = {
- [0] = PINGROUP(0, SOUTH, qup0, NA, NA, NA, NA, NA, NA, NA, NA),
- [1] = PINGROUP(1, SOUTH, qup0, NA, NA, NA, NA, NA, NA, NA, NA),
- [2] = PINGROUP(2, SOUTH, qup0, NA, NA, NA, NA, NA, NA, NA, NA),
- [3] = PINGROUP(3, SOUTH, qup0, NA, NA, NA, NA, NA, NA, NA, NA),
- [4] = PINGROUP(4, NORTH, qup9, qdss_cti, NA, NA, NA, NA, NA, NA, NA),
- [5] = PINGROUP(5, NORTH, qup9, qdss_cti, NA, NA, NA, NA, NA, NA, NA),
- [6] = PINGROUP(6, NORTH, qup9, NA, ddr_pxi0, NA, NA, NA, NA, NA, NA),
- [7] = PINGROUP(7, NORTH, qup9, ddr_bist, NA, atest_tsens2,
+ [0] = PINGROUP(0, qup0, NA, NA, NA, NA, NA, NA, NA, NA),
+ [1] = PINGROUP(1, qup0, NA, NA, NA, NA, NA, NA, NA, NA),
+ [2] = PINGROUP(2, qup0, NA, NA, NA, NA, NA, NA, NA, NA),
+ [3] = PINGROUP(3, qup0, NA, NA, NA, NA, NA, NA, NA, NA),
+ [4] = PINGROUP(4, qup9, qdss_cti, NA, NA, NA, NA, NA, NA, NA),
+ [5] = PINGROUP(5, qup9, qdss_cti, NA, NA, NA, NA, NA, NA, NA),
+ [6] = PINGROUP(6, qup9, NA, ddr_pxi0, NA, NA, NA, NA, NA, NA),
+ [7] = PINGROUP(7, qup9, ddr_bist, NA, atest_tsens2,
vsense_trigger, atest_usb1, ddr_pxi0, NA, NA),
- [8] = PINGROUP(8, WEST, qup_l4, GP_PDM1, ddr_bist, NA, NA, NA, NA, NA,
+ [8] = PINGROUP(8, qup_l4, GP_PDM1, ddr_bist, NA, NA, NA, NA, NA,
NA),
- [9] = PINGROUP(9, WEST, qup_l5, ddr_bist, NA, NA, NA, NA, NA, NA, NA),
- [10] = PINGROUP(10, NORTH, mdp_vsync, qup_l6, ddr_bist, wlan2_adc1,
+ [9] = PINGROUP(9, qup_l5, ddr_bist, NA, NA, NA, NA, NA, NA, NA),
+ [10] = PINGROUP(10, mdp_vsync, qup_l6, ddr_bist, wlan2_adc1,
atest_usb11, ddr_pxi2, NA, NA, NA),
- [11] = PINGROUP(11, NORTH, mdp_vsync, edp_lcd, dbg_out, wlan2_adc0,
+ [11] = PINGROUP(11, mdp_vsync, edp_lcd, dbg_out, wlan2_adc0,
atest_usb10, ddr_pxi2, NA, NA, NA),
- [12] = PINGROUP(12, SOUTH, mdp_vsync, m_voc, tsif1_sync, ddr_pxi3, NA,
+ [12] = PINGROUP(12, mdp_vsync, m_voc, tsif1_sync, ddr_pxi3, NA,
NA, NA, NA, NA),
- [13] = PINGROUP(13, WEST, cam_mclk, pll_bypassnl, qdss_gpio0, ddr_pxi3,
+ [13] = PINGROUP(13, cam_mclk, pll_bypassnl, qdss_gpio0, ddr_pxi3,
NA, NA, NA, NA, NA),
- [14] = PINGROUP(14, WEST, cam_mclk, pll_reset, qdss_gpio1, NA, NA, NA,
+ [14] = PINGROUP(14, cam_mclk, pll_reset, qdss_gpio1, NA, NA, NA,
NA, NA, NA),
- [15] = PINGROUP(15, WEST, cam_mclk, qdss_gpio2, NA, NA, NA, NA, NA, NA,
+ [15] = PINGROUP(15, cam_mclk, qdss_gpio2, NA, NA, NA, NA, NA, NA,
NA),
- [16] = PINGROUP(16, WEST, cam_mclk, qdss_gpio3, NA, NA, NA, NA, NA, NA,
+ [16] = PINGROUP(16, cam_mclk, qdss_gpio3, NA, NA, NA, NA, NA, NA,
NA),
- [17] = PINGROUP(17, WEST, cci_i2c, qup1, qdss_gpio4, NA, NA, NA, NA,
+ [17] = PINGROUP(17, cci_i2c, qup1, qdss_gpio4, NA, NA, NA, NA,
NA, NA),
- [18] = PINGROUP(18, WEST, cci_i2c, qup1, NA, qdss_gpio5, NA, NA, NA,
+ [18] = PINGROUP(18, cci_i2c, qup1, NA, qdss_gpio5, NA, NA, NA,
NA, NA),
- [19] = PINGROUP(19, WEST, cci_i2c, qup1, NA, qdss_gpio6, NA, NA, NA,
+ [19] = PINGROUP(19, cci_i2c, qup1, NA, qdss_gpio6, NA, NA, NA,
NA, NA),
- [20] = PINGROUP(20, WEST, cci_i2c, qup1, NA, qdss_gpio7, NA, NA, NA,
+ [20] = PINGROUP(20, cci_i2c, qup1, NA, qdss_gpio7, NA, NA, NA,
NA, NA),
- [21] = PINGROUP(21, WEST, cci_timer0, gcc_gp2, qdss_gpio8, NA, NA, NA,
+ [21] = PINGROUP(21, cci_timer0, gcc_gp2, qdss_gpio8, NA, NA, NA,
NA, NA, NA),
- [22] = PINGROUP(22, WEST, cci_timer1, gcc_gp3, qdss_gpio, NA, NA, NA,
+ [22] = PINGROUP(22, cci_timer1, gcc_gp3, qdss_gpio, NA, NA, NA,
NA, NA, NA),
- [23] = PINGROUP(23, WEST, cci_timer2, qdss_gpio9, NA, NA, NA, NA, NA,
+ [23] = PINGROUP(23, cci_timer2, qdss_gpio9, NA, NA, NA, NA, NA,
NA, NA),
- [24] = PINGROUP(24, WEST, cci_timer3, cci_async, qdss_gpio10, NA, NA,
+ [24] = PINGROUP(24, cci_timer3, cci_async, qdss_gpio10, NA, NA,
NA, NA, NA, NA),
- [25] = PINGROUP(25, WEST, cci_timer4, cci_async, qdss_gpio11, NA, NA,
+ [25] = PINGROUP(25, cci_timer4, cci_async, qdss_gpio11, NA, NA,
NA, NA, NA, NA),
- [26] = PINGROUP(26, WEST, cci_async, qdss_gpio12, JITTER_BIST, NA, NA,
+ [26] = PINGROUP(26, cci_async, qdss_gpio12, JITTER_BIST, NA, NA,
NA, NA, NA, NA),
- [27] = PINGROUP(27, WEST, qup2, qdss_gpio13, PLL_BIST, NA, NA, NA, NA,
+ [27] = PINGROUP(27, qup2, qdss_gpio13, PLL_BIST, NA, NA, NA, NA,
NA, NA),
- [28] = PINGROUP(28, WEST, qup2, qdss_gpio14, AGERA_PLL, NA, NA, NA, NA,
+ [28] = PINGROUP(28, qup2, qdss_gpio14, AGERA_PLL, NA, NA, NA, NA,
NA, NA),
- [29] = PINGROUP(29, WEST, qup2, NA, phase_flag1, qdss_gpio15,
+ [29] = PINGROUP(29, qup2, NA, phase_flag1, qdss_gpio15,
atest_tsens, NA, NA, NA, NA),
- [30] = PINGROUP(30, WEST, qup2, phase_flag2, qdss_gpio, NA, NA, NA, NA,
+ [30] = PINGROUP(30, qup2, phase_flag2, qdss_gpio, NA, NA, NA, NA,
NA, NA),
- [31] = PINGROUP(31, WEST, qup11, qup14, NA, NA, NA, NA, NA, NA, NA),
- [32] = PINGROUP(32, WEST, qup11, qup14, NA, NA, NA, NA, NA, NA, NA),
- [33] = PINGROUP(33, WEST, qup11, qup14, NA, NA, NA, NA, NA, NA, NA),
- [34] = PINGROUP(34, WEST, qup11, qup14, NA, NA, NA, NA, NA, NA, NA),
- [35] = PINGROUP(35, NORTH, pci_e0, QUP_L4, JITTER_BIST, NA, NA, NA, NA,
+ [31] = PINGROUP(31, qup11, qup14, NA, NA, NA, NA, NA, NA, NA),
+ [32] = PINGROUP(32, qup11, qup14, NA, NA, NA, NA, NA, NA, NA),
+ [33] = PINGROUP(33, qup11, qup14, NA, NA, NA, NA, NA, NA, NA),
+ [34] = PINGROUP(34, qup11, qup14, NA, NA, NA, NA, NA, NA, NA),
+ [35] = PINGROUP(35, pci_e0, QUP_L4, JITTER_BIST, NA, NA, NA, NA,
NA, NA),
- [36] = PINGROUP(36, NORTH, pci_e0, QUP_L5, PLL_BIST, NA, NA, NA, NA,
+ [36] = PINGROUP(36, pci_e0, QUP_L5, PLL_BIST, NA, NA, NA, NA,
NA, NA),
- [37] = PINGROUP(37, NORTH, QUP_L6, AGERA_PLL, NA, NA, NA, NA, NA, NA,
+ [37] = PINGROUP(37, QUP_L6, AGERA_PLL, NA, NA, NA, NA, NA, NA,
NA),
- [38] = PINGROUP(38, NORTH, usb_phy, NA, NA, NA, NA, NA, NA, NA, NA),
- [39] = PINGROUP(39, NORTH, lpass_slimbus, NA, NA, NA, NA, NA, NA, NA,
+ [38] = PINGROUP(38, usb_phy, NA, NA, NA, NA, NA, NA, NA, NA),
+ [39] = PINGROUP(39, lpass_slimbus, NA, NA, NA, NA, NA, NA, NA,
NA),
- [40] = PINGROUP(40, NORTH, sd_write, tsif1_error, NA, NA, NA, NA, NA,
+ [40] = PINGROUP(40, sd_write, tsif1_error, NA, NA, NA, NA, NA,
NA, NA),
- [41] = PINGROUP(41, SOUTH, qup3, NA, qdss_gpio6, NA, NA, NA, NA, NA,
+ [41] = PINGROUP(41, qup3, NA, qdss_gpio6, NA, NA, NA, NA, NA,
NA),
- [42] = PINGROUP(42, SOUTH, qup3, NA, qdss_gpio7, NA, NA, NA, NA, NA,
+ [42] = PINGROUP(42, qup3, NA, qdss_gpio7, NA, NA, NA, NA, NA,
NA),
- [43] = PINGROUP(43, SOUTH, qup3, NA, qdss_gpio14, NA, NA, NA, NA, NA,
+ [43] = PINGROUP(43, qup3, NA, qdss_gpio14, NA, NA, NA, NA, NA,
NA),
- [44] = PINGROUP(44, SOUTH, qup3, NA, qdss_gpio15, NA, NA, NA, NA, NA,
+ [44] = PINGROUP(44, qup3, NA, qdss_gpio15, NA, NA, NA, NA, NA,
NA),
- [45] = PINGROUP(45, SOUTH, qup6, NA, NA, NA, NA, NA, NA, NA, NA),
- [46] = PINGROUP(46, SOUTH, qup6, NA, NA, NA, NA, NA, NA, NA, NA),
- [47] = PINGROUP(47, SOUTH, qup6, NA, NA, NA, NA, NA, NA, NA, NA),
- [48] = PINGROUP(48, SOUTH, qup6, NA, NA, NA, NA, NA, NA, NA, NA),
- [49] = PINGROUP(49, NORTH, qup12, NA, NA, NA, NA, NA, NA, NA, NA),
- [50] = PINGROUP(50, NORTH, qup12, NA, NA, NA, NA, NA, NA, NA, NA),
- [51] = PINGROUP(51, NORTH, qup12, qdss_cti, NA, NA, NA, NA, NA, NA, NA),
- [52] = PINGROUP(52, NORTH, qup12, phase_flag16, qdss_cti, NA, NA, NA,
+ [45] = PINGROUP(45, qup6, NA, NA, NA, NA, NA, NA, NA, NA),
+ [46] = PINGROUP(46, qup6, NA, NA, NA, NA, NA, NA, NA, NA),
+ [47] = PINGROUP(47, qup6, NA, NA, NA, NA, NA, NA, NA, NA),
+ [48] = PINGROUP(48, qup6, NA, NA, NA, NA, NA, NA, NA, NA),
+ [49] = PINGROUP(49, qup12, NA, NA, NA, NA, NA, NA, NA, NA),
+ [50] = PINGROUP(50, qup12, NA, NA, NA, NA, NA, NA, NA, NA),
+ [51] = PINGROUP(51, qup12, qdss_cti, NA, NA, NA, NA, NA, NA, NA),
+ [52] = PINGROUP(52, qup12, phase_flag16, qdss_cti, NA, NA, NA,
NA, NA, NA),
- [53] = PINGROUP(53, NORTH, qup10, phase_flag11, NA, NA, NA, NA, NA, NA,
+ [53] = PINGROUP(53, qup10, phase_flag11, NA, NA, NA, NA, NA, NA,
NA),
- [54] = PINGROUP(54, NORTH, qup10, GP_PDM0, phase_flag12, NA,
+ [54] = PINGROUP(54, qup10, GP_PDM0, phase_flag12, NA,
wlan1_adc1, atest_usb13, ddr_pxi1, NA, NA),
- [55] = PINGROUP(55, NORTH, qup10, phase_flag13, NA, wlan1_adc0,
+ [55] = PINGROUP(55, qup10, phase_flag13, NA, wlan1_adc0,
atest_usb12, ddr_pxi1, NA, NA, NA),
- [56] = PINGROUP(56, NORTH, qup10, phase_flag17, NA, NA, NA, NA, NA, NA,
+ [56] = PINGROUP(56, qup10, phase_flag17, NA, NA, NA, NA, NA, NA,
NA),
- [57] = PINGROUP(57, NORTH, qua_mi2s, gcc_gp1, phase_flag18, NA, NA, NA,
+ [57] = PINGROUP(57, qua_mi2s, gcc_gp1, phase_flag18, NA, NA, NA,
NA, NA, NA),
- [58] = PINGROUP(58, DUMMY, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [59] = PINGROUP(59, DUMMY, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [60] = PINGROUP(60, DUMMY, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [61] = PINGROUP(61, DUMMY, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [62] = PINGROUP(62, DUMMY, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [63] = PINGROUP(63, DUMMY, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [64] = PINGROUP(64, DUMMY, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [65] = PINGROUP(65, NORTH, pri_mi2s, qup8, wsa_clk, NA, NA, NA, NA, NA,
+ [58] = PINGROUP(58, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [59] = PINGROUP(59, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [60] = PINGROUP(60, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [61] = PINGROUP(61, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [62] = PINGROUP(62, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [63] = PINGROUP(63, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [64] = PINGROUP(64, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [65] = PINGROUP(65, pri_mi2s, qup8, wsa_clk, NA, NA, NA, NA, NA,
NA),
- [66] = PINGROUP(66, NORTH, pri_mi2s_ws, qup8, wsa_data, GP_PDM1, NA,
+ [66] = PINGROUP(66, pri_mi2s_ws, qup8, wsa_data, GP_PDM1, NA,
NA, NA, NA, NA),
- [67] = PINGROUP(67, NORTH, pri_mi2s, qup8, NA, atest_usb2, NA, NA, NA,
+ [67] = PINGROUP(67, pri_mi2s, qup8, NA, atest_usb2, NA, NA, NA,
NA, NA),
- [68] = PINGROUP(68, NORTH, pri_mi2s, qup8, NA, atest_usb23, NA, NA, NA,
+ [68] = PINGROUP(68, pri_mi2s, qup8, NA, atest_usb23, NA, NA, NA,
NA, NA),
- [69] = PINGROUP(69, DUMMY, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [70] = PINGROUP(70, DUMMY, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [71] = PINGROUP(71, DUMMY, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [72] = PINGROUP(72, DUMMY, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [73] = PINGROUP(73, DUMMY, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [74] = PINGROUP(74, DUMMY, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [75] = PINGROUP(75, NORTH, ter_mi2s, phase_flag8, qdss_gpio8,
+ [69] = PINGROUP(69, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [70] = PINGROUP(70, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [71] = PINGROUP(71, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [72] = PINGROUP(72, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [73] = PINGROUP(73, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [74] = PINGROUP(74, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [75] = PINGROUP(75, ter_mi2s, phase_flag8, qdss_gpio8,
atest_usb22, QUP_L4, NA, NA, NA, NA),
- [76] = PINGROUP(76, NORTH, ter_mi2s, phase_flag9, qdss_gpio9,
+ [76] = PINGROUP(76, ter_mi2s, phase_flag9, qdss_gpio9,
atest_usb21, QUP_L5, NA, NA, NA, NA),
- [77] = PINGROUP(77, NORTH, ter_mi2s, phase_flag4, qdss_gpio10,
+ [77] = PINGROUP(77, ter_mi2s, phase_flag4, qdss_gpio10,
atest_usb20, QUP_L6, NA, NA, NA, NA),
- [78] = PINGROUP(78, NORTH, ter_mi2s, gcc_gp1, NA, NA, NA, NA, NA, NA,
+ [78] = PINGROUP(78, ter_mi2s, gcc_gp1, NA, NA, NA, NA, NA, NA,
NA),
- [79] = PINGROUP(79, NORTH, sec_mi2s, GP_PDM2, NA, qdss_gpio11, NA, NA,
+ [79] = PINGROUP(79, sec_mi2s, GP_PDM2, NA, qdss_gpio11, NA, NA,
NA, NA, NA),
- [80] = PINGROUP(80, NORTH, sec_mi2s, NA, qdss_gpio12, NA, NA, NA, NA,
+ [80] = PINGROUP(80, sec_mi2s, NA, qdss_gpio12, NA, NA, NA, NA,
NA, NA),
- [81] = PINGROUP(81, NORTH, sec_mi2s, qup15, NA, NA, NA, NA, NA, NA, NA),
- [82] = PINGROUP(82, NORTH, sec_mi2s, qup15, NA, NA, NA, NA, NA, NA, NA),
- [83] = PINGROUP(83, NORTH, sec_mi2s, qup15, NA, NA, NA, NA, NA, NA, NA),
- [84] = PINGROUP(84, NORTH, qup15, NA, NA, NA, NA, NA, NA, NA, NA),
- [85] = PINGROUP(85, SOUTH, qup5, NA, NA, NA, NA, NA, NA, NA, NA),
- [86] = PINGROUP(86, SOUTH, qup5, copy_gp, NA, NA, NA, NA, NA, NA, NA),
- [87] = PINGROUP(87, SOUTH, qup5, NA, NA, NA, NA, NA, NA, NA, NA),
- [88] = PINGROUP(88, SOUTH, qup5, NA, NA, NA, NA, NA, NA, NA, NA),
- [89] = PINGROUP(89, SOUTH, tsif1_clk, qup4, tgu_ch3, phase_flag10, NA,
+ [81] = PINGROUP(81, sec_mi2s, qup15, NA, NA, NA, NA, NA, NA, NA),
+ [82] = PINGROUP(82, sec_mi2s, qup15, NA, NA, NA, NA, NA, NA, NA),
+ [83] = PINGROUP(83, sec_mi2s, qup15, NA, NA, NA, NA, NA, NA, NA),
+ [84] = PINGROUP(84, qup15, NA, NA, NA, NA, NA, NA, NA, NA),
+ [85] = PINGROUP(85, qup5, NA, NA, NA, NA, NA, NA, NA, NA),
+ [86] = PINGROUP(86, qup5, copy_gp, NA, NA, NA, NA, NA, NA, NA),
+ [87] = PINGROUP(87, qup5, NA, NA, NA, NA, NA, NA, NA, NA),
+ [88] = PINGROUP(88, qup5, NA, NA, NA, NA, NA, NA, NA, NA),
+ [89] = PINGROUP(89, tsif1_clk, qup4, tgu_ch3, phase_flag10, NA,
NA, NA, NA, NA),
- [90] = PINGROUP(90, SOUTH, tsif1_en, mdp_vsync0, qup4, mdp_vsync1,
+ [90] = PINGROUP(90, tsif1_en, mdp_vsync0, qup4, mdp_vsync1,
mdp_vsync2, mdp_vsync3, tgu_ch0, phase_flag0, qdss_cti),
- [91] = PINGROUP(91, SOUTH, tsif1_data, sdc4_cmd, qup4, tgu_ch1, NA,
+ [91] = PINGROUP(91, tsif1_data, sdc4_cmd, qup4, tgu_ch1, NA,
qdss_cti, NA, NA, NA),
- [92] = PINGROUP(92, SOUTH, tsif2_error, sdc43, qup4, vfr_1, tgu_ch2,
+ [92] = PINGROUP(92, tsif2_error, sdc43, qup4, vfr_1, tgu_ch2,
NA, NA, NA, NA),
- [93] = PINGROUP(93, SOUTH, tsif2_clk, sdc4_clk, qup7, NA, qdss_gpio13,
+ [93] = PINGROUP(93, tsif2_clk, sdc4_clk, qup7, NA, qdss_gpio13,
NA, NA, NA, NA),
- [94] = PINGROUP(94, SOUTH, tsif2_en, sdc42, qup7, NA, NA, NA, NA, NA,
+ [94] = PINGROUP(94, tsif2_en, sdc42, qup7, NA, NA, NA, NA, NA,
NA),
- [95] = PINGROUP(95, SOUTH, tsif2_data, sdc41, qup7, GP_PDM0, NA, NA,
+ [95] = PINGROUP(95, tsif2_data, sdc41, qup7, GP_PDM0, NA, NA,
NA, NA, NA),
- [96] = PINGROUP(96, SOUTH, tsif2_sync, sdc40, qup7, phase_flag3, NA,
+ [96] = PINGROUP(96, tsif2_sync, sdc40, qup7, phase_flag3, NA,
NA, NA, NA, NA),
- [97] = PINGROUP(97, WEST, NA, NA, mdp_vsync, ldo_en, NA, NA, NA, NA,
+ [97] = PINGROUP(97, NA, NA, mdp_vsync, ldo_en, NA, NA, NA, NA,
NA),
- [98] = PINGROUP(98, WEST, NA, mdp_vsync, ldo_update, NA, NA, NA, NA,
+ [98] = PINGROUP(98, NA, mdp_vsync, ldo_update, NA, NA, NA, NA,
NA, NA),
- [99] = PINGROUP(99, NORTH, phase_flag14, prng_rosc, NA, NA, NA, NA, NA,
+ [99] = PINGROUP(99, phase_flag14, prng_rosc, NA, NA, NA, NA, NA,
NA, NA),
- [100] = PINGROUP(100, WEST, phase_flag15, NA, NA, NA, NA, NA, NA, NA,
+ [100] = PINGROUP(100, phase_flag15, NA, NA, NA, NA, NA, NA, NA,
NA),
- [101] = PINGROUP(101, WEST, NA, phase_flag5, NA, NA, NA, NA, NA, NA,
+ [101] = PINGROUP(101, NA, phase_flag5, NA, NA, NA, NA, NA, NA,
NA),
- [102] = PINGROUP(102, WEST, pci_e1, prng_rosc, NA, NA, NA, NA, NA, NA,
+ [102] = PINGROUP(102, pci_e1, prng_rosc, NA, NA, NA, NA, NA, NA,
NA),
- [103] = PINGROUP(103, WEST, pci_e1, COPY_PHASE, NA, NA, NA, NA, NA, NA,
+ [103] = PINGROUP(103, pci_e1, COPY_PHASE, NA, NA, NA, NA, NA, NA,
NA),
- [104] = PINGROUP(104, DUMMY, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [105] = PINGROUP(105, NORTH, uim2_data, qup13, qup_l4, NA, NA, NA, NA,
+ [104] = PINGROUP(104, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [105] = PINGROUP(105, uim2_data, qup13, qup_l4, NA, NA, NA, NA,
NA, NA),
- [106] = PINGROUP(106, NORTH, uim2_clk, qup13, qup_l5, NA, NA, NA, NA,
+ [106] = PINGROUP(106, uim2_clk, qup13, qup_l5, NA, NA, NA, NA,
NA, NA),
- [107] = PINGROUP(107, NORTH, uim2_reset, qup13, qup_l6, NA, NA, NA, NA,
+ [107] = PINGROUP(107, uim2_reset, qup13, qup_l6, NA, NA, NA, NA,
NA, NA),
- [108] = PINGROUP(108, NORTH, uim2_present, qup13, NA, NA, NA, NA, NA,
+ [108] = PINGROUP(108, uim2_present, qup13, NA, NA, NA, NA, NA,
NA, NA),
- [109] = PINGROUP(109, NORTH, uim1_data, NA, NA, NA, NA, NA, NA, NA, NA),
- [110] = PINGROUP(110, NORTH, uim1_clk, NA, NA, NA, NA, NA, NA, NA, NA),
- [111] = PINGROUP(111, NORTH, uim1_reset, NA, NA, NA, NA, NA, NA, NA,
+ [109] = PINGROUP(109, uim1_data, NA, NA, NA, NA, NA, NA, NA, NA),
+ [110] = PINGROUP(110, uim1_clk, NA, NA, NA, NA, NA, NA, NA, NA),
+ [111] = PINGROUP(111, uim1_reset, NA, NA, NA, NA, NA, NA, NA,
NA),
- [112] = PINGROUP(112, NORTH, uim1_present, NA, NA, NA, NA, NA, NA, NA,
+ [112] = PINGROUP(112, uim1_present, NA, NA, NA, NA, NA, NA, NA,
NA),
- [113] = PINGROUP(113, NORTH, uim_batt, edp_hot, NA, NA, NA, NA, NA, NA,
+ [113] = PINGROUP(113, uim_batt, edp_hot, NA, NA, NA, NA, NA, NA,
NA),
- [114] = PINGROUP(114, WEST, NA, NAV_PPS, NAV_PPS, GPS_TX, NA, NA, NA,
+ [114] = PINGROUP(114, NA, NAV_PPS, NAV_PPS, GPS_TX, NA, NA, NA,
NA, NA),
- [115] = PINGROUP(115, WEST, NA, NAV_PPS, NAV_PPS, GPS_TX, NA, NA, NA,
+ [115] = PINGROUP(115, NA, NAV_PPS, NAV_PPS, GPS_TX, NA, NA, NA,
NA, NA),
- [116] = PINGROUP(116, SOUTH, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [117] = PINGROUP(117, NORTH, NA, qdss_gpio0, atest_char, NA, NA, NA,
+ [116] = PINGROUP(116, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [117] = PINGROUP(117, NA, qdss_gpio0, atest_char, NA, NA, NA,
NA, NA, NA),
- [118] = PINGROUP(118, NORTH, adsp_ext, NA, qdss_gpio1, atest_char3, NA,
+ [118] = PINGROUP(118, adsp_ext, NA, qdss_gpio1, atest_char3, NA,
NA, NA, NA, NA),
- [119] = PINGROUP(119, NORTH, NA, qdss_gpio2, atest_char2, NA, NA, NA,
+ [119] = PINGROUP(119, NA, qdss_gpio2, atest_char2, NA, NA, NA,
NA, NA, NA),
- [120] = PINGROUP(120, NORTH, NA, qdss_gpio3, atest_char1, NA, NA, NA,
+ [120] = PINGROUP(120, NA, qdss_gpio3, atest_char1, NA, NA, NA,
NA, NA, NA),
- [121] = PINGROUP(121, NORTH, NA, qdss_gpio4, atest_char0, NA, NA, NA,
+ [121] = PINGROUP(121, NA, qdss_gpio4, atest_char0, NA, NA, NA,
NA, NA, NA),
- [122] = PINGROUP(122, NORTH, NA, qdss_gpio5, NA, NA, NA, NA, NA, NA,
+ [122] = PINGROUP(122, NA, qdss_gpio5, NA, NA, NA, NA, NA, NA,
NA),
- [123] = PINGROUP(123, NORTH, qup_l4, NA, qdss_gpio, NA, NA, NA, NA, NA,
+ [123] = PINGROUP(123, qup_l4, NA, qdss_gpio, NA, NA, NA, NA, NA,
NA),
- [124] = PINGROUP(124, NORTH, qup_l5, NA, qdss_gpio, NA, NA, NA, NA, NA,
+ [124] = PINGROUP(124, qup_l5, NA, qdss_gpio, NA, NA, NA, NA, NA,
NA),
- [125] = PINGROUP(125, NORTH, qup_l6, NA, NA, NA, NA, NA, NA, NA, NA),
- [126] = PINGROUP(126, NORTH, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [127] = PINGROUP(127, WEST, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [128] = PINGROUP(128, WEST, NAV_PPS, NAV_PPS, GPS_TX, NA, NA, NA, NA,
+ [125] = PINGROUP(125, qup_l6, NA, NA, NA, NA, NA, NA, NA, NA),
+ [126] = PINGROUP(126, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [127] = PINGROUP(127, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [128] = PINGROUP(128, NAV_PPS, NAV_PPS, GPS_TX, NA, NA, NA, NA,
NA, NA),
- [129] = PINGROUP(129, WEST, NAV_PPS, NAV_PPS, GPS_TX, NA, NA, NA, NA,
+ [129] = PINGROUP(129, NAV_PPS, NAV_PPS, GPS_TX, NA, NA, NA, NA,
NA, NA),
- [130] = PINGROUP(130, WEST, qlink_request, NA, NA, NA, NA, NA, NA, NA,
+ [130] = PINGROUP(130, qlink_request, NA, NA, NA, NA, NA, NA, NA,
NA),
- [131] = PINGROUP(131, WEST, qlink_enable, NA, NA, NA, NA, NA, NA, NA,
+ [131] = PINGROUP(131, qlink_enable, NA, NA, NA, NA, NA, NA, NA,
NA),
- [132] = PINGROUP(132, WEST, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [133] = PINGROUP(133, NORTH, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [134] = PINGROUP(134, NORTH, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [135] = PINGROUP(135, WEST, NA, pa_indicator, NA, NA, NA, NA, NA, NA,
+ [132] = PINGROUP(132, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [133] = PINGROUP(133, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [134] = PINGROUP(134, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [135] = PINGROUP(135, NA, pa_indicator, NA, NA, NA, NA, NA, NA,
NA),
- [136] = PINGROUP(136, WEST, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [137] = PINGROUP(137, WEST, NA, NA, phase_flag26, NA, NA, NA, NA, NA,
+ [136] = PINGROUP(136, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [137] = PINGROUP(137, NA, NA, phase_flag26, NA, NA, NA, NA, NA,
NA),
- [138] = PINGROUP(138, WEST, NA, NA, phase_flag27, NA, NA, NA, NA, NA,
+ [138] = PINGROUP(138, NA, NA, phase_flag27, NA, NA, NA, NA, NA,
NA),
- [139] = PINGROUP(139, WEST, NA, phase_flag28, NA, NA, NA, NA, NA, NA,
+ [139] = PINGROUP(139, NA, phase_flag28, NA, NA, NA, NA, NA, NA,
NA),
- [140] = PINGROUP(140, WEST, NA, NA, phase_flag6, NA, NA, NA, NA, NA,
+ [140] = PINGROUP(140, NA, NA, phase_flag6, NA, NA, NA, NA, NA,
NA),
- [141] = PINGROUP(141, WEST, NA, phase_flag29, NA, NA, NA, NA, NA, NA,
+ [141] = PINGROUP(141, NA, phase_flag29, NA, NA, NA, NA, NA, NA,
NA),
- [142] = PINGROUP(142, WEST, NA, phase_flag30, NA, NA, NA, NA, NA, NA,
+ [142] = PINGROUP(142, NA, phase_flag30, NA, NA, NA, NA, NA, NA,
NA),
- [143] = PINGROUP(143, WEST, NA, NAV_PPS, NAV_PPS, GPS_TX, phase_flag31,
+ [143] = PINGROUP(143, NA, NAV_PPS, NAV_PPS, GPS_TX, phase_flag31,
NA, NA, NA, NA),
- [144] = PINGROUP(144, SOUTH, mss_lte, NA, NA, NA, NA, NA, NA, NA, NA),
- [145] = PINGROUP(145, SOUTH, mss_lte, GPS_TX, NA, NA, NA, NA, NA, NA,
+ [144] = PINGROUP(144, mss_lte, NA, NA, NA, NA, NA, NA, NA, NA),
+ [145] = PINGROUP(145, mss_lte, GPS_TX, NA, NA, NA, NA, NA, NA,
NA),
- [146] = PINGROUP(146, WEST, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [147] = PINGROUP(147, WEST, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [148] = PINGROUP(148, WEST, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [149] = PINGROUP(149, WEST, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [146] = PINGROUP(146, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [147] = PINGROUP(147, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [148] = PINGROUP(148, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [149] = PINGROUP(149, NA, NA, NA, NA, NA, NA, NA, NA, NA),
[150] = SDC_QDSD_PINGROUP(sdc1_rclk, 0x599000, 15, 0),
[151] = SDC_QDSD_PINGROUP(sdc1_clk, 0x599000, 13, 6),
[152] = SDC_QDSD_PINGROUP(sdc1_cmd, 0x599000, 11, 3),
@@ -1585,6 +1585,74 @@
[157] = UFS_RESET(ufs_reset, 0x99f000),
};
+static const struct msm_dir_conn sdm670_dir_conn[] = {
+ {1, 510},
+ {3, 511},
+ {5, 512},
+ {10, 513},
+ {11, 514},
+ {20, 515},
+ {22, 516},
+ {24, 517},
+ {26, 518},
+ {30, 519},
+ {31, 639},
+ {32, 521},
+ {34, 522},
+ {36, 523},
+ {37, 524},
+ {38, 525},
+ {39, 526},
+ {40, 527},
+ {41, 637},
+ {43, 529},
+ {44, 530},
+ {46, 531},
+ {48, 532},
+ {49, 640},
+ {52, 534},
+ {53, 535},
+ {54, 536},
+ {56, 537},
+ {57, 538},
+ {66, 546},
+ {68, 547},
+ {77, 550},
+ {78, 551},
+ {79, 552},
+ {80, 553},
+ {84, 554},
+ {85, 555},
+ {86, 556},
+ {88, 557},
+ {89, 638},
+ {91, 559},
+ {92, 560},
+ {95, 561},
+ {96, 562},
+ {97, 563},
+ {101, 564},
+ {103, 565},
+ {115, 570},
+ {116, 571},
+ {117, 572},
+ {118, 573},
+ {119, 609},
+ {120, 610},
+ {121, 611},
+ {122, 612},
+ {123, 613},
+ {124, 614},
+ {125, 615},
+ {127, 617},
+ {128, 618},
+ {129, 619},
+ {130, 620},
+ {132, 621},
+ {133, 622},
+ {145, 623},
+};
+
static const struct msm_pinctrl_soc_data sdm670_pinctrl = {
.pins = sdm670_pins,
.npins = ARRAY_SIZE(sdm670_pins),
@@ -1593,6 +1661,12 @@
.groups = sdm670_groups,
.ngroups = ARRAY_SIZE(sdm670_groups),
.ngpios = 150,
+ .dir_conn = sdm670_dir_conn,
+ .n_dir_conns = ARRAY_SIZE(sdm670_dir_conn),
+ .tile_offsets = sdm670_tile_offsets,
+ .n_tile_offsets = ARRAY_SIZE(sdm670_tile_offsets),
+ .pin_base = sdm670_pin_base,
+ .reg_size = REG_SIZE,
};
static int sdm670_pinctrl_probe(struct platform_device *pdev)
diff --git a/drivers/pinctrl/qcom/pinctrl-sdm845.c b/drivers/pinctrl/qcom/pinctrl-sdm845.c
index 7d125eb..8faabb0 100644
--- a/drivers/pinctrl/qcom/pinctrl-sdm845.c
+++ b/drivers/pinctrl/qcom/pinctrl-sdm845.c
@@ -25,10 +25,8 @@
.ngroups = ARRAY_SIZE(fname##_groups), \
}
-#define NORTH 0x00500000
-#define SOUTH 0x00900000
#define REG_SIZE 0x1000
-#define PINGROUP(id, base, f1, f2, f3, f4, f5, f6, f7, f8, f9) \
+#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9) \
{ \
.name = "gpio" #id, \
.pins = gpio##id##_pins, \
@@ -46,11 +44,11 @@
msm_mux_##f9 \
}, \
.nfuncs = 10, \
- .ctl_reg = base + REG_SIZE * id, \
- .io_reg = base + 0x4 + REG_SIZE * id, \
- .intr_cfg_reg = base + 0x8 + REG_SIZE * id, \
- .intr_status_reg = base + 0xc + REG_SIZE * id, \
- .intr_target_reg = base + 0x8 + REG_SIZE * id, \
+ .ctl_reg = REG_SIZE * id, \
+ .io_reg = 0x4 + REG_SIZE * id, \
+ .intr_cfg_reg = 0x8 + REG_SIZE * id, \
+ .intr_status_reg = 0xc + REG_SIZE * id, \
+ .intr_target_reg = 0x8 + REG_SIZE * id, \
.mux_bit = 2, \
.pull_bit = 0, \
.drv_bit = 6, \
@@ -116,6 +114,10 @@
.intr_detection_bit = -1, \
.intr_detection_width = -1, \
}
+
+static const u32 sdm845_tile_offsets[] = {0x500000, 0x900000, 0x100000};
+static u32 sdm845_pin_base[150];
+
static const struct pinctrl_pin_desc sdm845_pins[] = {
PINCTRL_PIN(0, "GPIO_0"),
PINCTRL_PIN(1, "GPIO_1"),
@@ -432,306 +434,99 @@
static const unsigned int ufs_reset_pins[] = { 153 };
enum sdm845_functions {
- msm_mux_gpio,
- msm_mux_qup0,
- msm_mux_reserved0,
- msm_mux_reserved1,
- msm_mux_reserved2,
- msm_mux_reserved3,
- msm_mux_qup9,
- msm_mux_qdss_cti,
- msm_mux_reserved4,
- msm_mux_reserved5,
- msm_mux_ddr_pxi0,
- msm_mux_reserved6,
- msm_mux_ddr_bist,
- msm_mux_atest_tsens2,
- msm_mux_vsense_trigger,
- msm_mux_atest_usb1,
- msm_mux_reserved7,
- msm_mux_qup_l4,
- msm_mux_wlan1_adc1,
- msm_mux_atest_usb13,
- msm_mux_ddr_pxi1,
- msm_mux_reserved8,
- msm_mux_qup_l5,
- msm_mux_wlan1_adc0,
- msm_mux_atest_usb12,
- msm_mux_reserved9,
- msm_mux_mdp_vsync,
- msm_mux_qup_l6,
- msm_mux_wlan2_adc1,
- msm_mux_atest_usb11,
- msm_mux_ddr_pxi2,
- msm_mux_reserved10,
- msm_mux_edp_lcd,
- msm_mux_dbg_out,
- msm_mux_wlan2_adc0,
- msm_mux_atest_usb10,
- msm_mux_reserved11,
- msm_mux_m_voc,
- msm_mux_tsif1_sync,
msm_mux_ddr_pxi3,
- msm_mux_reserved12,
msm_mux_cam_mclk,
msm_mux_pll_bypassnl,
msm_mux_qdss_gpio0,
- msm_mux_reserved13,
msm_mux_pll_reset,
msm_mux_qdss_gpio1,
- msm_mux_reserved14,
msm_mux_qdss_gpio2,
- msm_mux_reserved15,
msm_mux_qdss_gpio3,
- msm_mux_reserved16,
msm_mux_cci_i2c,
msm_mux_qup1,
msm_mux_qdss_gpio4,
- msm_mux_reserved17,
msm_mux_qdss_gpio5,
- msm_mux_reserved18,
msm_mux_qdss_gpio6,
- msm_mux_reserved19,
msm_mux_qdss_gpio7,
- msm_mux_reserved20,
msm_mux_cci_timer0,
msm_mux_gcc_gp2,
msm_mux_qdss_gpio8,
- msm_mux_reserved21,
msm_mux_cci_timer1,
msm_mux_gcc_gp3,
msm_mux_qdss_gpio,
- msm_mux_reserved22,
msm_mux_cci_timer2,
msm_mux_qdss_gpio9,
- msm_mux_reserved23,
msm_mux_cci_timer3,
msm_mux_cci_async,
msm_mux_qdss_gpio10,
- msm_mux_reserved24,
msm_mux_cci_timer4,
msm_mux_qdss_gpio11,
- msm_mux_reserved25,
msm_mux_qdss_gpio12,
- msm_mux_reserved26,
msm_mux_qup2,
msm_mux_qdss_gpio13,
- msm_mux_reserved27,
msm_mux_qdss_gpio14,
- msm_mux_reserved28,
msm_mux_phase_flag1,
msm_mux_qdss_gpio15,
- msm_mux_reserved29,
msm_mux_phase_flag2,
- msm_mux_reserved30,
msm_mux_qup11,
msm_mux_qup14,
- msm_mux_reserved96,
- msm_mux_ldo_en,
- msm_mux_reserved97,
- msm_mux_ldo_update,
- msm_mux_reserved98,
- msm_mux_phase_flag14,
- msm_mux_reserved99,
- msm_mux_phase_flag15,
- msm_mux_reserved100,
- msm_mux_reserved101,
- msm_mux_pci_e1,
- msm_mux_prng_rosc,
- msm_mux_reserved102,
- msm_mux_phase_flag5,
- msm_mux_reserved103,
- msm_mux_reserved104,
- msm_mux_uim2_data,
- msm_mux_qup13,
- msm_mux_reserved105,
- msm_mux_uim2_clk,
- msm_mux_reserved106,
- msm_mux_uim2_reset,
- msm_mux_reserved107,
- msm_mux_uim2_present,
- msm_mux_reserved108,
- msm_mux_uim1_data,
- msm_mux_reserved109,
- msm_mux_uim1_clk,
- msm_mux_reserved110,
- msm_mux_uim1_reset,
- msm_mux_reserved111,
- msm_mux_uim1_present,
- msm_mux_reserved112,
- msm_mux_uim_batt,
- msm_mux_edp_hot,
- msm_mux_reserved113,
- msm_mux_nav_pps,
- msm_mux_reserved114,
- msm_mux_reserved115,
- msm_mux_reserved116,
- msm_mux_atest_char,
- msm_mux_reserved117,
- msm_mux_adsp_ext,
- msm_mux_atest_char3,
- msm_mux_reserved118,
- msm_mux_atest_char2,
- msm_mux_reserved119,
- msm_mux_atest_char1,
- msm_mux_reserved120,
- msm_mux_atest_char0,
- msm_mux_reserved121,
- msm_mux_reserved122,
- msm_mux_reserved123,
- msm_mux_reserved124,
- msm_mux_reserved125,
- msm_mux_reserved126,
- msm_mux_reserved127,
- msm_mux_reserved128,
- msm_mux_reserved129,
- msm_mux_qlink_request,
- msm_mux_reserved130,
- msm_mux_qlink_enable,
- msm_mux_reserved131,
- msm_mux_reserved132,
- msm_mux_reserved133,
- msm_mux_reserved134,
- msm_mux_pa_indicator,
- msm_mux_reserved135,
- msm_mux_reserved136,
- msm_mux_phase_flag26,
- msm_mux_reserved137,
- msm_mux_phase_flag27,
- msm_mux_reserved138,
- msm_mux_phase_flag28,
- msm_mux_reserved139,
- msm_mux_phase_flag6,
- msm_mux_reserved140,
- msm_mux_phase_flag29,
- msm_mux_reserved141,
- msm_mux_phase_flag30,
- msm_mux_reserved142,
- msm_mux_phase_flag31,
- msm_mux_reserved143,
- msm_mux_mss_lte,
- msm_mux_reserved144,
- msm_mux_reserved145,
- msm_mux_reserved146,
- msm_mux_reserved147,
- msm_mux_reserved148,
- msm_mux_reserved149,
- msm_mux_reserved31,
- msm_mux_reserved32,
- msm_mux_reserved33,
- msm_mux_reserved34,
msm_mux_pci_e0,
msm_mux_jitter_bist,
- msm_mux_reserved35,
msm_mux_pll_bist,
msm_mux_atest_tsens,
- msm_mux_reserved36,
msm_mux_agera_pll,
- msm_mux_reserved37,
msm_mux_usb_phy,
- msm_mux_reserved38,
msm_mux_lpass_slimbus,
- msm_mux_reserved39,
msm_mux_sd_write,
msm_mux_tsif1_error,
- msm_mux_reserved40,
msm_mux_qup3,
- msm_mux_reserved41,
- msm_mux_reserved42,
- msm_mux_reserved43,
- msm_mux_reserved44,
msm_mux_qup6,
- msm_mux_reserved45,
- msm_mux_reserved46,
- msm_mux_reserved47,
- msm_mux_reserved48,
msm_mux_qup12,
- msm_mux_reserved49,
- msm_mux_reserved50,
- msm_mux_reserved51,
msm_mux_phase_flag16,
- msm_mux_reserved52,
msm_mux_qup10,
msm_mux_phase_flag11,
- msm_mux_reserved53,
msm_mux_phase_flag12,
- msm_mux_reserved54,
msm_mux_phase_flag13,
- msm_mux_reserved55,
msm_mux_phase_flag17,
- msm_mux_reserved56,
msm_mux_qua_mi2s,
msm_mux_gcc_gp1,
msm_mux_phase_flag18,
- msm_mux_reserved57,
msm_mux_phase_flag19,
- msm_mux_reserved58,
msm_mux_phase_flag20,
- msm_mux_reserved59,
msm_mux_cri_trng0,
msm_mux_phase_flag21,
- msm_mux_reserved60,
msm_mux_cri_trng1,
msm_mux_phase_flag22,
- msm_mux_reserved61,
msm_mux_cri_trng,
msm_mux_phase_flag23,
- msm_mux_reserved62,
msm_mux_phase_flag24,
- msm_mux_reserved63,
msm_mux_pri_mi2s,
msm_mux_sp_cmu,
msm_mux_phase_flag25,
- msm_mux_reserved64,
msm_mux_qup8,
- msm_mux_reserved65,
msm_mux_pri_mi2s_ws,
- msm_mux_reserved66,
- msm_mux_reserved67,
- msm_mux_reserved68,
msm_mux_spkr_i2s,
msm_mux_audio_ref,
- msm_mux_reserved69,
- msm_mux_reserved70,
msm_mux_tsense_pwm1,
msm_mux_tsense_pwm2,
- msm_mux_reserved71,
- msm_mux_reserved72,
msm_mux_btfm_slimbus,
msm_mux_atest_usb2,
- msm_mux_reserved73,
msm_mux_ter_mi2s,
msm_mux_phase_flag7,
msm_mux_atest_usb23,
- msm_mux_reserved74,
msm_mux_phase_flag8,
msm_mux_atest_usb22,
- msm_mux_reserved75,
msm_mux_phase_flag9,
msm_mux_atest_usb21,
- msm_mux_reserved76,
msm_mux_phase_flag4,
msm_mux_atest_usb20,
- msm_mux_reserved77,
- msm_mux_reserved78,
msm_mux_sec_mi2s,
- msm_mux_reserved79,
- msm_mux_reserved80,
msm_mux_qup15,
- msm_mux_reserved81,
- msm_mux_reserved82,
- msm_mux_reserved83,
- msm_mux_reserved84,
msm_mux_qup5,
- msm_mux_reserved85,
- msm_mux_reserved86,
- msm_mux_reserved87,
- msm_mux_reserved88,
msm_mux_tsif1_clk,
msm_mux_qup4,
msm_mux_tgu_ch3,
msm_mux_phase_flag10,
- msm_mux_reserved89,
msm_mux_tsif1_en,
msm_mux_mdp_vsync0,
msm_mux_mdp_vsync1,
@@ -739,32 +534,552 @@
msm_mux_mdp_vsync3,
msm_mux_tgu_ch0,
msm_mux_phase_flag0,
- msm_mux_reserved90,
msm_mux_tsif1_data,
msm_mux_sdc4_cmd,
msm_mux_tgu_ch1,
- msm_mux_reserved91,
msm_mux_tsif2_error,
msm_mux_sdc43,
msm_mux_vfr_1,
msm_mux_tgu_ch2,
- msm_mux_reserved92,
msm_mux_tsif2_clk,
msm_mux_sdc4_clk,
msm_mux_qup7,
- msm_mux_reserved93,
msm_mux_tsif2_en,
msm_mux_sdc42,
- msm_mux_reserved94,
msm_mux_tsif2_data,
msm_mux_sdc41,
- msm_mux_reserved95,
msm_mux_tsif2_sync,
msm_mux_sdc40,
msm_mux_phase_flag3,
+ msm_mux_ldo_en,
+ msm_mux_ldo_update,
+ msm_mux_phase_flag14,
+ msm_mux_phase_flag15,
+ msm_mux_pci_e1,
+ msm_mux_prng_rosc,
+ msm_mux_phase_flag5,
+ msm_mux_uim2_data,
+ msm_mux_qup13,
+ msm_mux_uim2_clk,
+ msm_mux_uim2_reset,
+ msm_mux_uim2_present,
+ msm_mux_uim1_data,
+ msm_mux_uim1_clk,
+ msm_mux_uim1_reset,
+ msm_mux_uim1_present,
+ msm_mux_uim_batt,
+ msm_mux_edp_hot,
+ msm_mux_nav_pps,
+ msm_mux_atest_char,
+ msm_mux_adsp_ext,
+ msm_mux_atest_char3,
+ msm_mux_atest_char2,
+ msm_mux_atest_char1,
+ msm_mux_atest_char0,
+ msm_mux_qlink_request,
+ msm_mux_qlink_enable,
+ msm_mux_pa_indicator,
+ msm_mux_phase_flag26,
+ msm_mux_phase_flag27,
+ msm_mux_phase_flag28,
+ msm_mux_phase_flag6,
+ msm_mux_phase_flag29,
+ msm_mux_phase_flag30,
+ msm_mux_phase_flag31,
+ msm_mux_mss_lte,
+ msm_mux_qup0,
+ msm_mux_gpio,
+ msm_mux_qup9,
+ msm_mux_qdss_cti,
+ msm_mux_ddr_pxi0,
+ msm_mux_ddr_bist,
+ msm_mux_atest_tsens2,
+ msm_mux_vsense_trigger,
+ msm_mux_atest_usb1,
+ msm_mux_qup_l4,
+ msm_mux_wlan1_adc1,
+ msm_mux_atest_usb13,
+ msm_mux_ddr_pxi1,
+ msm_mux_qup_l5,
+ msm_mux_wlan1_adc0,
+ msm_mux_atest_usb12,
+ msm_mux_mdp_vsync,
+ msm_mux_qup_l6,
+ msm_mux_wlan2_adc1,
+ msm_mux_atest_usb11,
+ msm_mux_ddr_pxi2,
+ msm_mux_edp_lcd,
+ msm_mux_dbg_out,
+ msm_mux_wlan2_adc0,
+ msm_mux_atest_usb10,
+ msm_mux_m_voc,
+ msm_mux_tsif1_sync,
msm_mux_NA,
};
+static const char * const ddr_pxi3_groups[] = {
+ "gpio12", "gpio13",
+};
+static const char * const cam_mclk_groups[] = {
+ "gpio13", "gpio14", "gpio15", "gpio16",
+};
+static const char * const pll_bypassnl_groups[] = {
+ "gpio13",
+};
+static const char * const qdss_gpio0_groups[] = {
+ "gpio13", "gpio117",
+};
+static const char * const pll_reset_groups[] = {
+ "gpio14",
+};
+static const char * const qdss_gpio1_groups[] = {
+ "gpio14", "gpio118",
+};
+static const char * const qdss_gpio2_groups[] = {
+ "gpio15", "gpio119",
+};
+static const char * const qdss_gpio3_groups[] = {
+ "gpio16", "gpio120",
+};
+static const char * const cci_i2c_groups[] = {
+ "gpio17", "gpio18", "gpio19", "gpio20",
+};
+static const char * const qup1_groups[] = {
+ "gpio17", "gpio18", "gpio19", "gpio20",
+};
+static const char * const qdss_gpio4_groups[] = {
+ "gpio17", "gpio121",
+};
+static const char * const qdss_gpio5_groups[] = {
+ "gpio18", "gpio122",
+};
+static const char * const qdss_gpio6_groups[] = {
+ "gpio19", "gpio41",
+};
+static const char * const qdss_gpio7_groups[] = {
+ "gpio20", "gpio42",
+};
+static const char * const cci_timer0_groups[] = {
+ "gpio21",
+};
+static const char * const gcc_gp2_groups[] = {
+ "gpio21", "gpio58",
+};
+static const char * const qdss_gpio8_groups[] = {
+ "gpio21", "gpio75",
+};
+static const char * const cci_timer1_groups[] = {
+ "gpio22",
+};
+static const char * const gcc_gp3_groups[] = {
+ "gpio22", "gpio59",
+};
+static const char * const qdss_gpio_groups[] = {
+ "gpio22", "gpio30", "gpio123", "gpio124",
+};
+static const char * const cci_timer2_groups[] = {
+ "gpio23",
+};
+static const char * const qdss_gpio9_groups[] = {
+ "gpio23", "gpio76",
+};
+static const char * const cci_timer3_groups[] = {
+ "gpio24",
+};
+static const char * const cci_async_groups[] = {
+ "gpio24", "gpio25", "gpio26",
+};
+static const char * const qdss_gpio10_groups[] = {
+ "gpio24", "gpio77",
+};
+static const char * const cci_timer4_groups[] = {
+ "gpio25",
+};
+static const char * const qdss_gpio11_groups[] = {
+ "gpio25", "gpio79",
+};
+static const char * const qdss_gpio12_groups[] = {
+ "gpio26", "gpio80",
+};
+static const char * const qup2_groups[] = {
+ "gpio27", "gpio28", "gpio29", "gpio30",
+};
+static const char * const qdss_gpio13_groups[] = {
+ "gpio27", "gpio93",
+};
+static const char * const qdss_gpio14_groups[] = {
+ "gpio28", "gpio43",
+};
+static const char * const phase_flag1_groups[] = {
+ "gpio29",
+};
+static const char * const qdss_gpio15_groups[] = {
+ "gpio29", "gpio44",
+};
+static const char * const phase_flag2_groups[] = {
+ "gpio30",
+};
+static const char * const qup11_groups[] = {
+ "gpio31", "gpio32", "gpio33", "gpio34",
+};
+static const char * const qup14_groups[] = {
+ "gpio31", "gpio32", "gpio33", "gpio34",
+};
+static const char * const pci_e0_groups[] = {
+ "gpio35", "gpio36",
+};
+static const char * const jitter_bist_groups[] = {
+ "gpio35",
+};
+static const char * const pll_bist_groups[] = {
+ "gpio36",
+};
+static const char * const atest_tsens_groups[] = {
+ "gpio36",
+};
+static const char * const agera_pll_groups[] = {
+ "gpio37",
+};
+static const char * const usb_phy_groups[] = {
+ "gpio38",
+};
+static const char * const lpass_slimbus_groups[] = {
+ "gpio39", "gpio70", "gpio71", "gpio72",
+};
+static const char * const sd_write_groups[] = {
+ "gpio40",
+};
+static const char * const tsif1_error_groups[] = {
+ "gpio40",
+};
+static const char * const qup3_groups[] = {
+ "gpio41", "gpio42", "gpio43", "gpio44",
+};
+static const char * const qup6_groups[] = {
+ "gpio45", "gpio46", "gpio47", "gpio48",
+};
+static const char * const qup12_groups[] = {
+ "gpio49", "gpio50", "gpio51", "gpio52",
+};
+static const char * const phase_flag16_groups[] = {
+ "gpio52",
+};
+static const char * const qup10_groups[] = {
+ "gpio53", "gpio54", "gpio55", "gpio56",
+};
+static const char * const phase_flag11_groups[] = {
+ "gpio53",
+};
+static const char * const phase_flag12_groups[] = {
+ "gpio54",
+};
+static const char * const phase_flag13_groups[] = {
+ "gpio55",
+};
+static const char * const phase_flag17_groups[] = {
+ "gpio56",
+};
+static const char * const qua_mi2s_groups[] = {
+ "gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63",
+};
+static const char * const gcc_gp1_groups[] = {
+ "gpio57", "gpio78",
+};
+static const char * const phase_flag18_groups[] = {
+ "gpio57",
+};
+static const char * const phase_flag19_groups[] = {
+ "gpio58",
+};
+static const char * const phase_flag20_groups[] = {
+ "gpio59",
+};
+static const char * const cri_trng0_groups[] = {
+ "gpio60",
+};
+static const char * const phase_flag21_groups[] = {
+ "gpio60",
+};
+static const char * const cri_trng1_groups[] = {
+ "gpio61",
+};
+static const char * const phase_flag22_groups[] = {
+ "gpio61",
+};
+static const char * const cri_trng_groups[] = {
+ "gpio62",
+};
+static const char * const phase_flag23_groups[] = {
+ "gpio62",
+};
+static const char * const phase_flag24_groups[] = {
+ "gpio63",
+};
+static const char * const pri_mi2s_groups[] = {
+ "gpio64", "gpio65", "gpio67", "gpio68",
+};
+static const char * const sp_cmu_groups[] = {
+ "gpio64",
+};
+static const char * const phase_flag25_groups[] = {
+ "gpio64",
+};
+static const char * const qup8_groups[] = {
+ "gpio65", "gpio66", "gpio67", "gpio68",
+};
+static const char * const pri_mi2s_ws_groups[] = {
+ "gpio66",
+};
+static const char * const spkr_i2s_groups[] = {
+ "gpio69", "gpio70", "gpio71", "gpio72",
+};
+static const char * const audio_ref_groups[] = {
+ "gpio69",
+};
+static const char * const tsense_pwm1_groups[] = {
+ "gpio71",
+};
+static const char * const tsense_pwm2_groups[] = {
+ "gpio71",
+};
+static const char * const btfm_slimbus_groups[] = {
+ "gpio73", "gpio74",
+};
+static const char * const atest_usb2_groups[] = {
+ "gpio73",
+};
+static const char * const ter_mi2s_groups[] = {
+ "gpio74", "gpio75", "gpio76", "gpio77", "gpio78",
+};
+static const char * const phase_flag7_groups[] = {
+ "gpio74",
+};
+static const char * const atest_usb23_groups[] = {
+ "gpio74",
+};
+static const char * const phase_flag8_groups[] = {
+ "gpio75",
+};
+static const char * const atest_usb22_groups[] = {
+ "gpio75",
+};
+static const char * const phase_flag9_groups[] = {
+ "gpio76",
+};
+static const char * const atest_usb21_groups[] = {
+ "gpio76",
+};
+static const char * const phase_flag4_groups[] = {
+ "gpio77",
+};
+static const char * const atest_usb20_groups[] = {
+ "gpio77",
+};
+static const char * const sec_mi2s_groups[] = {
+ "gpio79", "gpio80", "gpio81", "gpio82", "gpio83",
+};
+static const char * const qup15_groups[] = {
+ "gpio81", "gpio82", "gpio83", "gpio84",
+};
+static const char * const qup5_groups[] = {
+ "gpio85", "gpio86", "gpio87", "gpio88",
+};
+static const char * const tsif1_clk_groups[] = {
+ "gpio89",
+};
+static const char * const qup4_groups[] = {
+ "gpio89", "gpio90", "gpio91", "gpio92",
+};
+static const char * const tgu_ch3_groups[] = {
+ "gpio89",
+};
+static const char * const phase_flag10_groups[] = {
+ "gpio89",
+};
+static const char * const tsif1_en_groups[] = {
+ "gpio90",
+};
+static const char * const mdp_vsync0_groups[] = {
+ "gpio90",
+};
+static const char * const mdp_vsync1_groups[] = {
+ "gpio90",
+};
+static const char * const mdp_vsync2_groups[] = {
+ "gpio90",
+};
+static const char * const mdp_vsync3_groups[] = {
+ "gpio90",
+};
+static const char * const tgu_ch0_groups[] = {
+ "gpio90",
+};
+static const char * const phase_flag0_groups[] = {
+ "gpio90",
+};
+static const char * const tsif1_data_groups[] = {
+ "gpio91",
+};
+static const char * const sdc4_cmd_groups[] = {
+ "gpio91",
+};
+static const char * const tgu_ch1_groups[] = {
+ "gpio91",
+};
+static const char * const tsif2_error_groups[] = {
+ "gpio92",
+};
+static const char * const sdc43_groups[] = {
+ "gpio92",
+};
+static const char * const vfr_1_groups[] = {
+ "gpio92",
+};
+static const char * const tgu_ch2_groups[] = {
+ "gpio92",
+};
+static const char * const tsif2_clk_groups[] = {
+ "gpio93",
+};
+static const char * const sdc4_clk_groups[] = {
+ "gpio93",
+};
+static const char * const qup7_groups[] = {
+ "gpio93", "gpio94", "gpio95", "gpio96",
+};
+static const char * const tsif2_en_groups[] = {
+ "gpio94",
+};
+static const char * const sdc42_groups[] = {
+ "gpio94",
+};
+static const char * const tsif2_data_groups[] = {
+ "gpio95",
+};
+static const char * const sdc41_groups[] = {
+ "gpio95",
+};
+static const char * const tsif2_sync_groups[] = {
+ "gpio96",
+};
+static const char * const sdc40_groups[] = {
+ "gpio96",
+};
+static const char * const phase_flag3_groups[] = {
+ "gpio96",
+};
+static const char * const ldo_en_groups[] = {
+ "gpio97",
+};
+static const char * const ldo_update_groups[] = {
+ "gpio98",
+};
+static const char * const phase_flag14_groups[] = {
+ "gpio99",
+};
+static const char * const phase_flag15_groups[] = {
+ "gpio100",
+};
+static const char * const pci_e1_groups[] = {
+ "gpio102", "gpio103",
+};
+static const char * const prng_rosc_groups[] = {
+ "gpio102",
+};
+static const char * const phase_flag5_groups[] = {
+ "gpio103",
+};
+static const char * const uim2_data_groups[] = {
+ "gpio105",
+};
+static const char * const qup13_groups[] = {
+ "gpio105", "gpio106", "gpio107", "gpio108",
+};
+static const char * const uim2_clk_groups[] = {
+ "gpio106",
+};
+static const char * const uim2_reset_groups[] = {
+ "gpio107",
+};
+static const char * const uim2_present_groups[] = {
+ "gpio108",
+};
+static const char * const uim1_data_groups[] = {
+ "gpio109",
+};
+static const char * const uim1_clk_groups[] = {
+ "gpio110",
+};
+static const char * const uim1_reset_groups[] = {
+ "gpio111",
+};
+static const char * const uim1_present_groups[] = {
+ "gpio112",
+};
+static const char * const uim_batt_groups[] = {
+ "gpio113",
+};
+static const char * const edp_hot_groups[] = {
+ "gpio113",
+};
+static const char * const nav_pps_groups[] = {
+ "gpio114", "gpio114", "gpio115", "gpio115", "gpio128", "gpio128",
+ "gpio129", "gpio129", "gpio143", "gpio143",
+};
+static const char * const atest_char_groups[] = {
+ "gpio117",
+};
+static const char * const adsp_ext_groups[] = {
+ "gpio118",
+};
+static const char * const atest_char3_groups[] = {
+ "gpio118",
+};
+static const char * const atest_char2_groups[] = {
+ "gpio119",
+};
+static const char * const atest_char1_groups[] = {
+ "gpio120",
+};
+static const char * const atest_char0_groups[] = {
+ "gpio121",
+};
+static const char * const qlink_request_groups[] = {
+ "gpio130",
+};
+static const char * const qlink_enable_groups[] = {
+ "gpio131",
+};
+static const char * const pa_indicator_groups[] = {
+ "gpio135",
+};
+static const char * const phase_flag26_groups[] = {
+ "gpio137",
+};
+static const char * const phase_flag27_groups[] = {
+ "gpio138",
+};
+static const char * const phase_flag28_groups[] = {
+ "gpio139",
+};
+static const char * const phase_flag6_groups[] = {
+ "gpio140",
+};
+static const char * const phase_flag29_groups[] = {
+ "gpio141",
+};
+static const char * const phase_flag30_groups[] = {
+ "gpio142",
+};
+static const char * const phase_flag31_groups[] = {
+ "gpio143",
+};
+static const char * const mss_lte_groups[] = {
+ "gpio144", "gpio145",
+};
+static const char * const qup0_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3",
+};
static const char * const gpio_groups[] = {
"gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7",
"gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14",
@@ -790,21 +1105,6 @@
"gpio141", "gpio142", "gpio143", "gpio144", "gpio145", "gpio146",
"gpio147", "gpio148", "gpio149",
};
-static const char * const qup0_groups[] = {
- "gpio0", "gpio1", "gpio2", "gpio3",
-};
-static const char * const reserved0_groups[] = {
- "gpio0",
-};
-static const char * const reserved1_groups[] = {
- "gpio1",
-};
-static const char * const reserved2_groups[] = {
- "gpio2",
-};
-static const char * const reserved3_groups[] = {
- "gpio3",
-};
static const char * const qup9_groups[] = {
"gpio4", "gpio5", "gpio6", "gpio7",
};
@@ -812,18 +1112,9 @@
"gpio4", "gpio5", "gpio51", "gpio52", "gpio62", "gpio63", "gpio90",
"gpio91",
};
-static const char * const reserved4_groups[] = {
- "gpio4",
-};
-static const char * const reserved5_groups[] = {
- "gpio5",
-};
static const char * const ddr_pxi0_groups[] = {
"gpio6", "gpio7",
};
-static const char * const reserved6_groups[] = {
- "gpio6",
-};
static const char * const ddr_bist_groups[] = {
"gpio7", "gpio8", "gpio9", "gpio10",
};
@@ -836,9 +1127,6 @@
static const char * const atest_usb1_groups[] = {
"gpio7",
};
-static const char * const reserved7_groups[] = {
- "gpio7",
-};
static const char * const qup_l4_groups[] = {
"gpio8", "gpio35", "gpio105", "gpio123",
};
@@ -851,9 +1139,6 @@
static const char * const ddr_pxi1_groups[] = {
"gpio8", "gpio9",
};
-static const char * const reserved8_groups[] = {
- "gpio8",
-};
static const char * const qup_l5_groups[] = {
"gpio9", "gpio36", "gpio106", "gpio124",
};
@@ -863,9 +1148,6 @@
static const char * const atest_usb12_groups[] = {
"gpio9",
};
-static const char * const reserved9_groups[] = {
- "gpio9",
-};
static const char * const mdp_vsync_groups[] = {
"gpio10", "gpio11", "gpio12", "gpio97", "gpio98",
};
@@ -881,9 +1163,6 @@
static const char * const ddr_pxi2_groups[] = {
"gpio10", "gpio11",
};
-static const char * const reserved10_groups[] = {
- "gpio10",
-};
static const char * const edp_lcd_groups[] = {
"gpio11",
};
@@ -896,1191 +1175,107 @@
static const char * const atest_usb10_groups[] = {
"gpio11",
};
-static const char * const reserved11_groups[] = {
- "gpio11",
-};
static const char * const m_voc_groups[] = {
"gpio12",
};
static const char * const tsif1_sync_groups[] = {
"gpio12",
};
-static const char * const ddr_pxi3_groups[] = {
- "gpio12", "gpio13",
-};
-static const char * const reserved12_groups[] = {
- "gpio12",
-};
-static const char * const cam_mclk_groups[] = {
- "gpio13", "gpio14", "gpio15", "gpio16",
-};
-static const char * const pll_bypassnl_groups[] = {
- "gpio13",
-};
-static const char * const qdss_gpio0_groups[] = {
- "gpio13", "gpio117",
-};
-static const char * const reserved13_groups[] = {
- "gpio13",
-};
-static const char * const pll_reset_groups[] = {
- "gpio14",
-};
-static const char * const qdss_gpio1_groups[] = {
- "gpio14", "gpio118",
-};
-static const char * const reserved14_groups[] = {
- "gpio14",
-};
-static const char * const qdss_gpio2_groups[] = {
- "gpio15", "gpio119",
-};
-static const char * const reserved15_groups[] = {
- "gpio15",
-};
-static const char * const qdss_gpio3_groups[] = {
- "gpio16", "gpio120",
-};
-static const char * const reserved16_groups[] = {
- "gpio16",
-};
-static const char * const cci_i2c_groups[] = {
- "gpio17", "gpio18", "gpio19", "gpio20",
-};
-static const char * const qup1_groups[] = {
- "gpio17", "gpio18", "gpio19", "gpio20",
-};
-static const char * const qdss_gpio4_groups[] = {
- "gpio17", "gpio121",
-};
-static const char * const reserved17_groups[] = {
- "gpio17",
-};
-static const char * const qdss_gpio5_groups[] = {
- "gpio18", "gpio122",
-};
-static const char * const reserved18_groups[] = {
- "gpio18",
-};
-static const char * const qdss_gpio6_groups[] = {
- "gpio19", "gpio41",
-};
-static const char * const reserved19_groups[] = {
- "gpio19",
-};
-static const char * const qdss_gpio7_groups[] = {
- "gpio20", "gpio42",
-};
-static const char * const reserved20_groups[] = {
- "gpio20",
-};
-static const char * const cci_timer0_groups[] = {
- "gpio21",
-};
-static const char * const gcc_gp2_groups[] = {
- "gpio21", "gpio58",
-};
-static const char * const qdss_gpio8_groups[] = {
- "gpio21", "gpio75",
-};
-static const char * const reserved21_groups[] = {
- "gpio21",
-};
-static const char * const cci_timer1_groups[] = {
- "gpio22",
-};
-static const char * const gcc_gp3_groups[] = {
- "gpio22", "gpio59",
-};
-static const char * const qdss_gpio_groups[] = {
- "gpio22", "gpio30", "gpio123", "gpio124",
-};
-static const char * const reserved22_groups[] = {
- "gpio22",
-};
-static const char * const cci_timer2_groups[] = {
- "gpio23",
-};
-static const char * const qdss_gpio9_groups[] = {
- "gpio23", "gpio76",
-};
-static const char * const reserved23_groups[] = {
- "gpio23",
-};
-static const char * const cci_timer3_groups[] = {
- "gpio24",
-};
-static const char * const cci_async_groups[] = {
- "gpio24", "gpio25", "gpio26",
-};
-static const char * const qdss_gpio10_groups[] = {
- "gpio24", "gpio77",
-};
-static const char * const reserved24_groups[] = {
- "gpio24",
-};
-static const char * const cci_timer4_groups[] = {
- "gpio25",
-};
-static const char * const qdss_gpio11_groups[] = {
- "gpio25", "gpio79",
-};
-static const char * const reserved25_groups[] = {
- "gpio25",
-};
-static const char * const qdss_gpio12_groups[] = {
- "gpio26", "gpio80",
-};
-static const char * const reserved26_groups[] = {
- "gpio26",
-};
-static const char * const qup2_groups[] = {
- "gpio27", "gpio28", "gpio29", "gpio30",
-};
-static const char * const qdss_gpio13_groups[] = {
- "gpio27", "gpio93",
-};
-static const char * const reserved27_groups[] = {
- "gpio27",
-};
-static const char * const qdss_gpio14_groups[] = {
- "gpio28", "gpio43",
-};
-static const char * const reserved28_groups[] = {
- "gpio28",
-};
-static const char * const phase_flag1_groups[] = {
- "gpio29",
-};
-static const char * const qdss_gpio15_groups[] = {
- "gpio29", "gpio44",
-};
-static const char * const reserved29_groups[] = {
- "gpio29",
-};
-static const char * const phase_flag2_groups[] = {
- "gpio30",
-};
-static const char * const reserved30_groups[] = {
- "gpio30",
-};
-static const char * const qup11_groups[] = {
- "gpio31", "gpio32", "gpio33", "gpio34",
-};
-static const char * const qup14_groups[] = {
- "gpio31", "gpio32", "gpio33", "gpio34",
-};
-static const char * const reserved96_groups[] = {
- "gpio96",
-};
-static const char * const ldo_en_groups[] = {
- "gpio97",
-};
-static const char * const reserved97_groups[] = {
- "gpio97",
-};
-static const char * const ldo_update_groups[] = {
- "gpio98",
-};
-static const char * const reserved98_groups[] = {
- "gpio98",
-};
-static const char * const phase_flag14_groups[] = {
- "gpio99",
-};
-static const char * const reserved99_groups[] = {
- "gpio99",
-};
-static const char * const phase_flag15_groups[] = {
- "gpio100",
-};
-static const char * const reserved100_groups[] = {
- "gpio100",
-};
-static const char * const reserved101_groups[] = {
- "gpio101",
-};
-static const char * const pci_e1_groups[] = {
- "gpio102", "gpio103",
-};
-static const char * const prng_rosc_groups[] = {
- "gpio102",
-};
-static const char * const reserved102_groups[] = {
- "gpio102",
-};
-static const char * const phase_flag5_groups[] = {
- "gpio103",
-};
-static const char * const reserved103_groups[] = {
- "gpio103",
-};
-static const char * const reserved104_groups[] = {
- "gpio104",
-};
-static const char * const uim2_data_groups[] = {
- "gpio105",
-};
-static const char * const qup13_groups[] = {
- "gpio105", "gpio106", "gpio107", "gpio108",
-};
-static const char * const reserved105_groups[] = {
- "gpio105",
-};
-static const char * const uim2_clk_groups[] = {
- "gpio106",
-};
-static const char * const reserved106_groups[] = {
- "gpio106",
-};
-static const char * const uim2_reset_groups[] = {
- "gpio107",
-};
-static const char * const reserved107_groups[] = {
- "gpio107",
-};
-static const char * const uim2_present_groups[] = {
- "gpio108",
-};
-static const char * const reserved108_groups[] = {
- "gpio108",
-};
-static const char * const uim1_data_groups[] = {
- "gpio109",
-};
-static const char * const reserved109_groups[] = {
- "gpio109",
-};
-static const char * const uim1_clk_groups[] = {
- "gpio110",
-};
-static const char * const reserved110_groups[] = {
- "gpio110",
-};
-static const char * const uim1_reset_groups[] = {
- "gpio111",
-};
-static const char * const reserved111_groups[] = {
- "gpio111",
-};
-static const char * const uim1_present_groups[] = {
- "gpio112",
-};
-static const char * const reserved112_groups[] = {
- "gpio112",
-};
-static const char * const uim_batt_groups[] = {
- "gpio113",
-};
-static const char * const edp_hot_groups[] = {
- "gpio113",
-};
-static const char * const reserved113_groups[] = {
- "gpio113",
-};
-static const char * const nav_pps_groups[] = {
- "gpio114", "gpio114", "gpio115", "gpio115", "gpio128", "gpio128",
- "gpio129", "gpio129", "gpio143", "gpio143",
-};
-static const char * const reserved114_groups[] = {
- "gpio114",
-};
-static const char * const reserved115_groups[] = {
- "gpio115",
-};
-static const char * const reserved116_groups[] = {
- "gpio116",
-};
-static const char * const atest_char_groups[] = {
- "gpio117",
-};
-static const char * const reserved117_groups[] = {
- "gpio117",
-};
-static const char * const adsp_ext_groups[] = {
- "gpio118",
-};
-static const char * const atest_char3_groups[] = {
- "gpio118",
-};
-static const char * const reserved118_groups[] = {
- "gpio118",
-};
-static const char * const atest_char2_groups[] = {
- "gpio119",
-};
-static const char * const reserved119_groups[] = {
- "gpio119",
-};
-static const char * const atest_char1_groups[] = {
- "gpio120",
-};
-static const char * const reserved120_groups[] = {
- "gpio120",
-};
-static const char * const atest_char0_groups[] = {
- "gpio121",
-};
-static const char * const reserved121_groups[] = {
- "gpio121",
-};
-static const char * const reserved122_groups[] = {
- "gpio122",
-};
-static const char * const reserved123_groups[] = {
- "gpio123",
-};
-static const char * const reserved124_groups[] = {
- "gpio124",
-};
-static const char * const reserved125_groups[] = {
- "gpio125",
-};
-static const char * const reserved126_groups[] = {
- "gpio126",
-};
-static const char * const reserved127_groups[] = {
- "gpio127",
-};
-static const char * const reserved128_groups[] = {
- "gpio128",
-};
-static const char * const reserved129_groups[] = {
- "gpio129",
-};
-static const char * const qlink_request_groups[] = {
- "gpio130",
-};
-static const char * const reserved130_groups[] = {
- "gpio130",
-};
-static const char * const qlink_enable_groups[] = {
- "gpio131",
-};
-static const char * const reserved131_groups[] = {
- "gpio131",
-};
-static const char * const reserved132_groups[] = {
- "gpio132",
-};
-static const char * const reserved133_groups[] = {
- "gpio133",
-};
-static const char * const reserved134_groups[] = {
- "gpio134",
-};
-static const char * const pa_indicator_groups[] = {
- "gpio135",
-};
-static const char * const reserved135_groups[] = {
- "gpio135",
-};
-static const char * const reserved136_groups[] = {
- "gpio136",
-};
-static const char * const phase_flag26_groups[] = {
- "gpio137",
-};
-static const char * const reserved137_groups[] = {
- "gpio137",
-};
-static const char * const phase_flag27_groups[] = {
- "gpio138",
-};
-static const char * const reserved138_groups[] = {
- "gpio138",
-};
-static const char * const phase_flag28_groups[] = {
- "gpio139",
-};
-static const char * const reserved139_groups[] = {
- "gpio139",
-};
-static const char * const phase_flag6_groups[] = {
- "gpio140",
-};
-static const char * const reserved140_groups[] = {
- "gpio140",
-};
-static const char * const phase_flag29_groups[] = {
- "gpio141",
-};
-static const char * const reserved141_groups[] = {
- "gpio141",
-};
-static const char * const phase_flag30_groups[] = {
- "gpio142",
-};
-static const char * const reserved142_groups[] = {
- "gpio142",
-};
-static const char * const phase_flag31_groups[] = {
- "gpio143",
-};
-static const char * const reserved143_groups[] = {
- "gpio143",
-};
-static const char * const mss_lte_groups[] = {
- "gpio144", "gpio145",
-};
-static const char * const reserved144_groups[] = {
- "gpio144",
-};
-static const char * const reserved145_groups[] = {
- "gpio145",
-};
-static const char * const reserved146_groups[] = {
- "gpio146",
-};
-static const char * const reserved147_groups[] = {
- "gpio147",
-};
-static const char * const reserved148_groups[] = {
- "gpio148",
-};
-static const char * const reserved149_groups[] = {
- "gpio149", "gpio149",
-};
-static const char * const reserved31_groups[] = {
- "gpio31",
-};
-static const char * const reserved32_groups[] = {
- "gpio32",
-};
-static const char * const reserved33_groups[] = {
- "gpio33",
-};
-static const char * const reserved34_groups[] = {
- "gpio34",
-};
-static const char * const pci_e0_groups[] = {
- "gpio35", "gpio36",
-};
-static const char * const jitter_bist_groups[] = {
- "gpio35",
-};
-static const char * const reserved35_groups[] = {
- "gpio35",
-};
-static const char * const pll_bist_groups[] = {
- "gpio36",
-};
-static const char * const atest_tsens_groups[] = {
- "gpio36",
-};
-static const char * const reserved36_groups[] = {
- "gpio36",
-};
-static const char * const agera_pll_groups[] = {
- "gpio37",
-};
-static const char * const reserved37_groups[] = {
- "gpio37",
-};
-static const char * const usb_phy_groups[] = {
- "gpio38",
-};
-static const char * const reserved38_groups[] = {
- "gpio38",
-};
-static const char * const lpass_slimbus_groups[] = {
- "gpio39", "gpio70", "gpio71", "gpio72",
-};
-static const char * const reserved39_groups[] = {
- "gpio39",
-};
-static const char * const sd_write_groups[] = {
- "gpio40",
-};
-static const char * const tsif1_error_groups[] = {
- "gpio40",
-};
-static const char * const reserved40_groups[] = {
- "gpio40",
-};
-static const char * const qup3_groups[] = {
- "gpio41", "gpio42", "gpio43", "gpio44",
-};
-static const char * const reserved41_groups[] = {
- "gpio41",
-};
-static const char * const reserved42_groups[] = {
- "gpio42",
-};
-static const char * const reserved43_groups[] = {
- "gpio43",
-};
-static const char * const reserved44_groups[] = {
- "gpio44",
-};
-static const char * const qup6_groups[] = {
- "gpio45", "gpio46", "gpio47", "gpio48",
-};
-static const char * const reserved45_groups[] = {
- "gpio45",
-};
-static const char * const reserved46_groups[] = {
- "gpio46",
-};
-static const char * const reserved47_groups[] = {
- "gpio47",
-};
-static const char * const reserved48_groups[] = {
- "gpio48",
-};
-static const char * const qup12_groups[] = {
- "gpio49", "gpio50", "gpio51", "gpio52",
-};
-static const char * const reserved49_groups[] = {
- "gpio49",
-};
-static const char * const reserved50_groups[] = {
- "gpio50",
-};
-static const char * const reserved51_groups[] = {
- "gpio51",
-};
-static const char * const phase_flag16_groups[] = {
- "gpio52",
-};
-static const char * const reserved52_groups[] = {
- "gpio52",
-};
-static const char * const qup10_groups[] = {
- "gpio53", "gpio54", "gpio55", "gpio56",
-};
-static const char * const phase_flag11_groups[] = {
- "gpio53",
-};
-static const char * const reserved53_groups[] = {
- "gpio53",
-};
-static const char * const phase_flag12_groups[] = {
- "gpio54",
-};
-static const char * const reserved54_groups[] = {
- "gpio54",
-};
-static const char * const phase_flag13_groups[] = {
- "gpio55",
-};
-static const char * const reserved55_groups[] = {
- "gpio55",
-};
-static const char * const phase_flag17_groups[] = {
- "gpio56",
-};
-static const char * const reserved56_groups[] = {
- "gpio56",
-};
-static const char * const qua_mi2s_groups[] = {
- "gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63",
-};
-static const char * const gcc_gp1_groups[] = {
- "gpio57", "gpio78",
-};
-static const char * const phase_flag18_groups[] = {
- "gpio57",
-};
-static const char * const reserved57_groups[] = {
- "gpio57",
-};
-static const char * const phase_flag19_groups[] = {
- "gpio58",
-};
-static const char * const reserved58_groups[] = {
- "gpio58",
-};
-static const char * const phase_flag20_groups[] = {
- "gpio59",
-};
-static const char * const reserved59_groups[] = {
- "gpio59",
-};
-static const char * const cri_trng0_groups[] = {
- "gpio60",
-};
-static const char * const phase_flag21_groups[] = {
- "gpio60",
-};
-static const char * const reserved60_groups[] = {
- "gpio60",
-};
-static const char * const cri_trng1_groups[] = {
- "gpio61",
-};
-static const char * const phase_flag22_groups[] = {
- "gpio61",
-};
-static const char * const reserved61_groups[] = {
- "gpio61",
-};
-static const char * const cri_trng_groups[] = {
- "gpio62",
-};
-static const char * const phase_flag23_groups[] = {
- "gpio62",
-};
-static const char * const reserved62_groups[] = {
- "gpio62",
-};
-static const char * const phase_flag24_groups[] = {
- "gpio63",
-};
-static const char * const reserved63_groups[] = {
- "gpio63",
-};
-static const char * const pri_mi2s_groups[] = {
- "gpio64", "gpio65", "gpio67", "gpio68",
-};
-static const char * const sp_cmu_groups[] = {
- "gpio64",
-};
-static const char * const phase_flag25_groups[] = {
- "gpio64",
-};
-static const char * const reserved64_groups[] = {
- "gpio64",
-};
-static const char * const qup8_groups[] = {
- "gpio65", "gpio66", "gpio67", "gpio68",
-};
-static const char * const reserved65_groups[] = {
- "gpio65",
-};
-static const char * const pri_mi2s_ws_groups[] = {
- "gpio66",
-};
-static const char * const reserved66_groups[] = {
- "gpio66",
-};
-static const char * const reserved67_groups[] = {
- "gpio67",
-};
-static const char * const reserved68_groups[] = {
- "gpio68",
-};
-static const char * const spkr_i2s_groups[] = {
- "gpio69", "gpio70", "gpio71", "gpio72",
-};
-static const char * const audio_ref_groups[] = {
- "gpio69",
-};
-static const char * const reserved69_groups[] = {
- "gpio69",
-};
-static const char * const reserved70_groups[] = {
- "gpio70",
-};
-static const char * const tsense_pwm1_groups[] = {
- "gpio71",
-};
-static const char * const tsense_pwm2_groups[] = {
- "gpio71",
-};
-static const char * const reserved71_groups[] = {
- "gpio71",
-};
-static const char * const reserved72_groups[] = {
- "gpio72",
-};
-static const char * const btfm_slimbus_groups[] = {
- "gpio73", "gpio74",
-};
-static const char * const atest_usb2_groups[] = {
- "gpio73",
-};
-static const char * const reserved73_groups[] = {
- "gpio73",
-};
-static const char * const ter_mi2s_groups[] = {
- "gpio74", "gpio75", "gpio76", "gpio77", "gpio78",
-};
-static const char * const phase_flag7_groups[] = {
- "gpio74",
-};
-static const char * const atest_usb23_groups[] = {
- "gpio74",
-};
-static const char * const reserved74_groups[] = {
- "gpio74",
-};
-static const char * const phase_flag8_groups[] = {
- "gpio75",
-};
-static const char * const atest_usb22_groups[] = {
- "gpio75",
-};
-static const char * const reserved75_groups[] = {
- "gpio75",
-};
-static const char * const phase_flag9_groups[] = {
- "gpio76",
-};
-static const char * const atest_usb21_groups[] = {
- "gpio76",
-};
-static const char * const reserved76_groups[] = {
- "gpio76",
-};
-static const char * const phase_flag4_groups[] = {
- "gpio77",
-};
-static const char * const atest_usb20_groups[] = {
- "gpio77",
-};
-static const char * const reserved77_groups[] = {
- "gpio77",
-};
-static const char * const reserved78_groups[] = {
- "gpio78",
-};
-static const char * const sec_mi2s_groups[] = {
- "gpio79", "gpio80", "gpio81", "gpio82", "gpio83",
-};
-static const char * const reserved79_groups[] = {
- "gpio79",
-};
-static const char * const reserved80_groups[] = {
- "gpio80",
-};
-static const char * const qup15_groups[] = {
- "gpio81", "gpio82", "gpio83", "gpio84",
-};
-static const char * const reserved81_groups[] = {
- "gpio81",
-};
-static const char * const reserved82_groups[] = {
- "gpio82",
-};
-static const char * const reserved83_groups[] = {
- "gpio83",
-};
-static const char * const reserved84_groups[] = {
- "gpio84",
-};
-static const char * const qup5_groups[] = {
- "gpio85", "gpio86", "gpio87", "gpio88",
-};
-static const char * const reserved85_groups[] = {
- "gpio85",
-};
-static const char * const reserved86_groups[] = {
- "gpio86",
-};
-static const char * const reserved87_groups[] = {
- "gpio87",
-};
-static const char * const reserved88_groups[] = {
- "gpio88",
-};
-static const char * const tsif1_clk_groups[] = {
- "gpio89",
-};
-static const char * const qup4_groups[] = {
- "gpio89", "gpio90", "gpio91", "gpio92",
-};
-static const char * const tgu_ch3_groups[] = {
- "gpio89",
-};
-static const char * const phase_flag10_groups[] = {
- "gpio89",
-};
-static const char * const reserved89_groups[] = {
- "gpio89",
-};
-static const char * const tsif1_en_groups[] = {
- "gpio90",
-};
-static const char * const mdp_vsync0_groups[] = {
- "gpio90",
-};
-static const char * const mdp_vsync1_groups[] = {
- "gpio90",
-};
-static const char * const mdp_vsync2_groups[] = {
- "gpio90",
-};
-static const char * const mdp_vsync3_groups[] = {
- "gpio90",
-};
-static const char * const tgu_ch0_groups[] = {
- "gpio90",
-};
-static const char * const phase_flag0_groups[] = {
- "gpio90",
-};
-static const char * const reserved90_groups[] = {
- "gpio90",
-};
-static const char * const tsif1_data_groups[] = {
- "gpio91",
-};
-static const char * const sdc4_cmd_groups[] = {
- "gpio91",
-};
-static const char * const tgu_ch1_groups[] = {
- "gpio91",
-};
-static const char * const reserved91_groups[] = {
- "gpio91",
-};
-static const char * const tsif2_error_groups[] = {
- "gpio92",
-};
-static const char * const sdc43_groups[] = {
- "gpio92",
-};
-static const char * const vfr_1_groups[] = {
- "gpio92",
-};
-static const char * const tgu_ch2_groups[] = {
- "gpio92",
-};
-static const char * const reserved92_groups[] = {
- "gpio92",
-};
-static const char * const tsif2_clk_groups[] = {
- "gpio93",
-};
-static const char * const sdc4_clk_groups[] = {
- "gpio93",
-};
-static const char * const qup7_groups[] = {
- "gpio93", "gpio94", "gpio95", "gpio96",
-};
-static const char * const reserved93_groups[] = {
- "gpio93",
-};
-static const char * const tsif2_en_groups[] = {
- "gpio94",
-};
-static const char * const sdc42_groups[] = {
- "gpio94",
-};
-static const char * const reserved94_groups[] = {
- "gpio94",
-};
-static const char * const tsif2_data_groups[] = {
- "gpio95",
-};
-static const char * const sdc41_groups[] = {
- "gpio95",
-};
-static const char * const reserved95_groups[] = {
- "gpio95",
-};
-static const char * const tsif2_sync_groups[] = {
- "gpio96",
-};
-static const char * const sdc40_groups[] = {
- "gpio96",
-};
-static const char * const phase_flag3_groups[] = {
- "gpio96",
-};
static const struct msm_function sdm845_functions[] = {
- FUNCTION(gpio),
- FUNCTION(qup0),
- FUNCTION(reserved0),
- FUNCTION(reserved1),
- FUNCTION(reserved2),
- FUNCTION(reserved3),
- FUNCTION(qup9),
- FUNCTION(qdss_cti),
- FUNCTION(reserved4),
- FUNCTION(reserved5),
- FUNCTION(ddr_pxi0),
- FUNCTION(reserved6),
- FUNCTION(ddr_bist),
- FUNCTION(atest_tsens2),
- FUNCTION(vsense_trigger),
- FUNCTION(atest_usb1),
- FUNCTION(reserved7),
- FUNCTION(qup_l4),
- FUNCTION(wlan1_adc1),
- FUNCTION(atest_usb13),
- FUNCTION(ddr_pxi1),
- FUNCTION(reserved8),
- FUNCTION(qup_l5),
- FUNCTION(wlan1_adc0),
- FUNCTION(atest_usb12),
- FUNCTION(reserved9),
- FUNCTION(mdp_vsync),
- FUNCTION(qup_l6),
- FUNCTION(wlan2_adc1),
- FUNCTION(atest_usb11),
- FUNCTION(ddr_pxi2),
- FUNCTION(reserved10),
- FUNCTION(edp_lcd),
- FUNCTION(dbg_out),
- FUNCTION(wlan2_adc0),
- FUNCTION(atest_usb10),
- FUNCTION(reserved11),
- FUNCTION(m_voc),
- FUNCTION(tsif1_sync),
FUNCTION(ddr_pxi3),
- FUNCTION(reserved12),
FUNCTION(cam_mclk),
FUNCTION(pll_bypassnl),
FUNCTION(qdss_gpio0),
- FUNCTION(reserved13),
FUNCTION(pll_reset),
FUNCTION(qdss_gpio1),
- FUNCTION(reserved14),
FUNCTION(qdss_gpio2),
- FUNCTION(reserved15),
FUNCTION(qdss_gpio3),
- FUNCTION(reserved16),
FUNCTION(cci_i2c),
FUNCTION(qup1),
FUNCTION(qdss_gpio4),
- FUNCTION(reserved17),
FUNCTION(qdss_gpio5),
- FUNCTION(reserved18),
FUNCTION(qdss_gpio6),
- FUNCTION(reserved19),
FUNCTION(qdss_gpio7),
- FUNCTION(reserved20),
FUNCTION(cci_timer0),
FUNCTION(gcc_gp2),
FUNCTION(qdss_gpio8),
- FUNCTION(reserved21),
FUNCTION(cci_timer1),
FUNCTION(gcc_gp3),
FUNCTION(qdss_gpio),
- FUNCTION(reserved22),
FUNCTION(cci_timer2),
FUNCTION(qdss_gpio9),
- FUNCTION(reserved23),
FUNCTION(cci_timer3),
FUNCTION(cci_async),
FUNCTION(qdss_gpio10),
- FUNCTION(reserved24),
FUNCTION(cci_timer4),
FUNCTION(qdss_gpio11),
- FUNCTION(reserved25),
FUNCTION(qdss_gpio12),
- FUNCTION(reserved26),
FUNCTION(qup2),
FUNCTION(qdss_gpio13),
- FUNCTION(reserved27),
FUNCTION(qdss_gpio14),
- FUNCTION(reserved28),
FUNCTION(phase_flag1),
FUNCTION(qdss_gpio15),
- FUNCTION(reserved29),
FUNCTION(phase_flag2),
- FUNCTION(reserved30),
FUNCTION(qup11),
FUNCTION(qup14),
- FUNCTION(reserved96),
- FUNCTION(ldo_en),
- FUNCTION(reserved97),
- FUNCTION(ldo_update),
- FUNCTION(reserved98),
- FUNCTION(phase_flag14),
- FUNCTION(reserved99),
- FUNCTION(phase_flag15),
- FUNCTION(reserved100),
- FUNCTION(reserved101),
- FUNCTION(pci_e1),
- FUNCTION(prng_rosc),
- FUNCTION(reserved102),
- FUNCTION(phase_flag5),
- FUNCTION(reserved103),
- FUNCTION(reserved104),
- FUNCTION(uim2_data),
- FUNCTION(qup13),
- FUNCTION(reserved105),
- FUNCTION(uim2_clk),
- FUNCTION(reserved106),
- FUNCTION(uim2_reset),
- FUNCTION(reserved107),
- FUNCTION(uim2_present),
- FUNCTION(reserved108),
- FUNCTION(uim1_data),
- FUNCTION(reserved109),
- FUNCTION(uim1_clk),
- FUNCTION(reserved110),
- FUNCTION(uim1_reset),
- FUNCTION(reserved111),
- FUNCTION(uim1_present),
- FUNCTION(reserved112),
- FUNCTION(uim_batt),
- FUNCTION(edp_hot),
- FUNCTION(reserved113),
- FUNCTION(nav_pps),
- FUNCTION(reserved114),
- FUNCTION(reserved115),
- FUNCTION(reserved116),
- FUNCTION(atest_char),
- FUNCTION(reserved117),
- FUNCTION(adsp_ext),
- FUNCTION(atest_char3),
- FUNCTION(reserved118),
- FUNCTION(atest_char2),
- FUNCTION(reserved119),
- FUNCTION(atest_char1),
- FUNCTION(reserved120),
- FUNCTION(atest_char0),
- FUNCTION(reserved121),
- FUNCTION(reserved122),
- FUNCTION(reserved123),
- FUNCTION(reserved124),
- FUNCTION(reserved125),
- FUNCTION(reserved126),
- FUNCTION(reserved127),
- FUNCTION(reserved128),
- FUNCTION(reserved129),
- FUNCTION(qlink_request),
- FUNCTION(reserved130),
- FUNCTION(qlink_enable),
- FUNCTION(reserved131),
- FUNCTION(reserved132),
- FUNCTION(reserved133),
- FUNCTION(reserved134),
- FUNCTION(pa_indicator),
- FUNCTION(reserved135),
- FUNCTION(reserved136),
- FUNCTION(phase_flag26),
- FUNCTION(reserved137),
- FUNCTION(phase_flag27),
- FUNCTION(reserved138),
- FUNCTION(phase_flag28),
- FUNCTION(reserved139),
- FUNCTION(phase_flag6),
- FUNCTION(reserved140),
- FUNCTION(phase_flag29),
- FUNCTION(reserved141),
- FUNCTION(phase_flag30),
- FUNCTION(reserved142),
- FUNCTION(phase_flag31),
- FUNCTION(reserved143),
- FUNCTION(mss_lte),
- FUNCTION(reserved144),
- FUNCTION(reserved145),
- FUNCTION(reserved146),
- FUNCTION(reserved147),
- FUNCTION(reserved148),
- FUNCTION(reserved149),
- FUNCTION(reserved31),
- FUNCTION(reserved32),
- FUNCTION(reserved33),
- FUNCTION(reserved34),
FUNCTION(pci_e0),
FUNCTION(jitter_bist),
- FUNCTION(reserved35),
FUNCTION(pll_bist),
FUNCTION(atest_tsens),
- FUNCTION(reserved36),
FUNCTION(agera_pll),
- FUNCTION(reserved37),
FUNCTION(usb_phy),
- FUNCTION(reserved38),
FUNCTION(lpass_slimbus),
- FUNCTION(reserved39),
FUNCTION(sd_write),
FUNCTION(tsif1_error),
- FUNCTION(reserved40),
FUNCTION(qup3),
- FUNCTION(reserved41),
- FUNCTION(reserved42),
- FUNCTION(reserved43),
- FUNCTION(reserved44),
FUNCTION(qup6),
- FUNCTION(reserved45),
- FUNCTION(reserved46),
- FUNCTION(reserved47),
- FUNCTION(reserved48),
FUNCTION(qup12),
- FUNCTION(reserved49),
- FUNCTION(reserved50),
- FUNCTION(reserved51),
FUNCTION(phase_flag16),
- FUNCTION(reserved52),
FUNCTION(qup10),
FUNCTION(phase_flag11),
- FUNCTION(reserved53),
FUNCTION(phase_flag12),
- FUNCTION(reserved54),
FUNCTION(phase_flag13),
- FUNCTION(reserved55),
FUNCTION(phase_flag17),
- FUNCTION(reserved56),
FUNCTION(qua_mi2s),
FUNCTION(gcc_gp1),
FUNCTION(phase_flag18),
- FUNCTION(reserved57),
FUNCTION(phase_flag19),
- FUNCTION(reserved58),
FUNCTION(phase_flag20),
- FUNCTION(reserved59),
FUNCTION(cri_trng0),
FUNCTION(phase_flag21),
- FUNCTION(reserved60),
FUNCTION(cri_trng1),
FUNCTION(phase_flag22),
- FUNCTION(reserved61),
FUNCTION(cri_trng),
FUNCTION(phase_flag23),
- FUNCTION(reserved62),
FUNCTION(phase_flag24),
- FUNCTION(reserved63),
FUNCTION(pri_mi2s),
FUNCTION(sp_cmu),
FUNCTION(phase_flag25),
- FUNCTION(reserved64),
FUNCTION(qup8),
- FUNCTION(reserved65),
FUNCTION(pri_mi2s_ws),
- FUNCTION(reserved66),
- FUNCTION(reserved67),
- FUNCTION(reserved68),
FUNCTION(spkr_i2s),
FUNCTION(audio_ref),
- FUNCTION(reserved69),
- FUNCTION(reserved70),
FUNCTION(tsense_pwm1),
FUNCTION(tsense_pwm2),
- FUNCTION(reserved71),
- FUNCTION(reserved72),
FUNCTION(btfm_slimbus),
FUNCTION(atest_usb2),
- FUNCTION(reserved73),
FUNCTION(ter_mi2s),
FUNCTION(phase_flag7),
FUNCTION(atest_usb23),
- FUNCTION(reserved74),
FUNCTION(phase_flag8),
FUNCTION(atest_usb22),
- FUNCTION(reserved75),
FUNCTION(phase_flag9),
FUNCTION(atest_usb21),
- FUNCTION(reserved76),
FUNCTION(phase_flag4),
FUNCTION(atest_usb20),
- FUNCTION(reserved77),
- FUNCTION(reserved78),
FUNCTION(sec_mi2s),
- FUNCTION(reserved79),
- FUNCTION(reserved80),
FUNCTION(qup15),
- FUNCTION(reserved81),
- FUNCTION(reserved82),
- FUNCTION(reserved83),
- FUNCTION(reserved84),
FUNCTION(qup5),
- FUNCTION(reserved85),
- FUNCTION(reserved86),
- FUNCTION(reserved87),
- FUNCTION(reserved88),
FUNCTION(tsif1_clk),
FUNCTION(qup4),
FUNCTION(tgu_ch3),
FUNCTION(phase_flag10),
- FUNCTION(reserved89),
FUNCTION(tsif1_en),
FUNCTION(mdp_vsync0),
FUNCTION(mdp_vsync1),
@@ -2088,293 +1283,347 @@
FUNCTION(mdp_vsync3),
FUNCTION(tgu_ch0),
FUNCTION(phase_flag0),
- FUNCTION(reserved90),
FUNCTION(tsif1_data),
FUNCTION(sdc4_cmd),
FUNCTION(tgu_ch1),
- FUNCTION(reserved91),
FUNCTION(tsif2_error),
FUNCTION(sdc43),
FUNCTION(vfr_1),
FUNCTION(tgu_ch2),
- FUNCTION(reserved92),
FUNCTION(tsif2_clk),
FUNCTION(sdc4_clk),
FUNCTION(qup7),
- FUNCTION(reserved93),
FUNCTION(tsif2_en),
FUNCTION(sdc42),
- FUNCTION(reserved94),
FUNCTION(tsif2_data),
FUNCTION(sdc41),
- FUNCTION(reserved95),
FUNCTION(tsif2_sync),
FUNCTION(sdc40),
FUNCTION(phase_flag3),
+ FUNCTION(ldo_en),
+ FUNCTION(ldo_update),
+ FUNCTION(phase_flag14),
+ FUNCTION(phase_flag15),
+ FUNCTION(pci_e1),
+ FUNCTION(prng_rosc),
+ FUNCTION(phase_flag5),
+ FUNCTION(uim2_data),
+ FUNCTION(qup13),
+ FUNCTION(uim2_clk),
+ FUNCTION(uim2_reset),
+ FUNCTION(uim2_present),
+ FUNCTION(uim1_data),
+ FUNCTION(uim1_clk),
+ FUNCTION(uim1_reset),
+ FUNCTION(uim1_present),
+ FUNCTION(uim_batt),
+ FUNCTION(edp_hot),
+ FUNCTION(nav_pps),
+ FUNCTION(atest_char),
+ FUNCTION(adsp_ext),
+ FUNCTION(atest_char3),
+ FUNCTION(atest_char2),
+ FUNCTION(atest_char1),
+ FUNCTION(atest_char0),
+ FUNCTION(qlink_request),
+ FUNCTION(qlink_enable),
+ FUNCTION(pa_indicator),
+ FUNCTION(phase_flag26),
+ FUNCTION(phase_flag27),
+ FUNCTION(phase_flag28),
+ FUNCTION(phase_flag6),
+ FUNCTION(phase_flag29),
+ FUNCTION(phase_flag30),
+ FUNCTION(phase_flag31),
+ FUNCTION(mss_lte),
+ FUNCTION(qup0),
+ FUNCTION(gpio),
+ FUNCTION(qup9),
+ FUNCTION(qdss_cti),
+ FUNCTION(ddr_pxi0),
+ FUNCTION(ddr_bist),
+ FUNCTION(atest_tsens2),
+ FUNCTION(vsense_trigger),
+ FUNCTION(atest_usb1),
+ FUNCTION(qup_l4),
+ FUNCTION(wlan1_adc1),
+ FUNCTION(atest_usb13),
+ FUNCTION(ddr_pxi1),
+ FUNCTION(qup_l5),
+ FUNCTION(wlan1_adc0),
+ FUNCTION(atest_usb12),
+ FUNCTION(mdp_vsync),
+ FUNCTION(qup_l6),
+ FUNCTION(wlan2_adc1),
+ FUNCTION(atest_usb11),
+ FUNCTION(ddr_pxi2),
+ FUNCTION(edp_lcd),
+ FUNCTION(dbg_out),
+ FUNCTION(wlan2_adc0),
+ FUNCTION(atest_usb10),
+ FUNCTION(m_voc),
+ FUNCTION(tsif1_sync),
};
+/* Every pin is maintained as a single group, and missing or non-existing pin
+ * would be maintained as dummy group to synchronize pin group index with
+ * pin descriptor registered with pinctrl core.
+ * Clients would not be able to request these dummy pin groups.
+ */
static const struct msm_pingroup sdm845_groups[] = {
- PINGROUP(0, NORTH, qup0, NA, reserved0, NA, NA, NA, NA, NA, NA),
- PINGROUP(1, NORTH, qup0, NA, reserved1, NA, NA, NA, NA, NA, NA),
- PINGROUP(2, NORTH, qup0, NA, reserved2, NA, NA, NA, NA, NA, NA),
- PINGROUP(3, NORTH, qup0, NA, reserved3, NA, NA, NA, NA, NA, NA),
- PINGROUP(4, NORTH, qup9, qdss_cti, reserved4, NA, NA, NA, NA, NA, NA),
- PINGROUP(5, NORTH, qup9, qdss_cti, reserved5, NA, NA, NA, NA, NA, NA),
- PINGROUP(6, NORTH, qup9, NA, ddr_pxi0, reserved6, NA, NA, NA, NA, NA),
- PINGROUP(7, NORTH, qup9, ddr_bist, NA, atest_tsens2, vsense_trigger,
- atest_usb1, ddr_pxi0, reserved7, NA),
- PINGROUP(8, NORTH, qup_l4, NA, ddr_bist, NA, NA, wlan1_adc1,
- atest_usb13, ddr_pxi1, reserved8),
- PINGROUP(9, NORTH, qup_l5, ddr_bist, NA, wlan1_adc0, atest_usb12,
- ddr_pxi1, reserved9, NA, NA),
- PINGROUP(10, NORTH, mdp_vsync, qup_l6, ddr_bist, wlan2_adc1,
- atest_usb11, ddr_pxi2, reserved10, NA, NA),
- PINGROUP(11, NORTH, mdp_vsync, edp_lcd, dbg_out, wlan2_adc0,
- atest_usb10, ddr_pxi2, reserved11, NA, NA),
- PINGROUP(12, SOUTH, mdp_vsync, m_voc, tsif1_sync, ddr_pxi3, reserved12,
- NA, NA, NA, NA),
- PINGROUP(13, SOUTH, cam_mclk, pll_bypassnl, qdss_gpio0, ddr_pxi3,
- reserved13, NA, NA, NA, NA),
- PINGROUP(14, SOUTH, cam_mclk, pll_reset, qdss_gpio1, reserved14, NA,
- NA, NA, NA, NA),
- PINGROUP(15, SOUTH, cam_mclk, qdss_gpio2, reserved15, NA, NA, NA, NA,
- NA, NA),
- PINGROUP(16, SOUTH, cam_mclk, qdss_gpio3, reserved16, NA, NA, NA, NA,
- NA, NA),
- PINGROUP(17, SOUTH, cci_i2c, qup1, qdss_gpio4, reserved17, NA, NA, NA,
- NA, NA),
- PINGROUP(18, SOUTH, cci_i2c, qup1, NA, qdss_gpio5, reserved18, NA, NA,
- NA, NA),
- PINGROUP(19, SOUTH, cci_i2c, qup1, NA, qdss_gpio6, reserved19, NA, NA,
- NA, NA),
- PINGROUP(20, SOUTH, cci_i2c, qup1, NA, qdss_gpio7, reserved20, NA, NA,
- NA, NA),
- PINGROUP(21, SOUTH, cci_timer0, gcc_gp2, qdss_gpio8, reserved21, NA,
- NA, NA, NA, NA),
- PINGROUP(22, SOUTH, cci_timer1, gcc_gp3, qdss_gpio, reserved22, NA, NA,
- NA, NA, NA),
- PINGROUP(23, SOUTH, cci_timer2, qdss_gpio9, reserved23, NA, NA, NA, NA,
- NA, NA),
- PINGROUP(24, SOUTH, cci_timer3, cci_async, qdss_gpio10, reserved24, NA,
- NA, NA, NA, NA),
- PINGROUP(25, SOUTH, cci_timer4, cci_async, qdss_gpio11, reserved25, NA,
- NA, NA, NA, NA),
- PINGROUP(26, SOUTH, cci_async, qdss_gpio12, reserved26, NA, NA, NA, NA,
- NA, NA),
- PINGROUP(27, NORTH, qup2, qdss_gpio13, reserved27, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(28, NORTH, qup2, qdss_gpio14, reserved28, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(29, NORTH, qup2, NA, phase_flag1, qdss_gpio15, reserved29, NA,
- NA, NA, NA),
- PINGROUP(30, NORTH, qup2, phase_flag2, qdss_gpio, reserved30, NA, NA,
- NA, NA, NA),
- PINGROUP(31, NORTH, qup11, qup14, reserved31, NA, NA, NA, NA, NA, NA),
- PINGROUP(32, NORTH, qup11, qup14, NA, reserved32, NA, NA, NA, NA, NA),
- PINGROUP(33, NORTH, qup11, qup14, NA, reserved33, NA, NA, NA, NA, NA),
- PINGROUP(34, NORTH, qup11, qup14, NA, reserved34, NA, NA, NA, NA, NA),
- PINGROUP(35, SOUTH, pci_e0, qup_l4, jitter_bist, NA, reserved35, NA,
- NA, NA, NA),
- PINGROUP(36, SOUTH, pci_e0, qup_l5, pll_bist, NA, atest_tsens,
- reserved36, NA, NA, NA),
- PINGROUP(37, SOUTH, qup_l6, agera_pll, NA, reserved37, NA, NA, NA, NA,
- NA),
- PINGROUP(38, NORTH, usb_phy, NA, reserved38, NA, NA, NA, NA, NA, NA),
- PINGROUP(39, NORTH, lpass_slimbus, NA, reserved39, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(40, SOUTH, sd_write, tsif1_error, NA, reserved40, NA, NA, NA,
- NA, NA),
- PINGROUP(41, SOUTH, qup3, NA, qdss_gpio6, reserved41, NA, NA, NA, NA,
- NA),
- PINGROUP(42, SOUTH, qup3, NA, qdss_gpio7, reserved42, NA, NA, NA, NA,
- NA),
- PINGROUP(43, SOUTH, qup3, NA, qdss_gpio14, reserved43, NA, NA, NA, NA,
- NA),
- PINGROUP(44, SOUTH, qup3, NA, qdss_gpio15, reserved44, NA, NA, NA, NA,
- NA),
- PINGROUP(45, NORTH, qup6, NA, reserved45, NA, NA, NA, NA, NA, NA),
- PINGROUP(46, NORTH, qup6, NA, reserved46, NA, NA, NA, NA, NA, NA),
- PINGROUP(47, NORTH, qup6, reserved47, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(48, NORTH, qup6, reserved48, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(49, NORTH, qup12, reserved49, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(50, NORTH, qup12, reserved50, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(51, NORTH, qup12, qdss_cti, reserved51, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(52, NORTH, qup12, phase_flag16, qdss_cti, reserved52, NA, NA,
- NA, NA, NA),
- PINGROUP(53, NORTH, qup10, phase_flag11, reserved53, NA, NA, NA, NA,
- NA, NA),
- PINGROUP(54, NORTH, qup10, NA, phase_flag12, reserved54, NA, NA, NA,
- NA, NA),
- PINGROUP(55, NORTH, qup10, phase_flag13, reserved55, NA, NA, NA, NA,
- NA, NA),
- PINGROUP(56, NORTH, qup10, phase_flag17, reserved56, NA, NA, NA, NA,
- NA, NA),
- PINGROUP(57, NORTH, qua_mi2s, gcc_gp1, phase_flag18, reserved57, NA,
- NA, NA, NA, NA),
- PINGROUP(58, NORTH, qua_mi2s, gcc_gp2, phase_flag19, reserved58, NA,
- NA, NA, NA, NA),
- PINGROUP(59, NORTH, qua_mi2s, gcc_gp3, phase_flag20, reserved59, NA,
- NA, NA, NA, NA),
- PINGROUP(60, NORTH, qua_mi2s, cri_trng0, phase_flag21, reserved60, NA,
- NA, NA, NA, NA),
- PINGROUP(61, NORTH, qua_mi2s, cri_trng1, phase_flag22, reserved61, NA,
- NA, NA, NA, NA),
- PINGROUP(62, NORTH, qua_mi2s, cri_trng, phase_flag23, qdss_cti,
- reserved62, NA, NA, NA, NA),
- PINGROUP(63, NORTH, qua_mi2s, NA, phase_flag24, qdss_cti, reserved63,
- NA, NA, NA, NA),
- PINGROUP(64, NORTH, pri_mi2s, sp_cmu, phase_flag25, reserved64, NA, NA,
- NA, NA, NA),
- PINGROUP(65, NORTH, pri_mi2s, qup8, reserved65, NA, NA, NA, NA, NA, NA),
- PINGROUP(66, NORTH, pri_mi2s_ws, qup8, reserved66, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(67, NORTH, pri_mi2s, qup8, reserved67, NA, NA, NA, NA, NA, NA),
- PINGROUP(68, NORTH, pri_mi2s, qup8, reserved68, NA, NA, NA, NA, NA, NA),
- PINGROUP(69, NORTH, spkr_i2s, audio_ref, reserved69, NA, NA, NA, NA,
- NA, NA),
- PINGROUP(70, NORTH, lpass_slimbus, spkr_i2s, reserved70, NA, NA, NA,
- NA, NA, NA),
- PINGROUP(71, NORTH, lpass_slimbus, spkr_i2s, tsense_pwm1, tsense_pwm2,
- reserved71, NA, NA, NA, NA),
- PINGROUP(72, NORTH, lpass_slimbus, spkr_i2s, reserved72, NA, NA, NA,
- NA, NA, NA),
- PINGROUP(73, NORTH, btfm_slimbus, atest_usb2, reserved73, NA, NA, NA,
- NA, NA, NA),
- PINGROUP(74, NORTH, btfm_slimbus, ter_mi2s, phase_flag7, atest_usb23,
- reserved74, NA, NA, NA, NA),
- PINGROUP(75, NORTH, ter_mi2s, phase_flag8, qdss_gpio8, atest_usb22,
- reserved75, NA, NA, NA, NA),
- PINGROUP(76, NORTH, ter_mi2s, phase_flag9, qdss_gpio9, atest_usb21,
- reserved76, NA, NA, NA, NA),
- PINGROUP(77, NORTH, ter_mi2s, phase_flag4, qdss_gpio10, atest_usb20,
- reserved77, NA, NA, NA, NA),
- PINGROUP(78, NORTH, ter_mi2s, gcc_gp1, reserved78, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(79, NORTH, sec_mi2s, NA, NA, qdss_gpio11, reserved79, NA, NA,
- NA, NA),
- PINGROUP(80, NORTH, sec_mi2s, NA, qdss_gpio12, reserved80, NA, NA, NA,
- NA, NA),
- PINGROUP(81, NORTH, sec_mi2s, qup15, NA, reserved81, NA, NA, NA, NA,
- NA),
- PINGROUP(82, NORTH, sec_mi2s, qup15, NA, reserved82, NA, NA, NA, NA,
- NA),
- PINGROUP(83, NORTH, sec_mi2s, qup15, NA, reserved83, NA, NA, NA, NA,
- NA),
- PINGROUP(84, NORTH, qup15, NA, reserved84, NA, NA, NA, NA, NA, NA),
- PINGROUP(85, SOUTH, qup5, NA, reserved85, NA, NA, NA, NA, NA, NA),
- PINGROUP(86, SOUTH, qup5, NA, NA, reserved86, NA, NA, NA, NA, NA),
- PINGROUP(87, SOUTH, qup5, NA, reserved87, NA, NA, NA, NA, NA, NA),
- PINGROUP(88, SOUTH, qup5, NA, reserved88, NA, NA, NA, NA, NA, NA),
- PINGROUP(89, SOUTH, tsif1_clk, qup4, tgu_ch3, phase_flag10, reserved89,
- NA, NA, NA, NA),
- PINGROUP(90, SOUTH, tsif1_en, mdp_vsync0, qup4, mdp_vsync1, mdp_vsync2,
- mdp_vsync3, tgu_ch0, phase_flag0, qdss_cti),
- PINGROUP(91, SOUTH, tsif1_data, sdc4_cmd, qup4, tgu_ch1, NA, qdss_cti,
- reserved91, NA, NA),
- PINGROUP(92, SOUTH, tsif2_error, sdc43, qup4, vfr_1, tgu_ch2, NA,
- reserved92, NA, NA),
- PINGROUP(93, SOUTH, tsif2_clk, sdc4_clk, qup7, NA, qdss_gpio13,
- reserved93, NA, NA, NA),
- PINGROUP(94, SOUTH, tsif2_en, sdc42, qup7, NA, reserved94, NA, NA, NA,
- NA),
- PINGROUP(95, SOUTH, tsif2_data, sdc41, qup7, NA, NA, reserved95, NA,
- NA, NA),
- PINGROUP(96, SOUTH, tsif2_sync, sdc40, qup7, phase_flag3, reserved96,
- NA, NA, NA, NA),
- PINGROUP(97, NORTH, NA, NA, mdp_vsync, ldo_en, reserved97, NA, NA, NA,
- NA),
- PINGROUP(98, NORTH, NA, mdp_vsync, ldo_update, reserved98, NA, NA, NA,
- NA, NA),
- PINGROUP(99, NORTH, phase_flag14, reserved99, NA, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(100, NORTH, phase_flag15, reserved100, NA, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(101, NORTH, NA, reserved101, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(102, NORTH, pci_e1, prng_rosc, reserved102, NA, NA, NA, NA,
- NA, NA),
- PINGROUP(103, NORTH, pci_e1, phase_flag5, reserved103, NA, NA, NA, NA,
- NA, NA),
- PINGROUP(104, NORTH, NA, reserved104, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(105, NORTH, uim2_data, qup13, qup_l4, NA, reserved105, NA, NA,
- NA, NA),
- PINGROUP(106, NORTH, uim2_clk, qup13, qup_l5, NA, reserved106, NA, NA,
- NA, NA),
- PINGROUP(107, NORTH, uim2_reset, qup13, qup_l6, reserved107, NA, NA,
- NA, NA, NA),
- PINGROUP(108, NORTH, uim2_present, qup13, reserved108, NA, NA, NA, NA,
- NA, NA),
- PINGROUP(109, NORTH, uim1_data, reserved109, NA, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(110, NORTH, uim1_clk, reserved110, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(111, NORTH, uim1_reset, reserved111, NA, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(112, NORTH, uim1_present, reserved112, NA, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(113, NORTH, uim_batt, edp_hot, reserved113, NA, NA, NA, NA,
- NA, NA),
- PINGROUP(114, NORTH, NA, nav_pps, nav_pps, NA, NA, reserved114, NA, NA,
- NA),
- PINGROUP(115, NORTH, NA, nav_pps, nav_pps, NA, NA, reserved115, NA, NA,
- NA),
- PINGROUP(116, NORTH, NA, reserved116, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(117, NORTH, NA, qdss_gpio0, atest_char, reserved117, NA, NA,
- NA, NA, NA),
- PINGROUP(118, NORTH, adsp_ext, NA, qdss_gpio1, atest_char3,
- reserved118, NA, NA, NA, NA),
- PINGROUP(119, NORTH, NA, qdss_gpio2, atest_char2, reserved119, NA, NA,
- NA, NA, NA),
- PINGROUP(120, NORTH, NA, qdss_gpio3, atest_char1, reserved120, NA, NA,
- NA, NA, NA),
- PINGROUP(121, NORTH, NA, qdss_gpio4, atest_char0, reserved121, NA, NA,
- NA, NA, NA),
- PINGROUP(122, NORTH, NA, qdss_gpio5, reserved122, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(123, NORTH, qup_l4, NA, qdss_gpio, reserved123, NA, NA, NA,
- NA, NA),
- PINGROUP(124, NORTH, qup_l5, NA, qdss_gpio, reserved124, NA, NA, NA,
- NA, NA),
- PINGROUP(125, NORTH, qup_l6, NA, reserved125, NA, NA, NA, NA, NA, NA),
- PINGROUP(126, NORTH, NA, reserved126, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(127, NORTH, NA, reserved127, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(128, NORTH, nav_pps, nav_pps, NA, NA, reserved128, NA, NA, NA,
- NA),
- PINGROUP(129, NORTH, nav_pps, nav_pps, NA, NA, reserved129, NA, NA, NA,
- NA),
- PINGROUP(130, NORTH, qlink_request, NA, reserved130, NA, NA, NA, NA,
- NA, NA),
- PINGROUP(131, NORTH, qlink_enable, NA, reserved131, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(132, NORTH, NA, NA, reserved132, NA, NA, NA, NA, NA, NA),
- PINGROUP(133, NORTH, NA, reserved133, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(134, NORTH, NA, reserved134, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(135, NORTH, NA, pa_indicator, NA, reserved135, NA, NA, NA, NA,
- NA),
- PINGROUP(136, NORTH, NA, reserved136, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(137, NORTH, NA, NA, phase_flag26, reserved137, NA, NA, NA, NA,
- NA),
- PINGROUP(138, NORTH, NA, NA, phase_flag27, reserved138, NA, NA, NA, NA,
- NA),
- PINGROUP(139, NORTH, NA, phase_flag28, reserved139, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(140, NORTH, NA, NA, phase_flag6, reserved140, NA, NA, NA, NA,
- NA),
- PINGROUP(141, NORTH, NA, phase_flag29, reserved141, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(142, NORTH, NA, phase_flag30, reserved142, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(143, NORTH, NA, nav_pps, nav_pps, NA, phase_flag31,
- reserved143, NA, NA, NA),
- PINGROUP(144, NORTH, mss_lte, reserved144, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(145, NORTH, mss_lte, NA, reserved145, NA, NA, NA, NA, NA, NA),
- PINGROUP(146, NORTH, NA, NA, reserved146, NA, NA, NA, NA, NA, NA),
- PINGROUP(147, NORTH, NA, NA, reserved147, NA, NA, NA, NA, NA, NA),
- PINGROUP(148, NORTH, NA, reserved148, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(149, NORTH, NA, reserved149, NA, NA, NA, NA, NA, NA, NA),
- SDC_QDSD_PINGROUP(sdc2_clk, 0x99a000, 14, 6),
- SDC_QDSD_PINGROUP(sdc2_cmd, 0x99a000, 11, 3),
- SDC_QDSD_PINGROUP(sdc2_data, 0x99a000, 9, 0),
- UFS_RESET(ufs_reset, 0x99f000),
+ [0] = PINGROUP(0, qup0, NA, NA, NA, NA, NA, NA, NA, NA),
+ [1] = PINGROUP(1, qup0, NA, NA, NA, NA, NA, NA, NA, NA),
+ [2] = PINGROUP(2, qup0, NA, NA, NA, NA, NA, NA, NA, NA),
+ [3] = PINGROUP(3, qup0, NA, NA, NA, NA, NA, NA, NA, NA),
+ [4] = PINGROUP(4, qup9, qdss_cti, NA, NA, NA, NA, NA, NA, NA),
+ [5] = PINGROUP(5, qup9, qdss_cti, NA, NA, NA, NA, NA, NA, NA),
+ [6] = PINGROUP(6, qup9, NA, ddr_pxi0, NA, NA, NA, NA, NA, NA),
+ [7] = PINGROUP(7, qup9, ddr_bist, NA, atest_tsens2,
+ vsense_trigger, atest_usb1, ddr_pxi0, NA, NA),
+ [8] = PINGROUP(8, qup_l4, NA, ddr_bist, NA, NA, wlan1_adc1,
+ atest_usb13, ddr_pxi1, NA),
+ [9] = PINGROUP(9, qup_l5, ddr_bist, NA, wlan1_adc0, atest_usb12,
+ ddr_pxi1, NA, NA, NA),
+ [10] = PINGROUP(10, mdp_vsync, qup_l6, ddr_bist, wlan2_adc1,
+ atest_usb11, ddr_pxi2, NA, NA, NA),
+ [11] = PINGROUP(11, mdp_vsync, edp_lcd, dbg_out, wlan2_adc0,
+ atest_usb10, ddr_pxi2, NA, NA, NA),
+ [12] = PINGROUP(12, mdp_vsync, m_voc, tsif1_sync, ddr_pxi3, NA,
+ NA, NA, NA, NA),
+ [13] = PINGROUP(13, cam_mclk, pll_bypassnl, qdss_gpio0,
+ ddr_pxi3, NA, NA, NA, NA, NA),
+ [14] = PINGROUP(14, cam_mclk, pll_reset, qdss_gpio1, NA, NA, NA,
+ NA, NA, NA),
+ [15] = PINGROUP(15, cam_mclk, qdss_gpio2, NA, NA, NA, NA, NA,
+ NA, NA),
+ [16] = PINGROUP(16, cam_mclk, qdss_gpio3, NA, NA, NA, NA, NA,
+ NA, NA),
+ [17] = PINGROUP(17, cci_i2c, qup1, qdss_gpio4, NA, NA, NA, NA,
+ NA, NA),
+ [18] = PINGROUP(18, cci_i2c, qup1, NA, qdss_gpio5, NA, NA, NA,
+ NA, NA),
+ [19] = PINGROUP(19, cci_i2c, qup1, NA, qdss_gpio6, NA, NA, NA,
+ NA, NA),
+ [20] = PINGROUP(20, cci_i2c, qup1, NA, qdss_gpio7, NA, NA, NA,
+ NA, NA),
+ [21] = PINGROUP(21, cci_timer0, gcc_gp2, qdss_gpio8, NA, NA, NA,
+ NA, NA, NA),
+ [22] = PINGROUP(22, cci_timer1, gcc_gp3, qdss_gpio, NA, NA, NA,
+ NA, NA, NA),
+ [23] = PINGROUP(23, cci_timer2, qdss_gpio9, NA, NA, NA, NA, NA,
+ NA, NA),
+ [24] = PINGROUP(24, cci_timer3, cci_async, qdss_gpio10, NA, NA,
+ NA, NA, NA, NA),
+ [25] = PINGROUP(25, cci_timer4, cci_async, qdss_gpio11, NA, NA,
+ NA, NA, NA, NA),
+ [26] = PINGROUP(26, cci_async, qdss_gpio12, NA, NA, NA, NA, NA,
+ NA, NA),
+ [27] = PINGROUP(27, qup2, qdss_gpio13, NA, NA, NA, NA, NA, NA,
+ NA),
+ [28] = PINGROUP(28, qup2, qdss_gpio14, NA, NA, NA, NA, NA, NA,
+ NA),
+ [29] = PINGROUP(29, qup2, NA, phase_flag1, qdss_gpio15, NA, NA,
+ NA, NA, NA),
+ [30] = PINGROUP(30, qup2, phase_flag2, qdss_gpio, NA, NA, NA, NA,
+ NA, NA),
+ [31] = PINGROUP(31, qup11, qup14, NA, NA, NA, NA, NA, NA, NA),
+ [32] = PINGROUP(32, qup11, qup14, NA, NA, NA, NA, NA, NA, NA),
+ [33] = PINGROUP(33, qup11, qup14, NA, NA, NA, NA, NA, NA, NA),
+ [34] = PINGROUP(34, qup11, qup14, NA, NA, NA, NA, NA, NA, NA),
+ [35] = PINGROUP(35, pci_e0, qup_l4, jitter_bist, NA, NA, NA, NA,
+ NA, NA),
+ [36] = PINGROUP(36, pci_e0, qup_l5, pll_bist, NA, atest_tsens,
+ NA, NA, NA, NA),
+ [37] = PINGROUP(37, qup_l6, agera_pll, NA, NA, NA, NA, NA, NA,
+ NA),
+ [38] = PINGROUP(38, usb_phy, NA, NA, NA, NA, NA, NA, NA, NA),
+ [39] = PINGROUP(39, lpass_slimbus, NA, NA, NA, NA, NA, NA, NA,
+ NA),
+ [40] = PINGROUP(40, sd_write, tsif1_error, NA, NA, NA, NA, NA,
+ NA, NA),
+ [41] = PINGROUP(41, qup3, NA, qdss_gpio6, NA, NA, NA, NA, NA, NA),
+ [42] = PINGROUP(42, qup3, NA, qdss_gpio7, NA, NA, NA, NA, NA, NA),
+ [43] = PINGROUP(43, qup3, NA, qdss_gpio14, NA, NA, NA, NA, NA,
+ NA),
+ [44] = PINGROUP(44, qup3, NA, qdss_gpio15, NA, NA, NA, NA, NA,
+ NA),
+ [45] = PINGROUP(45, qup6, NA, NA, NA, NA, NA, NA, NA, NA),
+ [46] = PINGROUP(46, qup6, NA, NA, NA, NA, NA, NA, NA, NA),
+ [47] = PINGROUP(47, qup6, NA, NA, NA, NA, NA, NA, NA, NA),
+ [48] = PINGROUP(48, qup6, NA, NA, NA, NA, NA, NA, NA, NA),
+ [49] = PINGROUP(49, qup12, NA, NA, NA, NA, NA, NA, NA, NA),
+ [50] = PINGROUP(50, qup12, NA, NA, NA, NA, NA, NA, NA, NA),
+ [51] = PINGROUP(51, qup12, qdss_cti, NA, NA, NA, NA, NA, NA, NA),
+ [52] = PINGROUP(52, qup12, phase_flag16, qdss_cti, NA, NA, NA,
+ NA, NA, NA),
+ [53] = PINGROUP(53, qup10, phase_flag11, NA, NA, NA, NA, NA, NA,
+ NA),
+ [54] = PINGROUP(54, qup10, NA, phase_flag12, NA, NA, NA, NA, NA,
+ NA),
+ [55] = PINGROUP(55, qup10, phase_flag13, NA, NA, NA, NA, NA, NA,
+ NA),
+ [56] = PINGROUP(56, qup10, phase_flag17, NA, NA, NA, NA, NA, NA,
+ NA),
+ [57] = PINGROUP(57, qua_mi2s, gcc_gp1, phase_flag18, NA, NA, NA,
+ NA, NA, NA),
+ [58] = PINGROUP(58, qua_mi2s, gcc_gp2, phase_flag19, NA, NA, NA,
+ NA, NA, NA),
+ [59] = PINGROUP(59, qua_mi2s, gcc_gp3, phase_flag20, NA, NA, NA,
+ NA, NA, NA),
+ [60] = PINGROUP(60, qua_mi2s, cri_trng0, phase_flag21, NA, NA,
+ NA, NA, NA, NA),
+ [61] = PINGROUP(61, qua_mi2s, cri_trng1, phase_flag22, NA, NA,
+ NA, NA, NA, NA),
+ [62] = PINGROUP(62, qua_mi2s, cri_trng, phase_flag23, qdss_cti,
+ NA, NA, NA, NA, NA),
+ [63] = PINGROUP(63, qua_mi2s, NA, phase_flag24, qdss_cti, NA,
+ NA, NA, NA, NA),
+ [64] = PINGROUP(64, pri_mi2s, sp_cmu, phase_flag25, NA, NA, NA,
+ NA, NA, NA),
+ [65] = PINGROUP(65, pri_mi2s, qup8, NA, NA, NA, NA, NA, NA, NA),
+ [66] = PINGROUP(66, pri_mi2s_ws, qup8, NA, NA, NA, NA, NA, NA,
+ NA),
+ [67] = PINGROUP(67, pri_mi2s, qup8, NA, NA, NA, NA, NA, NA, NA),
+ [68] = PINGROUP(68, pri_mi2s, qup8, NA, NA, NA, NA, NA, NA, NA),
+ [69] = PINGROUP(69, spkr_i2s, audio_ref, NA, NA, NA, NA, NA, NA,
+ NA),
+ [70] = PINGROUP(70, lpass_slimbus, spkr_i2s, NA, NA, NA, NA, NA,
+ NA, NA),
+ [71] = PINGROUP(71, lpass_slimbus, spkr_i2s, tsense_pwm1,
+ tsense_pwm2, NA, NA, NA, NA, NA),
+ [72] = PINGROUP(72, lpass_slimbus, spkr_i2s, NA, NA, NA, NA, NA,
+ NA, NA),
+ [73] = PINGROUP(73, btfm_slimbus, atest_usb2, NA, NA, NA, NA, NA,
+ NA, NA),
+ [74] = PINGROUP(74, btfm_slimbus, ter_mi2s, phase_flag7,
+ atest_usb23, NA, NA, NA, NA, NA),
+ [75] = PINGROUP(75, ter_mi2s, phase_flag8, qdss_gpio8,
+ atest_usb22, NA, NA, NA, NA, NA),
+ [76] = PINGROUP(76, ter_mi2s, phase_flag9, qdss_gpio9,
+ atest_usb21, NA, NA, NA, NA, NA),
+ [77] = PINGROUP(77, ter_mi2s, phase_flag4, qdss_gpio10,
+ atest_usb20, NA, NA, NA, NA, NA),
+ [78] = PINGROUP(78, ter_mi2s, gcc_gp1, NA, NA, NA, NA, NA, NA,
+ NA),
+ [79] = PINGROUP(79, sec_mi2s, NA, NA, qdss_gpio11, NA, NA, NA,
+ NA, NA),
+ [80] = PINGROUP(80, sec_mi2s, NA, qdss_gpio12, NA, NA, NA, NA,
+ NA, NA),
+ [81] = PINGROUP(81, sec_mi2s, qup15, NA, NA, NA, NA, NA, NA, NA),
+ [82] = PINGROUP(82, sec_mi2s, qup15, NA, NA, NA, NA, NA, NA, NA),
+ [83] = PINGROUP(83, sec_mi2s, qup15, NA, NA, NA, NA, NA, NA, NA),
+ [84] = PINGROUP(84, qup15, NA, NA, NA, NA, NA, NA, NA, NA),
+ [85] = PINGROUP(85, qup5, NA, NA, NA, NA, NA, NA, NA, NA),
+ [86] = PINGROUP(86, qup5, NA, NA, NA, NA, NA, NA, NA, NA),
+ [87] = PINGROUP(87, qup5, NA, NA, NA, NA, NA, NA, NA, NA),
+ [88] = PINGROUP(88, qup5, NA, NA, NA, NA, NA, NA, NA, NA),
+ [89] = PINGROUP(89, tsif1_clk, qup4, tgu_ch3, phase_flag10, NA,
+ NA, NA, NA, NA),
+ [90] = PINGROUP(90, tsif1_en, mdp_vsync0, qup4, mdp_vsync1,
+ mdp_vsync2, mdp_vsync3, tgu_ch0, phase_flag0, qdss_cti),
+ [91] = PINGROUP(91, tsif1_data, sdc4_cmd, qup4, tgu_ch1, NA,
+ qdss_cti, NA, NA, NA),
+ [92] = PINGROUP(92, tsif2_error, sdc43, qup4, vfr_1, tgu_ch2,
+ NA, NA, NA, NA),
+ [93] = PINGROUP(93, tsif2_clk, sdc4_clk, qup7, NA, qdss_gpio13,
+ NA, NA, NA, NA),
+ [94] = PINGROUP(94, tsif2_en, sdc42, qup7, NA, NA, NA, NA, NA,
+ NA),
+ [95] = PINGROUP(95, tsif2_data, sdc41, qup7, NA, NA, NA, NA, NA,
+ NA),
+ [96] = PINGROUP(96, tsif2_sync, sdc40, qup7, phase_flag3, NA,
+ NA, NA, NA, NA),
+ [97] = PINGROUP(97, NA, NA, mdp_vsync, ldo_en, NA, NA, NA, NA,
+ NA),
+ [98] = PINGROUP(98, NA, mdp_vsync, ldo_update, NA, NA, NA, NA,
+ NA, NA),
+ [99] = PINGROUP(99, phase_flag14, NA, NA, NA, NA, NA, NA, NA,
+ NA),
+ [100] = PINGROUP(100, phase_flag15, NA, NA, NA, NA, NA, NA, NA,
+ NA),
+ [101] = PINGROUP(101, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [102] = PINGROUP(102, pci_e1, prng_rosc, NA, NA, NA, NA, NA, NA,
+ NA),
+ [103] = PINGROUP(103, pci_e1, phase_flag5, NA, NA, NA, NA, NA,
+ NA, NA),
+ [104] = PINGROUP(104, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [105] = PINGROUP(105, uim2_data, qup13, qup_l4, NA, NA, NA, NA,
+ NA, NA),
+ [106] = PINGROUP(106, uim2_clk, qup13, qup_l5, NA, NA, NA, NA,
+ NA, NA),
+ [107] = PINGROUP(107, uim2_reset, qup13, qup_l6, NA, NA, NA, NA,
+ NA, NA),
+ [108] = PINGROUP(108, uim2_present, qup13, NA, NA, NA, NA, NA,
+ NA, NA),
+ [109] = PINGROUP(109, uim1_data, NA, NA, NA, NA, NA, NA, NA, NA),
+ [110] = PINGROUP(110, uim1_clk, NA, NA, NA, NA, NA, NA, NA, NA),
+ [111] = PINGROUP(111, uim1_reset, NA, NA, NA, NA, NA, NA, NA,
+ NA),
+ [112] = PINGROUP(112, uim1_present, NA, NA, NA, NA, NA, NA, NA,
+ NA),
+ [113] = PINGROUP(113, uim_batt, edp_hot, NA, NA, NA, NA, NA, NA,
+ NA),
+ [114] = PINGROUP(114, NA, nav_pps, nav_pps, NA, NA, NA, NA, NA,
+ NA),
+ [115] = PINGROUP(115, NA, nav_pps, nav_pps, NA, NA, NA, NA, NA,
+ NA),
+ [116] = PINGROUP(116, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [117] = PINGROUP(117, NA, qdss_gpio0, atest_char, NA, NA, NA,
+ NA, NA, NA),
+ [118] = PINGROUP(118, adsp_ext, NA, qdss_gpio1, atest_char3, NA,
+ NA, NA, NA, NA),
+ [119] = PINGROUP(119, NA, qdss_gpio2, atest_char2, NA, NA, NA,
+ NA, NA, NA),
+ [120] = PINGROUP(120, NA, qdss_gpio3, atest_char1, NA, NA, NA,
+ NA, NA, NA),
+ [121] = PINGROUP(121, NA, qdss_gpio4, atest_char0, NA, NA, NA,
+ NA, NA, NA),
+ [122] = PINGROUP(122, NA, qdss_gpio5, NA, NA, NA, NA, NA, NA, NA),
+ [123] = PINGROUP(123, qup_l4, NA, qdss_gpio, NA, NA, NA, NA, NA,
+ NA),
+ [124] = PINGROUP(124, qup_l5, NA, qdss_gpio, NA, NA, NA, NA, NA,
+ NA),
+ [125] = PINGROUP(125, qup_l6, NA, NA, NA, NA, NA, NA, NA, NA),
+ [126] = PINGROUP(126, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [127] = PINGROUP(127, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [128] = PINGROUP(128, nav_pps, nav_pps, NA, NA, NA, NA, NA, NA,
+ NA),
+ [129] = PINGROUP(129, nav_pps, nav_pps, NA, NA, NA, NA, NA, NA,
+ NA),
+ [130] = PINGROUP(130, qlink_request, NA, NA, NA, NA, NA, NA, NA,
+ NA),
+ [131] = PINGROUP(131, qlink_enable, NA, NA, NA, NA, NA, NA, NA,
+ NA),
+ [132] = PINGROUP(132, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [133] = PINGROUP(133, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [134] = PINGROUP(134, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [135] = PINGROUP(135, NA, pa_indicator, NA, NA, NA, NA, NA, NA,
+ NA),
+ [136] = PINGROUP(136, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [137] = PINGROUP(137, NA, NA, phase_flag26, NA, NA, NA, NA, NA,
+ NA),
+ [138] = PINGROUP(138, NA, NA, phase_flag27, NA, NA, NA, NA, NA,
+ NA),
+ [139] = PINGROUP(139, NA, phase_flag28, NA, NA, NA, NA, NA, NA,
+ NA),
+ [140] = PINGROUP(140, NA, NA, phase_flag6, NA, NA, NA, NA, NA,
+ NA),
+ [141] = PINGROUP(141, NA, phase_flag29, NA, NA, NA, NA, NA, NA,
+ NA),
+ [142] = PINGROUP(142, NA, phase_flag30, NA, NA, NA, NA, NA, NA,
+ NA),
+ [143] = PINGROUP(143, NA, nav_pps, nav_pps, NA, phase_flag31,
+ NA, NA, NA, NA),
+ [144] = PINGROUP(144, mss_lte, NA, NA, NA, NA, NA, NA, NA, NA),
+ [145] = PINGROUP(145, mss_lte, NA, NA, NA, NA, NA, NA, NA, NA),
+ [146] = PINGROUP(146, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [147] = PINGROUP(147, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [148] = PINGROUP(148, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [149] = PINGROUP(149, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [150] = SDC_QDSD_PINGROUP(sdc2_clk, 0x99a000, 14, 6),
+ [151] = SDC_QDSD_PINGROUP(sdc2_cmd, 0x99a000, 11, 3),
+ [152] = SDC_QDSD_PINGROUP(sdc2_data, 0x99a000, 9, 0),
+ [153] = UFS_RESET(ufs_reset, 0x99f000),
};
static const struct msm_dir_conn sdm845_dir_conn[] = {
@@ -2465,6 +1714,10 @@
.ngpios = 150,
.dir_conn = sdm845_dir_conn,
.n_dir_conns = ARRAY_SIZE(sdm845_dir_conn),
+ .tile_offsets = sdm845_tile_offsets,
+ .n_tile_offsets = ARRAY_SIZE(sdm845_tile_offsets),
+ .pin_base = sdm845_pin_base,
+ .reg_size = REG_SIZE,
};
static int sdm845_pinctrl_probe(struct platform_device *pdev)
diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig
index e5fe6ba..aef0db2 100644
--- a/drivers/platform/msm/Kconfig
+++ b/drivers/platform/msm/Kconfig
@@ -178,4 +178,11 @@
module is used to configure and read the configuration from the
Serial Engines.
+config MSM_EXT_DISPLAY
+ bool "MSM External Display Driver"
+ help
+ Enabling this option adds MSM External Display Driver.
+ External Display driver was added to support the communication
+ between external display driver and its counterparts.
+
endmenu
diff --git a/drivers/platform/msm/Makefile b/drivers/platform/msm/Makefile
index ff1d0e2..27179b9 100644
--- a/drivers/platform/msm/Makefile
+++ b/drivers/platform/msm/Makefile
@@ -12,3 +12,4 @@
obj-$(CONFIG_MSM_11AD) += msm_11ad/
obj-$(CONFIG_SEEMP_CORE) += seemp_core/
obj-$(CONFIG_QCOM_GENI_SE) += qcom-geni-se.o
+obj-$(CONFIG_MSM_EXT_DISPLAY) += msm_ext_display.o
diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c
index 9c133a8..7718257 100644
--- a/drivers/platform/msm/gsi/gsi.c
+++ b/drivers/platform/msm/gsi/gsi.c
@@ -1947,6 +1947,20 @@
res = wait_for_completion_timeout(&ctx->compl,
msecs_to_jiffies(GSI_STOP_CMD_TIMEOUT_MS));
if (res == 0) {
+ /*
+ * check channel state here in case the channel is stopped but
+ * the interrupt was not handled yet.
+ */
+ val = gsi_readl(gsi_ctx->base +
+ GSI_EE_n_GSI_CH_k_CNTXT_0_OFFS(chan_hdl,
+ gsi_ctx->per.ee));
+ ctx->state = (val &
+ GSI_EE_n_GSI_CH_k_CNTXT_0_CHSTATE_BMSK) >>
+ GSI_EE_n_GSI_CH_k_CNTXT_0_CHSTATE_SHFT;
+ if (ctx->state == GSI_CHAN_STATE_STOPPED) {
+ res = GSI_STATUS_SUCCESS;
+ goto free_lock;
+ }
GSIDBG("chan_hdl=%lu timed out\n", chan_hdl);
res = -GSI_STATUS_TIMED_OUT;
goto free_lock;
diff --git a/drivers/platform/msm/ipa/ipa_api.c b/drivers/platform/msm/ipa/ipa_api.c
index 9f417bb..4a9232e 100644
--- a/drivers/platform/msm/ipa/ipa_api.c
+++ b/drivers/platform/msm/ipa/ipa_api.c
@@ -2582,6 +2582,21 @@
EXPORT_SYMBOL(ipa_stop_gsi_channel);
/**
+ * ipa_start_gsi_channel()- Startsa GSI channel in IPA
+ *
+ * Return value: 0 on success, negative otherwise
+ */
+int ipa_start_gsi_channel(u32 clnt_hdl)
+{
+ int ret;
+
+ IPA_API_DISPATCH_RETURN(ipa_start_gsi_channel, clnt_hdl);
+
+ return ret;
+}
+EXPORT_SYMBOL(ipa_start_gsi_channel);
+
+/**
* ipa_get_version_string() - Get string representation of IPA version
* @ver: IPA version
*
diff --git a/drivers/platform/msm/ipa/ipa_api.h b/drivers/platform/msm/ipa/ipa_api.h
index 133e058..20471eb 100644
--- a/drivers/platform/msm/ipa/ipa_api.h
+++ b/drivers/platform/msm/ipa/ipa_api.h
@@ -324,6 +324,8 @@
int (*ipa_stop_gsi_channel)(u32 clnt_hdl);
+ int (*ipa_start_gsi_channel)(u32 clnt_hdl);
+
struct iommu_domain *(*ipa_get_smmu_domain)(void);
int (*ipa_disable_apps_wan_cons_deaggr)(uint32_t agg_size,
diff --git a/drivers/platform/msm/ipa/ipa_clients/odu_bridge.c b/drivers/platform/msm/ipa/ipa_clients/odu_bridge.c
index 79da63e..a623d0b 100644
--- a/drivers/platform/msm/ipa/ipa_clients/odu_bridge.c
+++ b/drivers/platform/msm/ipa/ipa_clients/odu_bridge.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, The Linux Foundation. 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 and
@@ -114,6 +114,7 @@
* @send_dl_skb: client callback for sending skb in downlink direction
* @stats: statistics, how many packets were transmitted using the SW bridge
* @is_conencted: is bridge connected ?
+ * @is_suspended: is bridge suspended ?
* @mode: ODU mode (router/bridge)
* @lock: for the initialization, connect and disconnect synchronization
* @llv6_addr: link local IPv6 address of ODU network interface
@@ -122,6 +123,8 @@
* @odu_prod_hdl: handle for IPA_CLIENT_ODU_PROD pipe
* @odu_emb_cons_hdl: handle for IPA_CLIENT_ODU_EMB_CONS pipe
* @odu_teth_cons_hdl: handle for IPA_CLIENT_ODU_TETH_CONS pipe
+ * @rm_comp: completion object for IP RM
+ * @wakeup_request: client callback to wakeup
*/
struct odu_bridge_ctx {
struct class *class;
@@ -135,6 +138,7 @@
int (*send_dl_skb)(void *priv, struct sk_buff *skb);
struct stats stats;
bool is_connected;
+ bool is_suspended;
enum odu_bridge_mode mode;
struct mutex lock;
struct in6_addr llv6_addr;
@@ -146,6 +150,8 @@
u32 ipa_sys_desc_size;
void *logbuf;
void *logbuf_low;
+ struct completion rm_comp;
+ void (*wakeup_request)(void *);
};
static struct odu_bridge_ctx *odu_bridge_ctx;
@@ -1246,6 +1252,288 @@
}
EXPORT_SYMBOL(odu_bridge_cleanup);
+/* IPA Bridge implementation */
+#ifdef CONFIG_IPA3
+
+static void ipa_br_rm_notify(void *user_data, enum ipa_rm_event event,
+ unsigned long data)
+{
+ if (event == IPA_RM_RESOURCE_GRANTED)
+ complete(&odu_bridge_ctx->rm_comp);
+}
+
+static int ipa_br_request_prod(void)
+{
+ int res;
+
+ ODU_BRIDGE_FUNC_ENTRY();
+
+ reinit_completion(&odu_bridge_ctx->rm_comp);
+ ODU_BRIDGE_DBG("requesting odu prod\n");
+ res = ipa_rm_request_resource(IPA_RM_RESOURCE_ODU_ADAPT_PROD);
+ if (res) {
+ if (res != -EINPROGRESS) {
+ ODU_BRIDGE_ERR("failed to request prod %d\n", res);
+ return res;
+ }
+ wait_for_completion(&odu_bridge_ctx->rm_comp);
+ }
+
+ ODU_BRIDGE_FUNC_EXIT();
+ return 0;
+
+}
+
+static int ipa_br_release_prod(void)
+{
+ int res;
+
+ ODU_BRIDGE_FUNC_ENTRY();
+
+ reinit_completion(&odu_bridge_ctx->rm_comp);
+ ODU_BRIDGE_DBG("requesting odu prod\n");
+ res = ipa_rm_release_resource(IPA_RM_RESOURCE_ODU_ADAPT_PROD);
+ if (res) {
+ ODU_BRIDGE_ERR("failed to release prod %d\n", res);
+ return res;
+ }
+
+ ODU_BRIDGE_FUNC_EXIT();
+ return 0;
+
+}
+
+static int ipa_br_cons_request(void)
+{
+ ODU_BRIDGE_FUNC_ENTRY();
+ if (odu_bridge_ctx->is_suspended)
+ odu_bridge_ctx->wakeup_request(odu_bridge_ctx->priv);
+ ODU_BRIDGE_FUNC_EXIT();
+ return 0;
+}
+
+static int ipa_br_cons_release(void)
+{
+ ODU_BRIDGE_FUNC_ENTRY();
+ ODU_BRIDGE_FUNC_EXIT();
+ return 0;
+}
+
+/* IPA Bridge API is the new API which will replaces old odu_bridge API */
+int ipa_bridge_init(struct ipa_bridge_init_params *params, u32 *hdl)
+{
+ int ret;
+ struct ipa_rm_create_params create_params;
+
+ if (!params || !params->wakeup_request || !hdl) {
+ ODU_BRIDGE_ERR("NULL arg\n");
+ return -EINVAL;
+ }
+
+
+ ret = odu_bridge_init(¶ms->info);
+ if (ret)
+ return ret;
+
+ odu_bridge_ctx->wakeup_request = params->wakeup_request;
+
+ /* create IPA RM resources for power management */
+ init_completion(&odu_bridge_ctx->rm_comp);
+ memset(&create_params, 0, sizeof(create_params));
+ create_params.name = IPA_RM_RESOURCE_ODU_ADAPT_PROD;
+ create_params.reg_params.user_data = odu_bridge_ctx;
+ create_params.reg_params.notify_cb = ipa_br_rm_notify;
+ create_params.floor_voltage = IPA_VOLTAGE_SVS;
+ ret = ipa_rm_create_resource(&create_params);
+ if (ret) {
+ ODU_BRIDGE_ERR("failed to create RM prod %d\n", ret);
+ goto fail_rm_prod;
+ }
+
+ ret = ipa_rm_add_dependency_sync(IPA_RM_RESOURCE_ODU_ADAPT_PROD,
+ IPA_RM_RESOURCE_APPS_CONS);
+ if (ret) {
+ ODU_BRIDGE_ERR("failed to add ODU->APPS dependency %d\n", ret);
+ goto fail_add_dep;
+ }
+
+ memset(&create_params, 0, sizeof(create_params));
+ create_params.name = IPA_RM_RESOURCE_ODU_ADAPT_CONS;
+ create_params.request_resource = ipa_br_cons_request;
+ create_params.release_resource = ipa_br_cons_release;
+ create_params.floor_voltage = IPA_VOLTAGE_SVS;
+ ret = ipa_rm_create_resource(&create_params);
+ if (ret) {
+ ODU_BRIDGE_ERR("failed to create RM cons %d\n", ret);
+ goto fail_rm_cons;
+ }
+
+ /* handle is ignored for now */
+ *hdl = 0;
+
+ return 0;
+
+fail_rm_cons:
+ ipa_rm_delete_dependency(IPA_RM_RESOURCE_ODU_ADAPT_PROD,
+ IPA_RM_RESOURCE_APPS_CONS);
+fail_add_dep:
+ ipa_rm_delete_resource(IPA_RM_RESOURCE_ODU_ADAPT_PROD);
+fail_rm_prod:
+ odu_bridge_cleanup();
+ return ret;
+}
+EXPORT_SYMBOL(ipa_bridge_init);
+
+int ipa_bridge_connect(u32 hdl)
+{
+ int ret;
+
+ if (!odu_bridge_ctx) {
+ ODU_BRIDGE_ERR("Not initialized\n");
+ return -EFAULT;
+ }
+
+ if (odu_bridge_ctx->is_connected) {
+ ODU_BRIDGE_ERR("already connected\n");
+ return -EFAULT;
+ }
+
+ ret = ipa_br_request_prod();
+ if (ret)
+ return ret;
+
+ return odu_bridge_connect();
+}
+EXPORT_SYMBOL(ipa_bridge_connect);
+
+int ipa_bridge_set_perf_profile(u32 hdl, u32 bandwidth)
+{
+ struct ipa_rm_perf_profile profile = {0};
+ int ret;
+
+ profile.max_supported_bandwidth_mbps = bandwidth;
+ ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_ODU_ADAPT_PROD, &profile);
+ if (ret) {
+ ODU_BRIDGE_ERR("failed to set perf profile to prod %d\n", ret);
+ return ret;
+ }
+
+ ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_ODU_ADAPT_CONS, &profile);
+ if (ret) {
+ ODU_BRIDGE_ERR("failed to set perf profile to cons %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(ipa_bridge_set_perf_profile);
+
+int ipa_bridge_disconnect(u32 hdl)
+{
+ int ret;
+
+ ret = odu_bridge_disconnect();
+ if (ret)
+ return ret;
+
+ ret = ipa_br_release_prod();
+ if (ret)
+ return ret;
+
+ return 0;
+}
+EXPORT_SYMBOL(ipa_bridge_disconnect);
+
+int ipa_bridge_suspend(u32 hdl)
+{
+ int ret;
+
+ if (!odu_bridge_ctx) {
+ ODU_BRIDGE_ERR("Not initialized\n");
+ return -EFAULT;
+ }
+
+ if (!odu_bridge_ctx->is_connected) {
+ ODU_BRIDGE_ERR("bridge is disconnected\n");
+ return -EFAULT;
+ }
+
+ if (odu_bridge_ctx->is_suspended) {
+ ODU_BRIDGE_ERR("bridge is already suspended\n");
+ return -EFAULT;
+ }
+
+ /* stop cons channel to prevent downlink data during suspend */
+ ret = ipa_stop_gsi_channel(odu_bridge_ctx->odu_emb_cons_hdl);
+ if (ret) {
+ ODU_BRIDGE_ERR("failed to stop CONS channel %d\n", ret);
+ return ret;
+ }
+
+ ret = ipa_br_release_prod();
+ if (ret) {
+ ODU_BRIDGE_ERR("failed to release prod %d\n", ret);
+ ipa_start_gsi_channel(odu_bridge_ctx->odu_emb_cons_hdl);
+ return ret;
+ }
+ odu_bridge_ctx->is_suspended = true;
+
+ return 0;
+}
+EXPORT_SYMBOL(ipa_bridge_suspend);
+
+int ipa_bridge_resume(u32 hdl)
+{
+ int ret;
+
+ if (!odu_bridge_ctx) {
+ ODU_BRIDGE_ERR("Not initialized\n");
+ return -EFAULT;
+ }
+
+ if (!odu_bridge_ctx->is_connected) {
+ ODU_BRIDGE_ERR("bridge is disconnected\n");
+ return -EFAULT;
+ }
+
+ if (!odu_bridge_ctx->is_suspended) {
+ ODU_BRIDGE_ERR("bridge is not suspended\n");
+ return -EFAULT;
+ }
+
+ ret = ipa_br_request_prod();
+ if (ret)
+ return ret;
+
+ ret = ipa_start_gsi_channel(odu_bridge_ctx->odu_emb_cons_hdl);
+ if (ret) {
+ ODU_BRIDGE_ERR("failed to start CONS channel %d\n", ret);
+ return ret;
+ }
+ odu_bridge_ctx->is_suspended = false;
+
+ return 0;
+}
+EXPORT_SYMBOL(ipa_bridge_resume);
+
+int ipa_bridge_tx_dp(u32 hdl, struct sk_buff *skb,
+ struct ipa_tx_meta *metadata)
+{
+ return odu_bridge_tx_dp(skb, metadata);
+}
+EXPORT_SYMBOL(ipa_bridge_tx_dp);
+
+int ipa_bridge_cleanup(u32 hdl)
+{
+ ipa_rm_delete_dependency(IPA_RM_RESOURCE_ODU_ADAPT_PROD,
+ IPA_RM_RESOURCE_APPS_CONS);
+ ipa_rm_delete_resource(IPA_RM_RESOURCE_ODU_ADAPT_PROD);
+ ipa_rm_delete_resource(IPA_RM_RESOURCE_ODU_ADAPT_CONS);
+ return odu_bridge_cleanup();
+}
+EXPORT_SYMBOL(ipa_bridge_cleanup);
+
+#endif /* CONFIG_IPA3 */
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("ODU bridge driver");
diff --git a/drivers/platform/msm/ipa/ipa_common_i.h b/drivers/platform/msm/ipa/ipa_common_i.h
index 07bca0c..32c8b25 100644
--- a/drivers/platform/msm/ipa/ipa_common_i.h
+++ b/drivers/platform/msm/ipa/ipa_common_i.h
@@ -384,5 +384,6 @@
void *user_data);
void ipa_ntn_uc_dereg_rdyCB(void);
const char *ipa_get_version_string(enum ipa_hw_type ver);
+int ipa_start_gsi_channel(u32 clnt_hdl);
#endif /* _IPA_COMMON_I_H_ */
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa.c b/drivers/platform/msm/ipa/ipa_v2/ipa.c
index 53ab299..bfd0446 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa.c
@@ -641,7 +641,7 @@
/* add check in case user-space module compromised */
if (unlikely(((struct ipa_ioc_nat_dma_cmd *)param)->entries
!= pre_entry)) {
- IPAERR("current %d pre %d\n",
+ IPAERR_RL("current %d pre %d\n",
((struct ipa_ioc_nat_dma_cmd *)param)->entries,
pre_entry);
retval = -EFAULT;
@@ -688,7 +688,7 @@
/* add check in case user-space module compromised */
if (unlikely(((struct ipa_ioc_add_hdr *)param)->num_hdrs
!= pre_entry)) {
- IPAERR("current %d pre %d\n",
+ IPAERR_RL("current %d pre %d\n",
((struct ipa_ioc_add_hdr *)param)->num_hdrs,
pre_entry);
retval = -EFAULT;
@@ -727,7 +727,7 @@
/* add check in case user-space module compromised */
if (unlikely(((struct ipa_ioc_del_hdr *)param)->num_hdls
!= pre_entry)) {
- IPAERR("current %d pre %d\n",
+ IPAERR_RL("current %d pre %d\n",
((struct ipa_ioc_del_hdr *)param)->num_hdls,
pre_entry);
retval = -EFAULT;
@@ -767,7 +767,7 @@
/* add check in case user-space module compromised */
if (unlikely(((struct ipa_ioc_add_rt_rule *)param)->num_rules
!= pre_entry)) {
- IPAERR("current %d pre %d\n",
+ IPAERR_RL("current %d pre %d\n",
((struct ipa_ioc_add_rt_rule *)param)->
num_rules,
pre_entry);
@@ -807,7 +807,7 @@
/* add check in case user-space module compromised */
if (unlikely(((struct ipa_ioc_mdfy_rt_rule *)param)->num_rules
!= pre_entry)) {
- IPAERR("current %d pre %d\n",
+ IPAERR_RL("current %d pre %d\n",
((struct ipa_ioc_mdfy_rt_rule *)param)->
num_rules,
pre_entry);
@@ -847,7 +847,7 @@
/* add check in case user-space module compromised */
if (unlikely(((struct ipa_ioc_del_rt_rule *)param)->num_hdls
!= pre_entry)) {
- IPAERR("current %d pre %d\n",
+ IPAERR_RL("current %d pre %d\n",
((struct ipa_ioc_del_rt_rule *)param)->num_hdls,
pre_entry);
retval = -EFAULT;
@@ -886,7 +886,7 @@
/* add check in case user-space module compromised */
if (unlikely(((struct ipa_ioc_add_flt_rule *)param)->num_rules
!= pre_entry)) {
- IPAERR("current %d pre %d\n",
+ IPAERR_RL("current %d pre %d\n",
((struct ipa_ioc_add_flt_rule *)param)->
num_rules,
pre_entry);
@@ -926,7 +926,7 @@
/* add check in case user-space module compromised */
if (unlikely(((struct ipa_ioc_del_flt_rule *)param)->num_hdls
!= pre_entry)) {
- IPAERR("current %d pre %d\n",
+ IPAERR_RL("current %d pre %d\n",
((struct ipa_ioc_del_flt_rule *)param)->
num_hdls,
pre_entry);
@@ -966,7 +966,7 @@
/* add check in case user-space module compromised */
if (unlikely(((struct ipa_ioc_mdfy_flt_rule *)param)->num_rules
!= pre_entry)) {
- IPAERR("current %d pre %d\n",
+ IPAERR_RL("current %d pre %d\n",
((struct ipa_ioc_mdfy_flt_rule *)param)->
num_rules,
pre_entry);
@@ -1104,7 +1104,7 @@
if (unlikely(((struct ipa_ioc_query_intf_tx_props *)
param)->num_tx_props
!= pre_entry)) {
- IPAERR("current %d pre %d\n",
+ IPAERR_RL("current %d pre %d\n",
((struct ipa_ioc_query_intf_tx_props *)
param)->num_tx_props, pre_entry);
retval = -EFAULT;
@@ -1149,7 +1149,7 @@
/* add check in case user-space module compromised */
if (unlikely(((struct ipa_ioc_query_intf_rx_props *)
param)->num_rx_props != pre_entry)) {
- IPAERR("current %d pre %d\n",
+ IPAERR_RL("current %d pre %d\n",
((struct ipa_ioc_query_intf_rx_props *)
param)->num_rx_props, pre_entry);
retval = -EFAULT;
@@ -1194,7 +1194,7 @@
/* add check in case user-space module compromised */
if (unlikely(((struct ipa_ioc_query_intf_ext_props *)
param)->num_ext_props != pre_entry)) {
- IPAERR("current %d pre %d\n",
+ IPAERR_RL("current %d pre %d\n",
((struct ipa_ioc_query_intf_ext_props *)
param)->num_ext_props, pre_entry);
retval = -EFAULT;
@@ -1232,7 +1232,7 @@
/* add check in case user-space module compromised */
if (unlikely(((struct ipa_msg_meta *)param)->msg_len
!= pre_entry)) {
- IPAERR("current %d pre %d\n",
+ IPAERR_RL("current %d pre %d\n",
((struct ipa_msg_meta *)param)->msg_len,
pre_entry);
retval = -EFAULT;
@@ -1372,7 +1372,7 @@
/* add check in case user-space module compromised */
if (unlikely(((struct ipa_ioc_add_hdr_proc_ctx *)
param)->num_proc_ctxs != pre_entry)) {
- IPAERR("current %d pre %d\n",
+ IPAERR_RL("current %d pre %d\n",
((struct ipa_ioc_add_hdr_proc_ctx *)
param)->num_proc_ctxs, pre_entry);
retval = -EFAULT;
@@ -1411,7 +1411,7 @@
/* add check in case user-space module compromised */
if (unlikely(((struct ipa_ioc_del_hdr_proc_ctx *)
param)->num_hdls != pre_entry)) {
- IPAERR("current %d pre %d\n",
+ IPAERR_RL("current %d pre %d\n",
((struct ipa_ioc_del_hdr_proc_ctx *)param)->
num_hdls,
pre_entry);
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c
index 8d9f0e0..f7b0864 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c
@@ -1015,25 +1015,25 @@
if (rule->action != IPA_PASS_TO_EXCEPTION) {
if (!rule->eq_attrib_type) {
if (!rule->rt_tbl_hdl) {
- IPAERR("invalid RT tbl\n");
+ IPAERR_RL("invalid RT tbl\n");
goto error;
}
rt_tbl = ipa_id_find(rule->rt_tbl_hdl);
if (rt_tbl == NULL) {
- IPAERR("RT tbl not found\n");
+ IPAERR_RL("RT tbl not found\n");
goto error;
}
if (rt_tbl->cookie != IPA_RT_TBL_COOKIE) {
- IPAERR("RT table cookie is invalid\n");
+ IPAERR_RL("RT table cookie is invalid\n");
goto error;
}
} else {
if (rule->rt_tbl_idx > ((ip == IPA_IP_v4) ?
IPA_MEM_PART(v4_modem_rt_index_hi) :
IPA_MEM_PART(v6_modem_rt_index_hi))) {
- IPAERR("invalid RT tbl\n");
+ IPAERR_RL("invalid RT tbl\n");
goto error;
}
}
@@ -1089,12 +1089,12 @@
entry = ipa_id_find(rule_hdl);
if (entry == NULL) {
- IPAERR("lookup failed\n");
+ IPAERR_RL("lookup failed\n");
return -EINVAL;
}
if (entry->cookie != IPA_FLT_COOKIE) {
- IPAERR("bad params\n");
+ IPAERR_RL("bad params\n");
return -EINVAL;
}
id = entry->id;
@@ -1121,12 +1121,12 @@
entry = ipa_id_find(frule->rule_hdl);
if (entry == NULL) {
- IPAERR("lookup failed\n");
+ IPAERR_RL("lookup failed\n");
goto error;
}
if (entry->cookie != IPA_FLT_COOKIE) {
- IPAERR("bad params\n");
+ IPAERR_RL("bad params\n");
goto error;
}
@@ -1136,25 +1136,25 @@
if (frule->rule.action != IPA_PASS_TO_EXCEPTION) {
if (!frule->rule.eq_attrib_type) {
if (!frule->rule.rt_tbl_hdl) {
- IPAERR("invalid RT tbl\n");
+ IPAERR_RL("invalid RT tbl\n");
goto error;
}
rt_tbl = ipa_id_find(frule->rule.rt_tbl_hdl);
if (rt_tbl == NULL) {
- IPAERR("RT tbl not found\n");
+ IPAERR_RL("RT tbl not found\n");
goto error;
}
if (rt_tbl->cookie != IPA_RT_TBL_COOKIE) {
- IPAERR("RT table cookie is invalid\n");
+ IPAERR_RL("RT table cookie is invalid\n");
goto error;
}
} else {
if (frule->rule.rt_tbl_idx > ((ip == IPA_IP_v4) ?
IPA_MEM_PART(v4_modem_rt_index_hi) :
IPA_MEM_PART(v6_modem_rt_index_hi))) {
- IPAERR("invalid RT tbl\n");
+ IPAERR_RL("invalid RT tbl\n");
goto error;
}
}
@@ -1178,7 +1178,7 @@
struct ipa_flt_tbl *tbl;
if (rule == NULL || rule_hdl == NULL) {
- IPAERR("bad parms rule=%p rule_hdl=%p\n", rule, rule_hdl);
+ IPAERR_RL("bad parms rule=%p rule_hdl=%p\n", rule, rule_hdl);
return -EINVAL;
}
@@ -1197,14 +1197,14 @@
int ipa_ep_idx;
if (rule == NULL || rule_hdl == NULL || ep >= IPA_CLIENT_MAX) {
- IPAERR("bad parms rule=%p rule_hdl=%p ep=%d\n", rule,
+ IPAERR_RL("bad parms rule=%p rule_hdl=%p ep=%d\n", rule,
rule_hdl, ep);
return -EINVAL;
}
ipa_ep_idx = ipa2_get_ep_mapping(ep);
if (ipa_ep_idx == IPA_FLT_TABLE_INDEX_NOT_FOUND) {
- IPAERR("ep not valid ep=%d\n", ep);
+ IPAERR_RL("ep not valid ep=%d\n", ep);
return -EINVAL;
}
if (ipa_ctx->ep[ipa_ep_idx].valid == 0)
@@ -1231,7 +1231,7 @@
if (rules == NULL || rules->num_rules == 0 ||
rules->ip >= IPA_IP_MAX) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
return -EINVAL;
}
@@ -1249,7 +1249,7 @@
rules->rules[i].at_rear,
&rules->rules[i].flt_rule_hdl);
if (result) {
- IPAERR("failed to add flt rule %d\n", i);
+ IPAERR_RL("failed to add flt rule %d\n", i);
rules->rules[i].status = IPA_FLT_STATUS_OF_ADD_FAILED;
} else {
rules->rules[i].status = 0;
@@ -1282,14 +1282,14 @@
int result;
if (hdls == NULL || hdls->num_hdls == 0 || hdls->ip >= IPA_IP_MAX) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
return -EINVAL;
}
mutex_lock(&ipa_ctx->lock);
for (i = 0; i < hdls->num_hdls; i++) {
if (__ipa_del_flt_rule(hdls->hdl[i].hdl)) {
- IPAERR("failed to del rt rule %i\n", i);
+ IPAERR_RL("failed to del rt rule %i\n", i);
hdls->hdl[i].status = IPA_FLT_STATUS_OF_DEL_FAILED;
} else {
hdls->hdl[i].status = 0;
@@ -1322,14 +1322,14 @@
int result;
if (hdls == NULL || hdls->num_rules == 0 || hdls->ip >= IPA_IP_MAX) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
return -EINVAL;
}
mutex_lock(&ipa_ctx->lock);
for (i = 0; i < hdls->num_rules; i++) {
if (__ipa_mdfy_flt_rule(&hdls->rules[i], hdls->ip)) {
- IPAERR("failed to mdfy rt rule %i\n", i);
+ IPAERR_RL("failed to mdfy rt rule %i\n", i);
hdls->rules[i].status = IPA_FLT_STATUS_OF_MDFY_FAILED;
} else {
hdls->rules[i].status = 0;
@@ -1363,7 +1363,7 @@
int result;
if (ip >= IPA_IP_MAX) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
return -EINVAL;
}
@@ -1399,7 +1399,7 @@
int id;
if (ip >= IPA_IP_MAX) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
return -EINVAL;
}
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c
index a6a7613..d4e39d7 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c
@@ -558,13 +558,13 @@
proc_ctx->type, proc_ctx->hdr_hdl);
if (!HDR_PROC_TYPE_IS_VALID(proc_ctx->type)) {
- IPAERR("invalid processing type %d\n", proc_ctx->type);
+ IPAERR_RL("invalid processing type %d\n", proc_ctx->type);
return -EINVAL;
}
hdr_entry = ipa_id_find(proc_ctx->hdr_hdl);
if (!hdr_entry || (hdr_entry->cookie != IPA_HDR_COOKIE)) {
- IPAERR("hdr_hdl is invalid\n");
+ IPAERR_RL("hdr_hdl is invalid\n");
return -EINVAL;
}
@@ -592,7 +592,7 @@
ipa_hdr_proc_ctx_bin_sz[IPA_HDR_PROC_CTX_BIN1]) {
bin = IPA_HDR_PROC_CTX_BIN1;
} else {
- IPAERR("unexpected needed len %d\n", needed_len);
+ IPAERR_RL("unexpected needed len %d\n", needed_len);
WARN_ON(1);
goto bad_len;
}
@@ -602,7 +602,7 @@
IPA_MEM_PART(apps_hdr_proc_ctx_size_ddr);
if (list_empty(&htbl->head_free_offset_list[bin])) {
if (htbl->end + ipa_hdr_proc_ctx_bin_sz[bin] > mem_size) {
- IPAERR("hdr proc ctx table overflow\n");
+ IPAERR_RL("hdr proc ctx table overflow\n");
goto bad_len;
}
@@ -649,8 +649,7 @@
return 0;
ipa_insert_failed:
- if (offset)
- list_move(&offset->link,
+ list_move(&offset->link,
&htbl->head_free_offset_list[offset->bin]);
entry->offset_entry = NULL;
list_del(&entry->link);
@@ -676,12 +675,12 @@
gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
if (hdr->hdr_len == 0 || hdr->hdr_len > IPA_HDR_MAX_SIZE) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
goto error;
}
if (!HDR_TYPE_IS_VALID(hdr->type)) {
- IPAERR("invalid hdr type %d\n", hdr->type);
+ IPAERR_RL("invalid hdr type %d\n", hdr->type);
goto error;
}
@@ -713,7 +712,7 @@
else if (hdr->hdr_len <= ipa_hdr_bin_sz[IPA_HDR_BIN4])
bin = IPA_HDR_BIN4;
else {
- IPAERR("unexpected hdr len %d\n", hdr->hdr_len);
+ IPAERR_RL("unexpected hdr len %d\n", hdr->hdr_len);
goto bad_hdr_len;
}
@@ -844,7 +843,7 @@
entry = ipa_id_find(proc_ctx_hdl);
if (!entry || (entry->cookie != IPA_PROC_HDR_COOKIE)) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
return -EINVAL;
}
@@ -852,7 +851,7 @@
htbl->proc_ctx_cnt, entry->offset_entry->offset);
if (by_user && entry->user_deleted) {
- IPAERR("proc_ctx already deleted by user\n");
+ IPAERR_RL("proc_ctx already deleted by user\n");
return -EINVAL;
}
@@ -890,12 +889,12 @@
entry = ipa_id_find(hdr_hdl);
if (entry == NULL) {
- IPAERR("lookup failed\n");
+ IPAERR_RL("lookup failed\n");
return -EINVAL;
}
if (entry->cookie != IPA_HDR_COOKIE) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
return -EINVAL;
}
@@ -907,7 +906,7 @@
htbl->hdr_cnt, entry->offset_entry->offset);
if (by_user && entry->user_deleted) {
- IPAERR("hdr already deleted by user\n");
+ IPAERR_RL("hdr already deleted by user\n");
return -EINVAL;
}
@@ -956,12 +955,12 @@
int result = -EFAULT;
if (unlikely(!ipa_ctx)) {
- IPAERR("IPA driver was not initialized\n");
+ IPAERR_RL("IPA driver was not initialized\n");
return -EINVAL;
}
if (hdrs == NULL || hdrs->num_hdrs == 0) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
return -EINVAL;
}
@@ -970,7 +969,7 @@
hdrs->num_hdrs);
for (i = 0; i < hdrs->num_hdrs; i++) {
if (__ipa_add_hdr(&hdrs->hdr[i])) {
- IPAERR("failed to add hdr %d\n", i);
+ IPAERR_RL("failed to add hdr %d\n", i);
hdrs->hdr[i].status = -1;
} else {
hdrs->hdr[i].status = 0;
@@ -1011,14 +1010,14 @@
}
if (hdls == NULL || hdls->num_hdls == 0) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
return -EINVAL;
}
mutex_lock(&ipa_ctx->lock);
for (i = 0; i < hdls->num_hdls; i++) {
if (__ipa_del_hdr(hdls->hdl[i].hdl, by_user)) {
- IPAERR("failed to del hdr %i\n", i);
+ IPAERR_RL("failed to del hdr %i\n", i);
hdls->hdl[i].status = -1;
} else {
hdls->hdl[i].status = 0;
@@ -1067,13 +1066,13 @@
if (ipa_ctx->ipa_hw_type <= IPA_HW_v2_0 ||
ipa_ctx->ipa_hw_type == IPA_HW_v2_6L) {
- IPAERR("Processing context not supported on IPA HW %d\n",
+ IPAERR_RL("Processing context not supported on IPA HW %d\n",
ipa_ctx->ipa_hw_type);
return -EFAULT;
}
if (proc_ctxs == NULL || proc_ctxs->num_proc_ctxs == 0) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
return -EINVAL;
}
@@ -1082,7 +1081,7 @@
proc_ctxs->num_proc_ctxs);
for (i = 0; i < proc_ctxs->num_proc_ctxs; i++) {
if (__ipa_add_hdr_proc_ctx(&proc_ctxs->proc_ctx[i], true)) {
- IPAERR("failed to add hdr pric ctx %d\n", i);
+ IPAERR_RL("failed to add hdr pric ctx %d\n", i);
proc_ctxs->proc_ctx[i].status = -1;
} else {
proc_ctxs->proc_ctx[i].status = 0;
@@ -1127,14 +1126,14 @@
}
if (hdls == NULL || hdls->num_hdls == 0) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
return -EINVAL;
}
mutex_lock(&ipa_ctx->lock);
for (i = 0; i < hdls->num_hdls; i++) {
if (__ipa_del_hdr_proc_ctx(hdls->hdl[i].hdl, true, by_user)) {
- IPAERR("failed to del hdr %i\n", i);
+ IPAERR_RL("failed to del hdr %i\n", i);
hdls->hdl[i].status = -1;
} else {
hdls->hdl[i].status = 0;
@@ -1371,7 +1370,7 @@
}
if (lookup == NULL) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
return -EINVAL;
}
mutex_lock(&ipa_ctx->lock);
@@ -1458,13 +1457,13 @@
entry = ipa_id_find(hdr_hdl);
if (entry == NULL) {
- IPAERR("lookup failed\n");
+ IPAERR_RL("lookup failed\n");
result = -EINVAL;
goto bail;
}
if (entry->cookie != IPA_HDR_COOKIE) {
- IPAERR("invalid header entry\n");
+ IPAERR_RL("invalid header entry\n");
result = -EINVAL;
goto bail;
}
@@ -1493,7 +1492,7 @@
int result = -EFAULT;
if (copy == NULL) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
return -EINVAL;
}
mutex_lock(&ipa_ctx->lock);
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
index 0c2410f..141bff1 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
@@ -68,6 +68,18 @@
#define IPAERR(fmt, args...) \
pr_err(DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args)
+#define IPAERR_RL(fmt, args...) \
+ do { \
+ pr_err_ratelimited(DRV_NAME " %s:%d " fmt, __func__, \
+ __LINE__, ## args);\
+ if (ipa_ctx) { \
+ IPA_IPC_LOGGING(ipa_ctx->logbuf, \
+ DRV_NAME " %s:%d " fmt, ## args); \
+ IPA_IPC_LOGGING(ipa_ctx->logbuf_low, \
+ DRV_NAME " %s:%d " fmt, ## args); \
+ } \
+ } while (0)
+
#define WLAN_AMPDU_TX_EP 15
#define WLAN_PROD_TX_EP 19
#define WLAN1_CONS_RX_EP 14
@@ -1730,9 +1742,6 @@
iowrite32(val, base + offset);
}
-int ipa_bridge_init(void);
-void ipa_bridge_cleanup(void);
-
ssize_t ipa_read(struct file *filp, char __user *buf, size_t count,
loff_t *f_pos);
int ipa_pull_msg(struct ipa_msg_meta *meta, char *buff, size_t count);
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c b/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c
index 12b1a99..e6954b7 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c
@@ -404,13 +404,13 @@
if (meta == NULL || (buff == NULL && callback != NULL) ||
(buff != NULL && callback == NULL)) {
- IPAERR("invalid param meta=%p buff=%p, callback=%p\n",
+ IPAERR_RL("invalid param meta=%p buff=%p, callback=%p\n",
meta, buff, callback);
return -EINVAL;
}
if (meta->msg_type >= IPA_EVENT_MAX_NUM) {
- IPAERR("unsupported message type %d\n", meta->msg_type);
+ IPAERR_RL("unsupported message type %d\n", meta->msg_type);
return -EINVAL;
}
@@ -633,7 +633,7 @@
int result = -EINVAL;
if (meta == NULL || buff == NULL || !count) {
- IPAERR("invalid param name=%p buff=%p count=%zu\n",
+ IPAERR_RL("invalid param name=%p buff=%p count=%zu\n",
meta, buff, count);
return result;
}
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_nat.c b/drivers/platform/msm/ipa/ipa_v2/ipa_nat.c
index a7f983e..50b2706 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_nat.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_nat.c
@@ -252,8 +252,8 @@
mutex_lock(&nat_ctx->lock);
if (strcmp(mem->dev_name, NAT_DEV_NAME)) {
- IPAERR("Nat device name mismatch\n");
- IPAERR("Expect: %s Recv: %s\n", NAT_DEV_NAME, mem->dev_name);
+ IPAERR_RL("Nat device name mismatch\n");
+ IPAERR_RL("Expect: %s Recv: %s\n", NAT_DEV_NAME, mem->dev_name);
result = -EPERM;
goto bail;
}
@@ -272,7 +272,7 @@
if (mem->size <= 0 ||
nat_ctx->is_dev_init == true) {
- IPAERR("Invalid Parameters or device is already init\n");
+ IPAERR_RL("Invalid Parameters or device is already init\n");
result = -EPERM;
goto bail;
}
@@ -335,8 +335,8 @@
/* check for integer overflow */
if (init->ipv4_rules_offset >
- UINT_MAX - (TBL_ENTRY_SIZE * (init->table_entries + 1))) {
- IPAERR("Detected overflow\n");
+ (UINT_MAX - (TBL_ENTRY_SIZE * (init->table_entries + 1)))) {
+ IPAERR_RL("Detected overflow\n");
return -EPERM;
}
/* Check Table Entry offset is not
@@ -345,8 +345,8 @@
tmp = init->ipv4_rules_offset +
(TBL_ENTRY_SIZE * (init->table_entries + 1));
if (tmp > ipa_ctx->nat_mem.size) {
- IPAERR("Table rules offset not valid\n");
- IPAERR("offset:%d entrys:%d size:%zu mem_size:%zu\n",
+ IPAERR_RL("Table rules offset not valid\n");
+ IPAERR_RL("offset:%d entrys:%d size:%zu mem_size:%zu\n",
init->ipv4_rules_offset, (init->table_entries + 1),
tmp, ipa_ctx->nat_mem.size);
return -EPERM;
@@ -355,7 +355,7 @@
/* check for integer overflow */
if (init->expn_rules_offset >
UINT_MAX - (TBL_ENTRY_SIZE * init->expn_table_entries)) {
- IPAERR("Detected overflow\n");
+ IPAERR_RL("Detected overflow\n");
return -EPERM;
}
/* Check Expn Table Entry offset is not
@@ -364,8 +364,8 @@
tmp = init->expn_rules_offset +
(TBL_ENTRY_SIZE * init->expn_table_entries);
if (tmp > ipa_ctx->nat_mem.size) {
- IPAERR("Expn Table rules offset not valid\n");
- IPAERR("offset:%d entrys:%d size:%zu mem_size:%zu\n",
+ IPAERR_RL("Expn Table rules offset not valid\n");
+ IPAERR_RL("offset:%d entrys:%d size:%zu mem_size:%zu\n",
init->expn_rules_offset, init->expn_table_entries,
tmp, ipa_ctx->nat_mem.size);
return -EPERM;
@@ -374,7 +374,7 @@
/* check for integer overflow */
if (init->index_offset >
UINT_MAX - (INDX_TBL_ENTRY_SIZE * (init->table_entries + 1))) {
- IPAERR("Detected overflow\n");
+ IPAERR_RL("Detected overflow\n");
return -EPERM;
}
/* Check Indx Table Entry offset is not
@@ -383,8 +383,8 @@
tmp = init->index_offset +
(INDX_TBL_ENTRY_SIZE * (init->table_entries + 1));
if (tmp > ipa_ctx->nat_mem.size) {
- IPAERR("Indx Table rules offset not valid\n");
- IPAERR("offset:%d entrys:%d size:%zu mem_size:%zu\n",
+ IPAERR_RL("Indx Table rules offset not valid\n");
+ IPAERR_RL("offset:%d entrys:%d size:%zu mem_size:%zu\n",
init->index_offset, (init->table_entries + 1),
tmp, ipa_ctx->nat_mem.size);
return -EPERM;
@@ -392,8 +392,8 @@
/* check for integer overflow */
if (init->index_expn_offset >
- UINT_MAX - (INDX_TBL_ENTRY_SIZE * init->expn_table_entries)) {
- IPAERR("Detected overflow\n");
+ (UINT_MAX - (INDX_TBL_ENTRY_SIZE * init->expn_table_entries))) {
+ IPAERR_RL("Detected overflow\n");
return -EPERM;
}
/* Check Expn Table entry offset is not
@@ -402,8 +402,8 @@
tmp = init->index_expn_offset +
(INDX_TBL_ENTRY_SIZE * init->expn_table_entries);
if (tmp > ipa_ctx->nat_mem.size) {
- IPAERR("Indx Expn Table rules offset not valid\n");
- IPAERR("offset:%d entrys:%d size:%zu mem_size:%zu\n",
+ IPAERR_RL("Indx Expn Table rules offset not valid\n");
+ IPAERR_RL("offset:%d entrys:%d size:%zu mem_size:%zu\n",
init->index_expn_offset, init->expn_table_entries,
tmp, ipa_ctx->nat_mem.size);
return -EPERM;
@@ -448,16 +448,16 @@
(init->expn_rules_offset > offset) ||
(init->index_offset > offset) ||
(init->index_expn_offset > offset)) {
- IPAERR("Failed due to integer overflow\n");
- IPAERR("nat.mem.dma_handle: 0x%pa\n",
+ IPAERR_RL("Failed due to integer overflow\n");
+ IPAERR_RL("nat.mem.dma_handle: 0x%pa\n",
&ipa_ctx->nat_mem.dma_handle);
- IPAERR("ipv4_rules_offset: 0x%x\n",
+ IPAERR_RL("ipv4_rules_offset: 0x%x\n",
init->ipv4_rules_offset);
- IPAERR("expn_rules_offset: 0x%x\n",
+ IPAERR_RL("expn_rules_offset: 0x%x\n",
init->expn_rules_offset);
- IPAERR("index_offset: 0x%x\n",
+ IPAERR_RL("index_offset: 0x%x\n",
init->index_offset);
- IPAERR("index_expn_offset: 0x%x\n",
+ IPAERR_RL("index_expn_offset: 0x%x\n",
init->index_expn_offset);
result = -EPERM;
goto free_mem;
@@ -513,7 +513,7 @@
desc[1].len = size;
IPADBG("posting v4 init command\n");
if (ipa_send_cmd(2, desc)) {
- IPAERR("Fail to send immediate command\n");
+ IPAERR_RL("Fail to send immediate command\n");
result = -EPERM;
goto free_mem;
}
@@ -578,7 +578,7 @@
IPADBG("\n");
if (dma->entries <= 0) {
- IPAERR("Invalid number of commands %d\n",
+ IPAERR_RL("Invalid number of commands %d\n",
dma->entries);
ret = -EPERM;
goto bail;
@@ -586,7 +586,7 @@
for (cnt = 0; cnt < dma->entries; cnt++) {
if (dma->dma[cnt].table_index >= 1) {
- IPAERR("Invalid table index %d\n",
+ IPAERR_RL("Invalid table index %d\n",
dma->dma[cnt].table_index);
ret = -EPERM;
goto bail;
@@ -597,7 +597,7 @@
if (dma->dma[cnt].offset >=
(ipa_ctx->nat_mem.size_base_tables + 1) *
NAT_TABLE_ENTRY_SIZE_BYTE) {
- IPAERR("Invalid offset %d\n",
+ IPAERR_RL("Invalid offset %d\n",
dma->dma[cnt].offset);
ret = -EPERM;
goto bail;
@@ -609,7 +609,7 @@
if (dma->dma[cnt].offset >=
ipa_ctx->nat_mem.size_expansion_tables *
NAT_TABLE_ENTRY_SIZE_BYTE) {
- IPAERR("Invalid offset %d\n",
+ IPAERR_RL("Invalid offset %d\n",
dma->dma[cnt].offset);
ret = -EPERM;
goto bail;
@@ -621,7 +621,7 @@
if (dma->dma[cnt].offset >=
(ipa_ctx->nat_mem.size_base_tables + 1) *
NAT_INTEX_TABLE_ENTRY_SIZE_BYTE) {
- IPAERR("Invalid offset %d\n",
+ IPAERR_RL("Invalid offset %d\n",
dma->dma[cnt].offset);
ret = -EPERM;
goto bail;
@@ -633,7 +633,7 @@
if (dma->dma[cnt].offset >=
ipa_ctx->nat_mem.size_expansion_tables *
NAT_INTEX_TABLE_ENTRY_SIZE_BYTE) {
- IPAERR("Invalid offset %d\n",
+ IPAERR_RL("Invalid offset %d\n",
dma->dma[cnt].offset);
ret = -EPERM;
goto bail;
@@ -642,7 +642,7 @@
break;
default:
- IPAERR("Invalid base_addr %d\n",
+ IPAERR_RL("Invalid base_addr %d\n",
dma->dma[cnt].base_addr);
ret = -EPERM;
goto bail;
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
index 1faa795..50930d3 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
@@ -850,7 +850,7 @@
struct ipa_rt_tbl *entry;
if (in->ip >= IPA_IP_MAX) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
return -EINVAL;
}
@@ -942,12 +942,12 @@
u32 id;
if (entry == NULL || (entry->cookie != IPA_RT_TBL_COOKIE)) {
- IPAERR("bad parms\n");
+ IPAERR_RL("bad parms\n");
return -EINVAL;
}
id = entry->id;
if (ipa_id_find(id) == NULL) {
- IPAERR("lookup failed\n");
+ IPAERR_RL("lookup failed\n");
return -EPERM;
}
@@ -1086,7 +1086,7 @@
int ret;
if (rules == NULL || rules->num_rules == 0 || rules->ip >= IPA_IP_MAX) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
return -EINVAL;
}
@@ -1096,7 +1096,7 @@
&rules->rules[i].rule,
rules->rules[i].at_rear,
&rules->rules[i].rt_rule_hdl)) {
- IPAERR("failed to add rt rule %d\n", i);
+ IPAERR_RL("failed to add rt rule %d\n", i);
rules->rules[i].status = IPA_RT_STATUS_OF_ADD_FAILED;
} else {
rules->rules[i].status = 0;
@@ -1123,12 +1123,12 @@
entry = ipa_id_find(rule_hdl);
if (entry == NULL) {
- IPAERR("lookup failed\n");
+ IPAERR_RL("lookup failed\n");
return -EINVAL;
}
if (entry->cookie != IPA_RT_RULE_COOKIE) {
- IPAERR("bad params\n");
+ IPAERR_RL("bad params\n");
return -EINVAL;
}
@@ -1142,7 +1142,7 @@
entry->tbl->rule_cnt);
if (entry->tbl->rule_cnt == 0 && entry->tbl->ref_cnt == 0) {
if (__ipa_del_rt_tbl(entry->tbl))
- IPAERR("fail to del RT tbl\n");
+ IPAERR_RL("fail to del RT tbl\n");
}
entry->cookie = 0;
id = entry->id;
@@ -1169,14 +1169,14 @@
int ret;
if (hdls == NULL || hdls->num_hdls == 0 || hdls->ip >= IPA_IP_MAX) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
return -EINVAL;
}
mutex_lock(&ipa_ctx->lock);
for (i = 0; i < hdls->num_hdls; i++) {
if (__ipa_del_rt_rule(hdls->hdl[i].hdl)) {
- IPAERR("failed to del rt rule %i\n", i);
+ IPAERR_RL("failed to del rt rule %i\n", i);
hdls->hdl[i].status = IPA_RT_STATUS_OF_DEL_FAILED;
} else {
hdls->hdl[i].status = 0;
@@ -1209,7 +1209,7 @@
int ret;
if (ip >= IPA_IP_MAX) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
return -EINVAL;
}
@@ -1253,7 +1253,7 @@
int id;
if (ip >= IPA_IP_MAX) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
return -EINVAL;
}
@@ -1271,7 +1271,7 @@
* filtering rules point to routing tables
*/
if (ipa2_reset_flt(ip))
- IPAERR("fail to reset flt ip=%d\n", ip);
+ IPAERR_RL("fail to reset flt ip=%d\n", ip);
set = &ipa_ctx->rt_tbl_set[ip];
rset = &ipa_ctx->reap_rt_tbl_set[ip];
@@ -1357,21 +1357,27 @@
int result = -EFAULT;
if (lookup == NULL || lookup->ip >= IPA_IP_MAX) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
return -EINVAL;
}
mutex_lock(&ipa_ctx->lock);
entry = __ipa_find_rt_tbl(lookup->ip, lookup->name);
if (entry && entry->cookie == IPA_RT_TBL_COOKIE) {
+ if (entry->ref_cnt == U32_MAX) {
+ IPAERR("fail: ref count crossed limit\n");
+ goto ret;
+ }
entry->ref_cnt++;
lookup->hdl = entry->id;
/* commit for get */
if (ipa_ctx->ctrl->ipa_commit_rt(lookup->ip))
- IPAERR("fail to commit RT tbl\n");
+ IPAERR_RL("fail to commit RT tbl\n");
result = 0;
}
+
+ret:
mutex_unlock(&ipa_ctx->lock);
return result;
@@ -1389,18 +1395,18 @@
{
struct ipa_rt_tbl *entry;
enum ipa_ip_type ip = IPA_IP_MAX;
- int result;
+ int result = 0;
mutex_lock(&ipa_ctx->lock);
entry = ipa_id_find(rt_tbl_hdl);
if (entry == NULL) {
- IPAERR("lookup failed\n");
+ IPAERR_RL("lookup failed\n");
result = -EINVAL;
goto ret;
}
if ((entry->cookie != IPA_RT_TBL_COOKIE) || entry->ref_cnt == 0) {
- IPAERR("bad parms\n");
+ IPAERR_RL("bad parms\n");
result = -EINVAL;
goto ret;
}
@@ -1418,10 +1424,10 @@
entry->ref_cnt--;
if (entry->ref_cnt == 0 && entry->rule_cnt == 0) {
if (__ipa_del_rt_tbl(entry))
- IPAERR("fail to del RT tbl\n");
+ IPAERR_RL("fail to del RT tbl\n");
/* commit for put */
if (ipa_ctx->ctrl->ipa_commit_rt(ip))
- IPAERR("fail to commit RT tbl\n");
+ IPAERR_RL("fail to commit RT tbl\n");
}
result = 0;
@@ -1441,19 +1447,19 @@
if (rtrule->rule.hdr_hdl) {
hdr = ipa_id_find(rtrule->rule.hdr_hdl);
if ((hdr == NULL) || (hdr->cookie != IPA_HDR_COOKIE)) {
- IPAERR("rt rule does not point to valid hdr\n");
+ IPAERR_RL("rt rule does not point to valid hdr\n");
goto error;
}
}
entry = ipa_id_find(rtrule->rt_rule_hdl);
if (entry == NULL) {
- IPAERR("lookup failed\n");
+ IPAERR_RL("lookup failed\n");
goto error;
}
if (entry->cookie != IPA_RT_RULE_COOKIE) {
- IPAERR("bad params\n");
+ IPAERR_RL("bad params\n");
goto error;
}
@@ -1486,14 +1492,14 @@
int result;
if (hdls == NULL || hdls->num_rules == 0 || hdls->ip >= IPA_IP_MAX) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
return -EINVAL;
}
mutex_lock(&ipa_ctx->lock);
for (i = 0; i < hdls->num_rules; i++) {
if (__ipa_mdfy_rt_rule(&hdls->rules[i])) {
- IPAERR("failed to mdfy rt rule %i\n", i);
+ IPAERR_RL("failed to mdfy rt rule %i\n", i);
hdls->rules[i].status = IPA_RT_STATUS_OF_MDFY_FAILED;
} else {
hdls->rules[i].status = 0;
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c
index b7815cb..a454382 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c
@@ -1673,7 +1673,7 @@
if (clnt_hdl >= ipa_ctx->ipa_num_pipes ||
ipa_ctx->ep[clnt_hdl].valid == 0) {
- IPAERR("bad parm, %d\n", clnt_hdl);
+ IPAERR_RL("bad parm, %d\n", clnt_hdl);
return -EINVAL;
}
@@ -1686,7 +1686,7 @@
ep = &ipa_ctx->ep[clnt_hdl];
if (!(ep->uc_offload_state & IPA_WDI_CONNECTED)) {
- IPAERR("WDI channel bad state %d\n", ep->uc_offload_state);
+ IPAERR_RL("WDI channel bad state %d\n", ep->uc_offload_state);
return -EFAULT;
}
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
index b133f9c..2c88244 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
@@ -847,7 +847,7 @@
}
if (client >= IPA_CLIENT_MAX || client < 0) {
- IPAERR("Bad client number! client =%d\n", client);
+ IPAERR_RL("Bad client number! client =%d\n", client);
return INVALID_EP_MAPPING_INDEX;
}
@@ -1700,7 +1700,7 @@
if (attrib->attrib_mask & IPA_FLT_NEXT_HDR ||
attrib->attrib_mask & IPA_FLT_TC || attrib->attrib_mask &
IPA_FLT_FLOW_LABEL) {
- IPAERR("v6 attrib's specified for v4 rule\n");
+ IPAERR_RL("v6 attrib's specified for v4 rule\n");
return -EPERM;
}
@@ -1712,7 +1712,7 @@
if (attrib->attrib_mask & IPA_FLT_TOS_MASKED) {
if (ipa_ofst_meq32[ofst_meq32] == -1) {
- IPAERR("ran out of meq32 eq\n");
+ IPAERR_RL("ran out of meq32 eq\n");
return -EPERM;
}
*en_rule |= ipa_ofst_meq32[ofst_meq32];
@@ -1732,7 +1732,7 @@
if (attrib->attrib_mask & IPA_FLT_SRC_ADDR) {
if (ipa_ofst_meq32[ofst_meq32] == -1) {
- IPAERR("ran out of meq32 eq\n");
+ IPAERR_RL("ran out of meq32 eq\n");
return -EPERM;
}
*en_rule |= ipa_ofst_meq32[ofst_meq32];
@@ -1746,7 +1746,7 @@
if (attrib->attrib_mask & IPA_FLT_DST_ADDR) {
if (ipa_ofst_meq32[ofst_meq32] == -1) {
- IPAERR("ran out of meq32 eq\n");
+ IPAERR_RL("ran out of meq32 eq\n");
return -EPERM;
}
*en_rule |= ipa_ofst_meq32[ofst_meq32];
@@ -1760,11 +1760,11 @@
if (attrib->attrib_mask & IPA_FLT_SRC_PORT_RANGE) {
if (ipa_ihl_ofst_rng16[ihl_ofst_rng16] == -1) {
- IPAERR("ran out of ihl_rng16 eq\n");
+ IPAERR_RL("ran out of ihl_rng16 eq\n");
return -EPERM;
}
if (attrib->src_port_hi < attrib->src_port_lo) {
- IPAERR("bad src port range param\n");
+ IPAERR_RL("bad src port range param\n");
return -EPERM;
}
*en_rule |= ipa_ihl_ofst_rng16[ihl_ofst_rng16];
@@ -1778,11 +1778,11 @@
if (attrib->attrib_mask & IPA_FLT_DST_PORT_RANGE) {
if (ipa_ihl_ofst_rng16[ihl_ofst_rng16] == -1) {
- IPAERR("ran out of ihl_rng16 eq\n");
+ IPAERR_RL("ran out of ihl_rng16 eq\n");
return -EPERM;
}
if (attrib->dst_port_hi < attrib->dst_port_lo) {
- IPAERR("bad dst port range param\n");
+ IPAERR_RL("bad dst port range param\n");
return -EPERM;
}
*en_rule |= ipa_ihl_ofst_rng16[ihl_ofst_rng16];
@@ -1796,7 +1796,7 @@
if (attrib->attrib_mask & IPA_FLT_TYPE) {
if (ipa_ihl_ofst_meq32[ihl_ofst_meq32] == -1) {
- IPAERR("ran out of ihl_meq32 eq\n");
+ IPAERR_RL("ran out of ihl_meq32 eq\n");
return -EPERM;
}
*en_rule |= ipa_ihl_ofst_meq32[ihl_ofst_meq32];
@@ -1809,7 +1809,7 @@
if (attrib->attrib_mask & IPA_FLT_CODE) {
if (ipa_ihl_ofst_meq32[ihl_ofst_meq32] == -1) {
- IPAERR("ran out of ihl_meq32 eq\n");
+ IPAERR_RL("ran out of ihl_meq32 eq\n");
return -EPERM;
}
*en_rule |= ipa_ihl_ofst_meq32[ihl_ofst_meq32];
@@ -1822,7 +1822,7 @@
if (attrib->attrib_mask & IPA_FLT_SPI) {
if (ipa_ihl_ofst_meq32[ihl_ofst_meq32] == -1) {
- IPAERR("ran out of ihl_meq32 eq\n");
+ IPAERR_RL("ran out of ihl_meq32 eq\n");
return -EPERM;
}
*en_rule |= ipa_ihl_ofst_meq32[ihl_ofst_meq32];
@@ -1836,7 +1836,7 @@
if (attrib->attrib_mask & IPA_FLT_SRC_PORT) {
if (ipa_ihl_ofst_rng16[ihl_ofst_rng16] == -1) {
- IPAERR("ran out of ihl_rng16 eq\n");
+ IPAERR_RL("ran out of ihl_rng16 eq\n");
return -EPERM;
}
*en_rule |= ipa_ihl_ofst_rng16[ihl_ofst_rng16];
@@ -1850,7 +1850,7 @@
if (attrib->attrib_mask & IPA_FLT_DST_PORT) {
if (ipa_ihl_ofst_rng16[ihl_ofst_rng16] == -1) {
- IPAERR("ran out of ihl_rng16 eq\n");
+ IPAERR_RL("ran out of ihl_rng16 eq\n");
return -EPERM;
}
*en_rule |= ipa_ihl_ofst_rng16[ihl_ofst_rng16];
@@ -1877,7 +1877,7 @@
if (attrib->attrib_mask & IPA_FLT_MAC_DST_ADDR_ETHER_II) {
if (ipa_ofst_meq128[ofst_meq128] == -1) {
- IPAERR("ran out of meq128 eq\n");
+ IPAERR_RL("ran out of meq128 eq\n");
return -EPERM;
}
*en_rule |= ipa_ofst_meq128[ofst_meq128];
@@ -1892,7 +1892,7 @@
if (attrib->attrib_mask & IPA_FLT_MAC_SRC_ADDR_ETHER_II) {
if (ipa_ofst_meq128[ofst_meq128] == -1) {
- IPAERR("ran out of meq128 eq\n");
+ IPAERR_RL("ran out of meq128 eq\n");
return -EPERM;
}
*en_rule |= ipa_ofst_meq128[ofst_meq128];
@@ -1907,7 +1907,7 @@
if (attrib->attrib_mask & IPA_FLT_MAC_DST_ADDR_802_3) {
if (ipa_ofst_meq128[ofst_meq128] == -1) {
- IPAERR("ran out of meq128 eq\n");
+ IPAERR_RL("ran out of meq128 eq\n");
return -EPERM;
}
*en_rule |= ipa_ofst_meq128[ofst_meq128];
@@ -1922,7 +1922,7 @@
if (attrib->attrib_mask & IPA_FLT_MAC_SRC_ADDR_802_3) {
if (ipa_ofst_meq128[ofst_meq128] == -1) {
- IPAERR("ran out of meq128 eq\n");
+ IPAERR_RL("ran out of meq128 eq\n");
return -EPERM;
}
*en_rule |= ipa_ofst_meq128[ofst_meq128];
@@ -1937,7 +1937,7 @@
if (attrib->attrib_mask & IPA_FLT_MAC_ETHER_TYPE) {
if (ipa_ofst_meq32[ofst_meq32] == -1) {
- IPAERR("ran out of meq128 eq\n");
+ IPAERR_RL("ran out of meq128 eq\n");
return -EPERM;
}
*en_rule |= ipa_ofst_meq32[ofst_meq32];
@@ -1955,7 +1955,7 @@
/* error check */
if (attrib->attrib_mask & IPA_FLT_TOS ||
attrib->attrib_mask & IPA_FLT_PROTOCOL) {
- IPAERR("v4 attrib's specified for v6 rule\n");
+ IPAERR_RL("v4 attrib's specified for v6 rule\n");
return -EPERM;
}
@@ -1967,7 +1967,7 @@
if (attrib->attrib_mask & IPA_FLT_TYPE) {
if (ipa_ihl_ofst_meq32[ihl_ofst_meq32] == -1) {
- IPAERR("ran out of ihl_meq32 eq\n");
+ IPAERR_RL("ran out of ihl_meq32 eq\n");
return -EPERM;
}
*en_rule |= ipa_ihl_ofst_meq32[ihl_ofst_meq32];
@@ -1980,7 +1980,7 @@
if (attrib->attrib_mask & IPA_FLT_CODE) {
if (ipa_ihl_ofst_meq32[ihl_ofst_meq32] == -1) {
- IPAERR("ran out of ihl_meq32 eq\n");
+ IPAERR_RL("ran out of ihl_meq32 eq\n");
return -EPERM;
}
*en_rule |= ipa_ihl_ofst_meq32[ihl_ofst_meq32];
@@ -1993,7 +1993,7 @@
if (attrib->attrib_mask & IPA_FLT_SPI) {
if (ipa_ihl_ofst_meq32[ihl_ofst_meq32] == -1) {
- IPAERR("ran out of ihl_meq32 eq\n");
+ IPAERR_RL("ran out of ihl_meq32 eq\n");
return -EPERM;
}
*en_rule |= ipa_ihl_ofst_meq32[ihl_ofst_meq32];
@@ -2007,7 +2007,7 @@
if (attrib->attrib_mask & IPA_FLT_SRC_PORT) {
if (ipa_ihl_ofst_rng16[ihl_ofst_rng16] == -1) {
- IPAERR("ran out of ihl_rng16 eq\n");
+ IPAERR_RL("ran out of ihl_rng16 eq\n");
return -EPERM;
}
*en_rule |= ipa_ihl_ofst_rng16[ihl_ofst_rng16];
@@ -2021,7 +2021,7 @@
if (attrib->attrib_mask & IPA_FLT_DST_PORT) {
if (ipa_ihl_ofst_rng16[ihl_ofst_rng16] == -1) {
- IPAERR("ran out of ihl_rng16 eq\n");
+ IPAERR_RL("ran out of ihl_rng16 eq\n");
return -EPERM;
}
*en_rule |= ipa_ihl_ofst_rng16[ihl_ofst_rng16];
@@ -2035,11 +2035,11 @@
if (attrib->attrib_mask & IPA_FLT_SRC_PORT_RANGE) {
if (ipa_ihl_ofst_rng16[ihl_ofst_rng16] == -1) {
- IPAERR("ran out of ihl_rng16 eq\n");
+ IPAERR_RL("ran out of ihl_rng16 eq\n");
return -EPERM;
}
if (attrib->src_port_hi < attrib->src_port_lo) {
- IPAERR("bad src port range param\n");
+ IPAERR_RL("bad src port range param\n");
return -EPERM;
}
*en_rule |= ipa_ihl_ofst_rng16[ihl_ofst_rng16];
@@ -2053,11 +2053,11 @@
if (attrib->attrib_mask & IPA_FLT_DST_PORT_RANGE) {
if (ipa_ihl_ofst_rng16[ihl_ofst_rng16] == -1) {
- IPAERR("ran out of ihl_rng16 eq\n");
+ IPAERR_RL("ran out of ihl_rng16 eq\n");
return -EPERM;
}
if (attrib->dst_port_hi < attrib->dst_port_lo) {
- IPAERR("bad dst port range param\n");
+ IPAERR_RL("bad dst port range param\n");
return -EPERM;
}
*en_rule |= ipa_ihl_ofst_rng16[ihl_ofst_rng16];
@@ -2071,7 +2071,7 @@
if (attrib->attrib_mask & IPA_FLT_SRC_ADDR) {
if (ipa_ofst_meq128[ofst_meq128] == -1) {
- IPAERR("ran out of meq128 eq\n");
+ IPAERR_RL("ran out of meq128 eq\n");
return -EPERM;
}
*en_rule |= ipa_ofst_meq128[ofst_meq128];
@@ -2097,7 +2097,7 @@
if (attrib->attrib_mask & IPA_FLT_DST_ADDR) {
if (ipa_ofst_meq128[ofst_meq128] == -1) {
- IPAERR("ran out of meq128 eq\n");
+ IPAERR_RL("ran out of meq128 eq\n");
return -EPERM;
}
*en_rule |= ipa_ofst_meq128[ofst_meq128];
@@ -2129,7 +2129,7 @@
if (attrib->attrib_mask & IPA_FLT_TOS_MASKED) {
if (ipa_ofst_meq128[ofst_meq128] == -1) {
- IPAERR("ran out of meq128 eq\n");
+ IPAERR_RL("ran out of meq128 eq\n");
return -EPERM;
}
*en_rule |= ipa_ofst_meq128[ofst_meq128];
@@ -2174,7 +2174,7 @@
if (attrib->attrib_mask & IPA_FLT_MAC_DST_ADDR_ETHER_II) {
if (ipa_ofst_meq128[ofst_meq128] == -1) {
- IPAERR("ran out of meq128 eq\n");
+ IPAERR_RL("ran out of meq128 eq\n");
return -EPERM;
}
*en_rule |= ipa_ofst_meq128[ofst_meq128];
@@ -2189,7 +2189,7 @@
if (attrib->attrib_mask & IPA_FLT_MAC_SRC_ADDR_ETHER_II) {
if (ipa_ofst_meq128[ofst_meq128] == -1) {
- IPAERR("ran out of meq128 eq\n");
+ IPAERR_RL("ran out of meq128 eq\n");
return -EPERM;
}
*en_rule |= ipa_ofst_meq128[ofst_meq128];
@@ -2204,7 +2204,7 @@
if (attrib->attrib_mask & IPA_FLT_MAC_DST_ADDR_802_3) {
if (ipa_ofst_meq128[ofst_meq128] == -1) {
- IPAERR("ran out of meq128 eq\n");
+ IPAERR_RL("ran out of meq128 eq\n");
return -EPERM;
}
*en_rule |= ipa_ofst_meq128[ofst_meq128];
@@ -2219,7 +2219,7 @@
if (attrib->attrib_mask & IPA_FLT_MAC_SRC_ADDR_802_3) {
if (ipa_ofst_meq128[ofst_meq128] == -1) {
- IPAERR("ran out of meq128 eq\n");
+ IPAERR_RL("ran out of meq128 eq\n");
return -EPERM;
}
*en_rule |= ipa_ofst_meq128[ofst_meq128];
@@ -2234,7 +2234,7 @@
if (attrib->attrib_mask & IPA_FLT_MAC_ETHER_TYPE) {
if (ipa_ofst_meq32[ofst_meq32] == -1) {
- IPAERR("ran out of meq128 eq\n");
+ IPAERR_RL("ran out of meq128 eq\n");
return -EPERM;
}
*en_rule |= ipa_ofst_meq32[ofst_meq32];
@@ -2247,7 +2247,7 @@
}
} else {
- IPAERR("unsupported ip %d\n", ip);
+ IPAERR_RL("unsupported ip %d\n", ip);
return -EPERM;
}
@@ -2257,7 +2257,7 @@
*/
if (attrib->attrib_mask == 0) {
if (ipa_ofst_meq32[ofst_meq32] == -1) {
- IPAERR("ran out of meq32 eq\n");
+ IPAERR_RL("ran out of meq32 eq\n");
return -EPERM;
}
*en_rule |= ipa_ofst_meq32[ofst_meq32];
@@ -3548,19 +3548,19 @@
}
if (param_in->client >= IPA_CLIENT_MAX) {
- IPAERR("bad parm client:%d\n", param_in->client);
+ IPAERR_RL("bad parm client:%d\n", param_in->client);
goto fail;
}
ipa_ep_idx = ipa2_get_ep_mapping(param_in->client);
if (ipa_ep_idx == -1) {
- IPAERR("Invalid client.\n");
+ IPAERR_RL("Invalid client.\n");
goto fail;
}
ep = &ipa_ctx->ep[ipa_ep_idx];
if (!ep->valid) {
- IPAERR("EP not allocated.\n");
+ IPAERR_RL("EP not allocated.\n");
goto fail;
}
@@ -3574,7 +3574,7 @@
ipa_ctx->ep[ipa_ep_idx].cfg.meta = meta;
result = ipa_write_qmapid_wdi_pipe(ipa_ep_idx, meta.qmap_id);
if (result)
- IPAERR("qmap_id %d write failed on ep=%d\n",
+ IPAERR_RL("qmap_id %d write failed on ep=%d\n",
meta.qmap_id, ipa_ep_idx);
result = 0;
}
diff --git a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c
index 0bdfea9..9c75202 100644
--- a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c
@@ -1877,7 +1877,9 @@
if (ret < 0)
IPAWANERR("Error deleting resource %d, ret=%d\n",
IPA_RM_RESOURCE_Q6_PROD, ret);
- destroy_workqueue(ipa_rm_q6_workqueue);
+
+ if (ipa_rm_q6_workqueue)
+ destroy_workqueue(ipa_rm_q6_workqueue);
}
static void wake_tx_queue(struct work_struct *work)
@@ -2186,7 +2188,10 @@
IPAWANERR("Error deleting resource %d, ret=%d\n",
IPA_RM_RESOURCE_WWAN_0_PROD, ret);
create_rsrc_err:
- q6_deinitialize_rm();
+
+ if (!atomic_read(&is_ssr))
+ q6_deinitialize_rm();
+
q6_init_err:
free_netdev(ipa_netdevs[0]);
ipa_netdevs[0] = NULL;
diff --git a/drivers/platform/msm/ipa/ipa_v3/Makefile b/drivers/platform/msm/ipa/ipa_v3/Makefile
index a4faaea..e3f8d45 100644
--- a/drivers/platform/msm/ipa/ipa_v3/Makefile
+++ b/drivers/platform/msm/ipa/ipa_v3/Makefile
@@ -3,6 +3,7 @@
obj-$(CONFIG_IPA3) += ipat.o
ipat-y := ipa.o ipa_debugfs.o ipa_hdr.o ipa_flt.o ipa_rt.o ipa_dp.o ipa_client.o \
ipa_utils.o ipa_nat.o ipa_intf.o teth_bridge.o ipa_interrupts.o \
- ipa_uc.o ipa_uc_wdi.o ipa_dma.o ipa_uc_mhi.o ipa_mhi.o ipa_uc_ntn.o
+ ipa_uc.o ipa_uc_wdi.o ipa_dma.o ipa_uc_mhi.o ipa_mhi.o ipa_uc_ntn.o \
+ ipa_hw_stats.o
obj-$(CONFIG_RMNET_IPA3) += rmnet_ipa.o ipa_qmi_service_v01.o ipa_qmi_service.o rmnet_ipa_fd_ioctl.o
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index 4b056f6c..4d4e993 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -266,7 +266,9 @@
int cnt = 0;
int start_idx;
int end_idx;
+ unsigned long flags;
+ spin_lock_irqsave(&ipa3_ctx->ipa3_active_clients_logging.lock, flags);
start_idx = (ipa3_ctx->ipa3_active_clients_logging.log_tail + 1) %
IPA3_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES;
end_idx = ipa3_ctx->ipa3_active_clients_logging.log_head;
@@ -277,6 +279,8 @@
.log_buffer[i]);
cnt += nbytes;
}
+ spin_unlock_irqrestore(&ipa3_ctx->ipa3_active_clients_logging.lock,
+ flags);
return cnt;
}
@@ -286,7 +290,9 @@
int i;
struct ipa3_active_client_htable_entry *iterator;
int cnt = 0;
+ unsigned long flags;
+ spin_lock_irqsave(&ipa3_ctx->ipa3_active_clients_logging.lock, flags);
cnt = scnprintf(buf, size, "\n---- Active Clients Table ----\n");
hash_for_each(ipa3_ctx->ipa3_active_clients_logging.htable, i,
iterator, list) {
@@ -319,6 +325,8 @@
cnt += scnprintf(buf + cnt, size - cnt,
"\nTotal active clients count: %d\n",
atomic_read(&ipa3_ctx->ipa3_active_clients.cnt));
+ spin_unlock_irqrestore(&ipa3_ctx->ipa3_active_clients_logging.lock,
+ flags);
return cnt;
}
@@ -368,6 +376,7 @@
{
int i;
+ spin_lock_init(&ipa3_ctx->ipa3_active_clients_logging.lock);
ipa3_ctx->ipa3_active_clients_logging.log_buffer[0] = kzalloc(
IPA3_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES *
sizeof(char[IPA3_ACTIVE_CLIENTS_LOG_LINE_LEN]),
@@ -399,20 +408,28 @@
void ipa3_active_clients_log_clear(void)
{
- mutex_lock(&ipa3_ctx->ipa3_active_clients.mutex);
+ unsigned long flags;
+
+ spin_lock_irqsave(&ipa3_ctx->ipa3_active_clients_logging.lock, flags);
ipa3_ctx->ipa3_active_clients_logging.log_head = 0;
ipa3_ctx->ipa3_active_clients_logging.log_tail =
IPA3_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES - 1;
- mutex_unlock(&ipa3_ctx->ipa3_active_clients.mutex);
+ spin_unlock_irqrestore(&ipa3_ctx->ipa3_active_clients_logging.lock,
+ flags);
}
static void ipa3_active_clients_log_destroy(void)
{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ipa3_ctx->ipa3_active_clients_logging.lock, flags);
ipa3_ctx->ipa3_active_clients_logging.log_rdy = 0;
kfree(ipa3_ctx->ipa3_active_clients_logging.log_buffer[0]);
ipa3_ctx->ipa3_active_clients_logging.log_head = 0;
ipa3_ctx->ipa3_active_clients_logging.log_tail =
IPA3_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES - 1;
+ spin_unlock_irqrestore(&ipa3_ctx->ipa3_active_clients_logging.lock,
+ flags);
}
enum ipa_smmu_cb_type {
@@ -542,7 +559,7 @@
msg_meta.msg_len = sizeof(struct ipa_wan_msg);
retval = ipa3_send_msg(&msg_meta, wan_msg, ipa3_wan_msg_free_cb);
if (retval) {
- IPAERR("ipa3_send_msg failed: %d\n", retval);
+ IPAERR_RL("ipa3_send_msg failed: %d\n", retval);
kfree(wan_msg);
return retval;
}
@@ -719,7 +736,7 @@
/* add check in case user-space module compromised */
if (unlikely(((struct ipa_ioc_nat_dma_cmd *)param)->entries
!= pre_entry)) {
- IPAERR("current %d pre %d\n",
+ IPAERR_RL("current %d pre %d\n",
((struct ipa_ioc_nat_dma_cmd *)param)->entries,
pre_entry);
retval = -EFAULT;
@@ -778,7 +795,7 @@
/* add check in case user-space module compromised */
if (unlikely(((struct ipa_ioc_add_hdr *)param)->num_hdrs
!= pre_entry)) {
- IPAERR("current %d pre %d\n",
+ IPAERR_RL("current %d pre %d\n",
((struct ipa_ioc_add_hdr *)param)->num_hdrs,
pre_entry);
retval = -EFAULT;
@@ -817,7 +834,7 @@
/* add check in case user-space module compromised */
if (unlikely(((struct ipa_ioc_del_hdr *)param)->num_hdls
!= pre_entry)) {
- IPAERR("current %d pre %d\n",
+ IPAERR_RL("current %d pre %d\n",
((struct ipa_ioc_del_hdr *)param)->num_hdls,
pre_entry);
retval = -EFAULT;
@@ -857,7 +874,7 @@
/* add check in case user-space module compromised */
if (unlikely(((struct ipa_ioc_add_rt_rule *)param)->num_rules
!= pre_entry)) {
- IPAERR("current %d pre %d\n",
+ IPAERR_RL("current %d pre %d\n",
((struct ipa_ioc_add_rt_rule *)param)->
num_rules,
pre_entry);
@@ -897,7 +914,7 @@
/* add check in case user-space module compromised */
if (unlikely(((struct ipa_ioc_add_rt_rule_after *)param)->
num_rules != pre_entry)) {
- IPAERR("current %d pre %d\n",
+ IPAERR_RL("current %d pre %d\n",
((struct ipa_ioc_add_rt_rule_after *)param)->
num_rules,
pre_entry);
@@ -939,7 +956,7 @@
/* add check in case user-space module compromised */
if (unlikely(((struct ipa_ioc_mdfy_rt_rule *)param)->num_rules
!= pre_entry)) {
- IPAERR("current %d pre %d\n",
+ IPAERR_RL("current %d pre %d\n",
((struct ipa_ioc_mdfy_rt_rule *)param)->
num_rules,
pre_entry);
@@ -979,7 +996,7 @@
/* add check in case user-space module compromised */
if (unlikely(((struct ipa_ioc_del_rt_rule *)param)->num_hdls
!= pre_entry)) {
- IPAERR("current %d pre %d\n",
+ IPAERR_RL("current %d pre %d\n",
((struct ipa_ioc_del_rt_rule *)param)->num_hdls,
pre_entry);
retval = -EFAULT;
@@ -1018,7 +1035,7 @@
/* add check in case user-space module compromised */
if (unlikely(((struct ipa_ioc_add_flt_rule *)param)->num_rules
!= pre_entry)) {
- IPAERR("current %d pre %d\n",
+ IPAERR_RL("current %d pre %d\n",
((struct ipa_ioc_add_flt_rule *)param)->
num_rules,
pre_entry);
@@ -1060,7 +1077,7 @@
/* add check in case user-space module compromised */
if (unlikely(((struct ipa_ioc_add_flt_rule_after *)param)->
num_rules != pre_entry)) {
- IPAERR("current %d pre %d\n",
+ IPAERR_RL("current %d pre %d\n",
((struct ipa_ioc_add_flt_rule_after *)param)->
num_rules,
pre_entry);
@@ -1101,7 +1118,7 @@
/* add check in case user-space module compromised */
if (unlikely(((struct ipa_ioc_del_flt_rule *)param)->num_hdls
!= pre_entry)) {
- IPAERR("current %d pre %d\n",
+ IPAERR_RL("current %d pre %d\n",
((struct ipa_ioc_del_flt_rule *)param)->
num_hdls,
pre_entry);
@@ -1141,7 +1158,7 @@
/* add check in case user-space module compromised */
if (unlikely(((struct ipa_ioc_mdfy_flt_rule *)param)->num_rules
!= pre_entry)) {
- IPAERR("current %d pre %d\n",
+ IPAERR_RL("current %d pre %d\n",
((struct ipa_ioc_mdfy_flt_rule *)param)->
num_rules,
pre_entry);
@@ -1279,7 +1296,7 @@
if (unlikely(((struct ipa_ioc_query_intf_tx_props *)
param)->num_tx_props
!= pre_entry)) {
- IPAERR("current %d pre %d\n",
+ IPAERR_RL("current %d pre %d\n",
((struct ipa_ioc_query_intf_tx_props *)
param)->num_tx_props, pre_entry);
retval = -EFAULT;
@@ -1324,7 +1341,7 @@
/* add check in case user-space module compromised */
if (unlikely(((struct ipa_ioc_query_intf_rx_props *)
param)->num_rx_props != pre_entry)) {
- IPAERR("current %d pre %d\n",
+ IPAERR_RL("current %d pre %d\n",
((struct ipa_ioc_query_intf_rx_props *)
param)->num_rx_props, pre_entry);
retval = -EFAULT;
@@ -1369,7 +1386,7 @@
/* add check in case user-space module compromised */
if (unlikely(((struct ipa_ioc_query_intf_ext_props *)
param)->num_ext_props != pre_entry)) {
- IPAERR("current %d pre %d\n",
+ IPAERR_RL("current %d pre %d\n",
((struct ipa_ioc_query_intf_ext_props *)
param)->num_ext_props, pre_entry);
retval = -EFAULT;
@@ -1407,7 +1424,7 @@
/* add check in case user-space module compromised */
if (unlikely(((struct ipa_msg_meta *)param)->msg_len
!= pre_entry)) {
- IPAERR("current %d pre %d\n",
+ IPAERR_RL("current %d pre %d\n",
((struct ipa_msg_meta *)param)->msg_len,
pre_entry);
retval = -EFAULT;
@@ -1547,7 +1564,7 @@
/* add check in case user-space module compromised */
if (unlikely(((struct ipa_ioc_add_hdr_proc_ctx *)
param)->num_proc_ctxs != pre_entry)) {
- IPAERR("current %d pre %d\n",
+ IPAERR_RL("current %d pre %d\n",
((struct ipa_ioc_add_hdr_proc_ctx *)
param)->num_proc_ctxs, pre_entry);
retval = -EFAULT;
@@ -1586,7 +1603,7 @@
/* add check in case user-space module compromised */
if (unlikely(((struct ipa_ioc_del_hdr_proc_ctx *)
param)->num_hdls != pre_entry)) {
- IPAERR("current %d pre %d\n",
+ IPAERR_RL("current %d pre %d\n",
((struct ipa_ioc_del_hdr_proc_ctx *)param)->
num_hdls,
pre_entry);
@@ -3402,7 +3419,10 @@
struct ipa3_active_client_htable_entry *hfound;
u32 hkey;
char str_to_hash[IPA3_ACTIVE_CLIENTS_LOG_NAME_LEN];
+ unsigned long flags;
+ spin_lock_irqsave(&ipa3_ctx->ipa3_active_clients_logging.lock, flags);
+ int_ctx = true;
hfound = NULL;
memset(str_to_hash, 0, IPA3_ACTIVE_CLIENTS_LOG_NAME_LEN);
strlcpy(str_to_hash, id->id_string, IPA3_ACTIVE_CLIENTS_LOG_NAME_LEN);
@@ -3422,6 +3442,9 @@
int_ctx ? GFP_ATOMIC : GFP_KERNEL);
if (hentry == NULL) {
IPAERR("failed allocating active clients hash entry");
+ spin_unlock_irqrestore(
+ &ipa3_ctx->ipa3_active_clients_logging.lock,
+ flags);
return;
}
hentry->type = id->type;
@@ -3446,6 +3469,8 @@
id->id_string, id->file, id->line);
ipa3_active_clients_log_insert(temp_str);
}
+ spin_unlock_irqrestore(&ipa3_ctx->ipa3_active_clients_logging.lock,
+ flags);
}
void ipa3_active_clients_log_dec(struct ipa_active_client_logging_info *id,
@@ -3922,14 +3947,17 @@
int i;
struct ipa3_flt_tbl *flt_tbl;
+ idr_destroy(&ipa3_ctx->flt_rule_ids[IPA_IP_v4]);
+ idr_destroy(&ipa3_ctx->flt_rule_ids[IPA_IP_v6]);
+
for (i = 0; i < ipa3_ctx->ipa_num_pipes; i++) {
if (!ipa_is_ep_support_flt(i))
continue;
flt_tbl = &ipa3_ctx->flt_tbl[i][IPA_IP_v4];
- idr_destroy(&flt_tbl->rule_ids);
+ flt_tbl->rule_ids = NULL;
flt_tbl = &ipa3_ctx->flt_tbl[i][IPA_IP_v6];
- idr_destroy(&flt_tbl->rule_ids);
+ flt_tbl->rule_ids = NULL;
}
}
@@ -4104,6 +4132,7 @@
struct ipa3_uc_hdlrs uc_hdlrs = { 0 };
struct ipa3_flt_tbl *flt_tbl;
int i;
+ struct idr *idr;
if (ipa3_ctx == NULL) {
IPADBG("IPA driver haven't initialized\n");
@@ -4127,6 +4156,11 @@
/* Assign resource limitation to each group */
ipa3_set_resorce_groups_min_max_limits();
+ idr = &(ipa3_ctx->flt_rule_ids[IPA_IP_v4]);
+ idr_init(idr);
+ idr = &(ipa3_ctx->flt_rule_ids[IPA_IP_v6]);
+ idr_init(idr);
+
for (i = 0; i < ipa3_ctx->ipa_num_pipes; i++) {
if (!ipa_is_ep_support_flt(i))
continue;
@@ -4137,7 +4171,7 @@
!ipa3_ctx->ip4_flt_tbl_hash_lcl;
flt_tbl->in_sys[IPA_RULE_NON_HASHABLE] =
!ipa3_ctx->ip4_flt_tbl_nhash_lcl;
- idr_init(&flt_tbl->rule_ids);
+ flt_tbl->rule_ids = &ipa3_ctx->flt_rule_ids[IPA_IP_v4];
flt_tbl = &ipa3_ctx->flt_tbl[i][IPA_IP_v6];
INIT_LIST_HEAD(&flt_tbl->head_flt_rule_list);
@@ -4145,7 +4179,7 @@
!ipa3_ctx->ip6_flt_tbl_hash_lcl;
flt_tbl->in_sys[IPA_RULE_NON_HASHABLE] =
!ipa3_ctx->ip6_flt_tbl_nhash_lcl;
- idr_init(&flt_tbl->rule_ids);
+ flt_tbl->rule_ids = &ipa3_ctx->flt_rule_ids[IPA_IP_v6];
}
if (!ipa3_ctx->apply_rg10_wa) {
@@ -4230,6 +4264,12 @@
else
IPADBG(":ntn init ok\n");
+ result = ipa_hw_stats_init();
+ if (result)
+ IPAERR("fail to init stats %d\n", result);
+ else
+ IPADBG(":stats init ok\n");
+
ipa3_register_panic_hdlr();
ipa3_ctx->q6_proxy_clk_vote_valid = true;
@@ -4790,12 +4830,16 @@
hdr_proc_ctx_tbl.head_free_offset_list[i]);
}
INIT_LIST_HEAD(&ipa3_ctx->rt_tbl_set[IPA_IP_v4].head_rt_tbl_list);
+ idr_init(&ipa3_ctx->rt_tbl_set[IPA_IP_v4].rule_ids);
INIT_LIST_HEAD(&ipa3_ctx->rt_tbl_set[IPA_IP_v6].head_rt_tbl_list);
+ idr_init(&ipa3_ctx->rt_tbl_set[IPA_IP_v6].rule_ids);
rset = &ipa3_ctx->reap_rt_tbl_set[IPA_IP_v4];
INIT_LIST_HEAD(&rset->head_rt_tbl_list);
+ idr_init(&rset->rule_ids);
rset = &ipa3_ctx->reap_rt_tbl_set[IPA_IP_v6];
INIT_LIST_HEAD(&rset->head_rt_tbl_list);
+ idr_init(&rset->rule_ids);
INIT_LIST_HEAD(&ipa3_ctx->intf_list);
INIT_LIST_HEAD(&ipa3_ctx->msg_list);
@@ -4915,6 +4959,12 @@
fail_device_create:
unregister_chrdev_region(ipa3_ctx->dev_num, 1);
fail_alloc_chrdev_region:
+ rset = &ipa3_ctx->reap_rt_tbl_set[IPA_IP_v6];
+ idr_destroy(&rset->rule_ids);
+ rset = &ipa3_ctx->reap_rt_tbl_set[IPA_IP_v4];
+ idr_destroy(&rset->rule_ids);
+ idr_destroy(&ipa3_ctx->rt_tbl_set[IPA_IP_v6].rule_ids);
+ idr_destroy(&ipa3_ctx->rt_tbl_set[IPA_IP_v4].rule_ids);
ipa3_free_dma_task_for_gsi();
fail_dma_task:
idr_destroy(&ipa3_ctx->ipa_idr);
@@ -5570,6 +5620,10 @@
struct device_node *node = dev->of_node;
int res;
+ if (ipa3_ctx == NULL) {
+ IPAERR("ipa3_ctx was not initialized\n");
+ return -ENXIO;
+ }
IPADBG("node->name=%s\n", node->name);
if (strcmp("qcom,smp2pgpio_map_ipa_1_out", node->name) == 0) {
res = of_get_gpio(node, 0);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
index f172dc4..153548b 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
@@ -540,6 +540,12 @@
if (attrib->attrib_mask & IPA_FLT_MAC_ETHER_TYPE)
pr_err("ether_type:%x ", attrib->ether_type);
+ if (attrib->attrib_mask & IPA_FLT_TCP_SYN)
+ pr_err("tcp syn ");
+
+ if (attrib->attrib_mask & IPA_FLT_TCP_SYN_L2TP)
+ pr_err("tcp syn l2tp ");
+
pr_err("\n");
return 0;
}
@@ -2169,6 +2175,8 @@
goto fail;
}
+ ipa_debugfs_init_stats(dent);
+
return;
fail:
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dma.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dma.c
index a95547c..5a29cbc 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_dma.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dma.c
@@ -941,10 +941,10 @@
ipa3_dma_debugfs_destroy();
kmem_cache_destroy(ipa3_dma_ctx->ipa_dma_xfer_wrapper_cache);
- kfree(ipa3_dma_ctx);
dma_free_coherent(ipa3_ctx->pdev, IPA_DMA_DUMMY_BUFF_SZ * 4,
ipa3_dma_ctx->ipa_dma_dummy_src_sync.base,
ipa3_dma_ctx->ipa_dma_dummy_src_sync.phys_base);
+ kfree(ipa3_dma_ctx);
ipa3_dma_ctx = NULL;
IPADMA_FUNC_EXIT();
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
index 018467a..02c5991 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
@@ -2574,6 +2574,7 @@
WARN_ON(1);
return;
}
+ spin_lock_bh(&sys->spinlock);
rx_pkt_expected = list_first_entry(&sys->head_desc_list,
struct ipa3_rx_pkt_wrapper,
link);
@@ -2581,6 +2582,7 @@
sys->len--;
if (size)
rx_pkt_expected->len = size;
+ spin_unlock_bh(&sys->spinlock);
rx_skb = rx_pkt_expected->data.skb;
dma_unmap_single(ipa3_ctx->pdev, rx_pkt_expected->data.dma_addr,
sys->rx_buff_sz, DMA_FROM_DEVICE);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c
index b1e50ac..beca549 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c
@@ -806,7 +806,7 @@
if (rule->rule_id) {
id = rule->rule_id;
} else {
- id = ipa3_alloc_rule_id(&tbl->rule_ids);
+ id = ipa3_alloc_rule_id(tbl->rule_ids);
if (id < 0) {
IPAERR("failed to allocate rule id\n");
WARN_ON(1);
@@ -880,7 +880,7 @@
list_del(&entry->link);
/* if rule id was allocated from idr, remove it */
if (!(entry->rule_id & ipahal_get_rule_id_hi_bit()))
- idr_remove(&entry->tbl->rule_ids, entry->rule_id);
+ idr_remove(entry->tbl->rule_ids, entry->rule_id);
kmem_cache_free(ipa3_ctx->flt_rule_cache, entry);
error:
@@ -900,7 +900,7 @@
goto error;
if (rule == NULL || rule_hdl == NULL) {
- IPAERR("bad parms rule=%p rule_hdl=%p\n", rule,
+ IPAERR_RL("bad parms rule=%p rule_hdl=%p\n", rule,
rule_hdl);
goto error;
}
@@ -927,7 +927,7 @@
list_del(&entry->link);
/* if rule id was allocated from idr, remove it */
if (!(entry->rule_id & ipahal_get_rule_id_hi_bit()))
- idr_remove(&entry->tbl->rule_ids, entry->rule_id);
+ idr_remove(entry->tbl->rule_ids, entry->rule_id);
kmem_cache_free(ipa3_ctx->flt_rule_cache, entry);
error:
@@ -942,12 +942,12 @@
entry = ipa3_id_find(rule_hdl);
if (entry == NULL) {
- IPAERR("lookup failed\n");
+ IPAERR_RL("lookup failed\n");
return -EINVAL;
}
if (entry->cookie != IPA_FLT_COOKIE) {
- IPAERR("bad params\n");
+ IPAERR_RL("bad params\n");
return -EINVAL;
}
id = entry->id;
@@ -961,7 +961,7 @@
entry->cookie = 0;
/* if rule id was allocated from idr, remove it */
if (!(entry->rule_id & ipahal_get_rule_id_hi_bit()))
- idr_remove(&entry->tbl->rule_ids, entry->rule_id);
+ idr_remove(entry->tbl->rule_ids, entry->rule_id);
kmem_cache_free(ipa3_ctx->flt_rule_cache, entry);
@@ -979,12 +979,12 @@
entry = ipa3_id_find(frule->rule_hdl);
if (entry == NULL) {
- IPAERR("lookup failed\n");
+ IPAERR_RL("lookup failed\n");
goto error;
}
if (entry->cookie != IPA_FLT_COOKIE) {
- IPAERR("bad params\n");
+ IPAERR_RL("bad params\n");
goto error;
}
@@ -994,25 +994,25 @@
if (frule->rule.action != IPA_PASS_TO_EXCEPTION) {
if (!frule->rule.eq_attrib_type) {
if (!frule->rule.rt_tbl_hdl) {
- IPAERR("invalid RT tbl\n");
+ IPAERR_RL("invalid RT tbl\n");
goto error;
}
rt_tbl = ipa3_id_find(frule->rule.rt_tbl_hdl);
if (rt_tbl == NULL) {
- IPAERR("RT tbl not found\n");
+ IPAERR_RL("RT tbl not found\n");
goto error;
}
if (rt_tbl->cookie != IPA_RT_TBL_COOKIE) {
- IPAERR("RT table cookie is invalid\n");
+ IPAERR_RL("RT table cookie is invalid\n");
goto error;
}
} else {
if (frule->rule.rt_tbl_idx > ((ip == IPA_IP_v4) ?
IPA_MEM_PART(v4_modem_rt_index_hi) :
IPA_MEM_PART(v6_modem_rt_index_hi))) {
- IPAERR("invalid RT tbl\n");
+ IPAERR_RL("invalid RT tbl\n");
goto error;
}
}
@@ -1057,7 +1057,7 @@
int ipa_ep_idx;
if (rule == NULL || rule_hdl == NULL || ep >= IPA_CLIENT_MAX) {
- IPAERR("bad parms rule=%p rule_hdl=%p ep=%d\n", rule,
+ IPAERR_RL("bad parms rule=%p rule_hdl=%p ep=%d\n", rule,
rule_hdl, ep);
return -EINVAL;
@@ -1087,7 +1087,7 @@
if (rules == NULL || rules->num_rules == 0 ||
rules->ip >= IPA_IP_MAX) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
return -EINVAL;
}
@@ -1102,7 +1102,7 @@
result = -1;
if (result) {
- IPAERR("failed to add flt rule %d\n", i);
+ IPAERR_RL("failed to add flt rule %d\n", i);
rules->rules[i].status = IPA_FLT_STATUS_OF_ADD_FAILED;
} else {
rules->rules[i].status = 0;
@@ -1110,7 +1110,7 @@
}
if (rules->global) {
- IPAERR("no support for global filter rules\n");
+ IPAERR_RL("no support for global filter rules\n");
result = -EPERM;
goto bail;
}
@@ -1145,12 +1145,12 @@
if (rules == NULL || rules->num_rules == 0 ||
rules->ip >= IPA_IP_MAX) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
return -EINVAL;
}
if (rules->ep >= IPA_CLIENT_MAX) {
- IPAERR("bad parms ep=%d\n", rules->ep);
+ IPAERR_RL("bad parms ep=%d\n", rules->ep);
return -EINVAL;
}
@@ -1165,20 +1165,20 @@
entry = ipa3_id_find(rules->add_after_hdl);
if (entry == NULL) {
- IPAERR("lookup failed\n");
+ IPAERR_RL("lookup failed\n");
result = -EINVAL;
goto bail;
}
if (entry->tbl != tbl) {
- IPAERR("given entry does not match the table\n");
+ IPAERR_RL("given entry does not match the table\n");
result = -EINVAL;
goto bail;
}
if (tbl->sticky_rear)
if (&entry->link == tbl->head_flt_rule_list.prev) {
- IPAERR("cannot add rule at end of a sticky table");
+ IPAERR_RL("cannot add rule at end of a sticky table");
result = -EINVAL;
goto bail;
}
@@ -1200,7 +1200,7 @@
&entry);
if (result) {
- IPAERR("failed to add flt rule %d\n", i);
+ IPAERR_RL("failed to add flt rule %d\n", i);
rules->rules[i].status = IPA_FLT_STATUS_OF_ADD_FAILED;
} else {
rules->rules[i].status = 0;
@@ -1234,14 +1234,14 @@
int result;
if (hdls == NULL || hdls->num_hdls == 0 || hdls->ip >= IPA_IP_MAX) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
return -EINVAL;
}
mutex_lock(&ipa3_ctx->lock);
for (i = 0; i < hdls->num_hdls; i++) {
if (__ipa_del_flt_rule(hdls->hdl[i].hdl)) {
- IPAERR("failed to del flt rule %i\n", i);
+ IPAERR_RL("failed to del flt rule %i\n", i);
hdls->hdl[i].status = IPA_FLT_STATUS_OF_DEL_FAILED;
} else {
hdls->hdl[i].status = 0;
@@ -1274,14 +1274,14 @@
int result;
if (hdls == NULL || hdls->num_rules == 0 || hdls->ip >= IPA_IP_MAX) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
return -EINVAL;
}
mutex_lock(&ipa3_ctx->lock);
for (i = 0; i < hdls->num_rules; i++) {
if (__ipa_mdfy_flt_rule(&hdls->rules[i], hdls->ip)) {
- IPAERR("failed to mdfy flt rule %i\n", i);
+ IPAERR_RL("failed to mdfy flt rule %i\n", i);
hdls->rules[i].status = IPA_FLT_STATUS_OF_MDFY_FAILED;
} else {
hdls->rules[i].status = 0;
@@ -1315,7 +1315,7 @@
int result;
if (ip >= IPA_IP_MAX) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
return -EINVAL;
}
@@ -1351,7 +1351,7 @@
int id;
if (ip >= IPA_IP_MAX) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
return -EINVAL;
}
@@ -1374,7 +1374,7 @@
entry->rt_tbl->ref_cnt--;
/* if rule id was allocated from idr, remove it */
if (!(entry->rule_id & ipahal_get_rule_id_hi_bit()))
- idr_remove(&entry->tbl->rule_ids,
+ idr_remove(entry->tbl->rule_ids,
entry->rule_id);
entry->cookie = 0;
id = entry->id;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c
index 0c1832c..cc29f8f 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c
@@ -66,12 +66,29 @@
{
struct ipa3_hdr_proc_ctx_entry *entry;
int ret;
+ int ep;
list_for_each_entry(entry,
&ipa3_ctx->hdr_proc_ctx_tbl.head_proc_ctx_entry_list,
link) {
IPADBG_LOW("processing type %d ofst=%d\n",
entry->type, entry->offset_entry->offset);
+
+ if (entry->l2tp_params.is_dst_pipe_valid) {
+ ep = ipa3_get_ep_mapping(entry->l2tp_params.dst_pipe);
+ if (ep >= 0) {
+ entry->l2tp_params.hdr_remove_param.
+ hdr_ofst_pkt_size_valid = ipa3_ctx->
+ ep[ep].cfg.hdr.hdr_ofst_pkt_size_valid;
+ entry->l2tp_params.hdr_remove_param.
+ hdr_ofst_pkt_size = ipa3_ctx->ep[ep].
+ cfg.hdr.hdr_ofst_pkt_size;
+ entry->l2tp_params.hdr_remove_param.
+ hdr_endianness = ipa3_ctx->ep[ep].
+ cfg.hdr_ext.hdr_little_endian ? 0 : 1;
+ }
+ }
+
ret = ipahal_cp_proc_ctx_to_hw_buff(entry->type, mem->base,
entry->offset_entry->offset,
entry->hdr->hdr_len,
@@ -327,17 +344,17 @@
proc_ctx->type, proc_ctx->hdr_hdl);
if (!HDR_PROC_TYPE_IS_VALID(proc_ctx->type)) {
- IPAERR("invalid processing type %d\n", proc_ctx->type);
+ IPAERR_RL("invalid processing type %d\n", proc_ctx->type);
return -EINVAL;
}
hdr_entry = ipa3_id_find(proc_ctx->hdr_hdl);
if (!hdr_entry) {
- IPAERR("hdr_hdl is invalid\n");
+ IPAERR_RL("hdr_hdl is invalid\n");
return -EINVAL;
}
if (hdr_entry->cookie != IPA_HDR_COOKIE) {
- IPAERR("Invalid header cookie %u\n", hdr_entry->cookie);
+ IPAERR_RL("Invalid header cookie %u\n", hdr_entry->cookie);
WARN_ON(1);
return -EINVAL;
}
@@ -367,7 +384,7 @@
ipa_hdr_proc_ctx_bin_sz[IPA_HDR_PROC_CTX_BIN1]) {
bin = IPA_HDR_PROC_CTX_BIN1;
} else {
- IPAERR("unexpected needed len %d\n", needed_len);
+ IPAERR_RL("unexpected needed len %d\n", needed_len);
WARN_ON(1);
goto bad_len;
}
@@ -377,7 +394,7 @@
IPA_MEM_PART(apps_hdr_proc_ctx_size_ddr);
if (list_empty(&htbl->head_free_offset_list[bin])) {
if (htbl->end + ipa_hdr_proc_ctx_bin_sz[bin] > mem_size) {
- IPAERR("hdr proc ctx table overflow\n");
+ IPAERR_RL("hdr proc ctx table overflow\n");
goto bad_len;
}
@@ -424,8 +441,7 @@
return 0;
ipa_insert_failed:
- if (offset)
- list_move(&offset->link,
+ list_move(&offset->link,
&htbl->head_free_offset_list[offset->bin]);
entry->offset_entry = NULL;
list_del(&entry->link);
@@ -450,12 +466,12 @@
int mem_size;
if (hdr->hdr_len == 0 || hdr->hdr_len > IPA_HDR_MAX_SIZE) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
goto error;
}
if (!HDR_TYPE_IS_VALID(hdr->type)) {
- IPAERR("invalid hdr type %d\n", hdr->type);
+ IPAERR_RL("invalid hdr type %d\n", hdr->type);
goto error;
}
@@ -487,7 +503,7 @@
else if (hdr->hdr_len <= ipa_hdr_bin_sz[IPA_HDR_BIN4])
bin = IPA_HDR_BIN4;
else {
- IPAERR("unexpected hdr len %d\n", hdr->hdr_len);
+ IPAERR_RL("unexpected hdr len %d\n", hdr->hdr_len);
goto bad_hdr_len;
}
@@ -609,7 +625,7 @@
entry = ipa3_id_find(proc_ctx_hdl);
if (!entry || (entry->cookie != IPA_PROC_HDR_COOKIE)) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
return -EINVAL;
}
@@ -617,7 +633,7 @@
htbl->proc_ctx_cnt, entry->offset_entry->offset);
if (by_user && entry->user_deleted) {
- IPAERR("proc_ctx already deleted by user\n");
+ IPAERR_RL("proc_ctx already deleted by user\n");
return -EINVAL;
}
@@ -655,12 +671,12 @@
entry = ipa3_id_find(hdr_hdl);
if (entry == NULL) {
- IPAERR("lookup failed\n");
+ IPAERR_RL("lookup failed\n");
return -EINVAL;
}
if (entry->cookie != IPA_HDR_COOKIE) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
return -EINVAL;
}
@@ -673,7 +689,7 @@
entry->offset_entry->offset);
if (by_user && entry->user_deleted) {
- IPAERR("proc_ctx already deleted by user\n");
+ IPAERR_RL("proc_ctx already deleted by user\n");
return -EINVAL;
}
@@ -722,7 +738,7 @@
int result = -EFAULT;
if (hdrs == NULL || hdrs->num_hdrs == 0) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
return -EINVAL;
}
@@ -731,7 +747,7 @@
hdrs->num_hdrs);
for (i = 0; i < hdrs->num_hdrs; i++) {
if (__ipa_add_hdr(&hdrs->hdr[i])) {
- IPAERR("failed to add hdr %d\n", i);
+ IPAERR_RL("failed to add hdr %d\n", i);
hdrs->hdr[i].status = -1;
} else {
hdrs->hdr[i].status = 0;
@@ -767,14 +783,14 @@
int result = -EFAULT;
if (hdls == NULL || hdls->num_hdls == 0) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
return -EINVAL;
}
mutex_lock(&ipa3_ctx->lock);
for (i = 0; i < hdls->num_hdls; i++) {
if (__ipa3_del_hdr(hdls->hdl[i].hdl, by_user)) {
- IPAERR("failed to del hdr %i\n", i);
+ IPAERR_RL("failed to del hdr %i\n", i);
hdls->hdl[i].status = -1;
} else {
hdls->hdl[i].status = 0;
@@ -822,7 +838,7 @@
int result = -EFAULT;
if (proc_ctxs == NULL || proc_ctxs->num_proc_ctxs == 0) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
return -EINVAL;
}
@@ -831,7 +847,7 @@
proc_ctxs->num_proc_ctxs);
for (i = 0; i < proc_ctxs->num_proc_ctxs; i++) {
if (__ipa_add_hdr_proc_ctx(&proc_ctxs->proc_ctx[i], true)) {
- IPAERR("failed to add hdr pric ctx %d\n", i);
+ IPAERR_RL("failed to add hdr pric ctx %d\n", i);
proc_ctxs->proc_ctx[i].status = -1;
} else {
proc_ctxs->proc_ctx[i].status = 0;
@@ -869,14 +885,14 @@
int result;
if (hdls == NULL || hdls->num_hdls == 0) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
return -EINVAL;
}
mutex_lock(&ipa3_ctx->lock);
for (i = 0; i < hdls->num_hdls; i++) {
if (__ipa3_del_hdr_proc_ctx(hdls->hdl[i].hdl, true, by_user)) {
- IPAERR("failed to del hdr %i\n", i);
+ IPAERR_RL("failed to del hdr %i\n", i);
hdls->hdl[i].status = -1;
} else {
hdls->hdl[i].status = 0;
@@ -1083,7 +1099,7 @@
struct ipa3_hdr_entry *entry;
if (strnlen(name, IPA_RESOURCE_NAME_MAX) == IPA_RESOURCE_NAME_MAX) {
- IPAERR("Header name too long: %s\n", name);
+ IPAERR_RL("Header name too long: %s\n", name);
return NULL;
}
@@ -1113,7 +1129,7 @@
int result = -1;
if (lookup == NULL) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
return -EINVAL;
}
mutex_lock(&ipa3_ctx->lock);
@@ -1200,13 +1216,13 @@
entry = ipa3_id_find(hdr_hdl);
if (entry == NULL) {
- IPAERR("lookup failed\n");
+ IPAERR_RL("lookup failed\n");
result = -EINVAL;
goto bail;
}
if (entry->cookie != IPA_HDR_COOKIE) {
- IPAERR("invalid header entry\n");
+ IPAERR_RL("invalid header entry\n");
result = -EINVAL;
goto bail;
}
@@ -1235,7 +1251,7 @@
int result = -EFAULT;
if (copy == NULL) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
return -EINVAL;
}
mutex_lock(&ipa3_ctx->lock);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_hw_stats.c b/drivers/platform/msm/ipa/ipa_v3/ipa_hw_stats.c
new file mode 100644
index 0000000..8a4d945
--- /dev/null
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_hw_stats.c
@@ -0,0 +1,1973 @@
+/* Copyright (c) 2017, The Linux Foundation. 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 and
+ * only 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/debugfs.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include "ipa_i.h"
+#include "ipahal/ipahal.h"
+#include "ipahal/ipahal_hw_stats.h"
+
+#define IPA_CLIENT_BIT_32(client) \
+ ((ipa3_get_ep_mapping(client) >= 0 && \
+ ipa3_get_ep_mapping(client) < IPA_STATS_MAX_PIPE_BIT) ? \
+ (1 << ipa3_get_ep_mapping(client)) : 0)
+
+int ipa_hw_stats_init(void)
+{
+ if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0)
+ return 0;
+
+ /* initialize stats here */
+ ipa3_ctx->hw_stats.enabled = true;
+ return 0;
+}
+
+int ipa_init_quota_stats(u32 pipe_bitmask)
+{
+ struct ipahal_stats_init_pyld *pyld;
+ struct ipahal_imm_cmd_dma_shared_mem cmd = { 0 };
+ struct ipahal_imm_cmd_pyld *cmd_pyld;
+ struct ipahal_imm_cmd_register_write quota_base = {0};
+ struct ipahal_imm_cmd_pyld *quota_base_pyld;
+ struct ipahal_imm_cmd_register_write quota_mask = {0};
+ struct ipahal_imm_cmd_pyld *quota_mask_pyld;
+ struct ipa3_desc desc[3] = { {0} };
+ dma_addr_t dma_address;
+ int ret;
+
+ if (!ipa3_ctx->hw_stats.enabled)
+ return 0;
+
+ /* reset driver's cache */
+ memset(&ipa3_ctx->hw_stats.quota, 0, sizeof(ipa3_ctx->hw_stats.quota));
+ ipa3_ctx->hw_stats.quota.init.enabled_bitmask = pipe_bitmask;
+ IPADBG_LOW("pipe_bitmask=0x%x\n", pipe_bitmask);
+
+ pyld = ipahal_stats_generate_init_pyld(IPAHAL_HW_STATS_QUOTA,
+ &ipa3_ctx->hw_stats.quota.init, false);
+ if (!pyld) {
+ IPAERR("failed to generate pyld\n");
+ return -EPERM;
+ }
+
+ if (pyld->len > IPA_MEM_PART(stats_quota_size)) {
+ IPAERR("SRAM partition too small: %d needed %d\n",
+ IPA_MEM_PART(stats_quota_size), pyld->len);
+ ret = -EPERM;
+ goto destroy_init_pyld;
+ }
+
+ dma_address = dma_map_single(ipa3_ctx->pdev,
+ pyld->data,
+ pyld->len,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(ipa3_ctx->pdev, dma_address)) {
+ IPAERR("failed to DMA map\n");
+ ret = -EPERM;
+ goto destroy_init_pyld;
+ }
+
+ /* setting the registers and init the stats pyld are done atomically */
+ quota_mask.skip_pipeline_clear = false;
+ quota_mask.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR;
+ quota_mask.offset = ipahal_get_reg_n_ofst(IPA_STAT_QUOTA_MASK_n,
+ ipa3_ctx->ee);
+ quota_mask.value = pipe_bitmask;
+ quota_mask.value_mask = ~0;
+ quota_mask_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_REGISTER_WRITE,
+ "a_mask, false);
+ if (!quota_mask_pyld) {
+ IPAERR("failed to construct register_write imm cmd\n");
+ ret = -ENOMEM;
+ goto unmap;
+ }
+ desc[0].opcode = quota_mask_pyld->opcode;
+ desc[0].pyld = quota_mask_pyld->data;
+ desc[0].len = quota_mask_pyld->len;
+ desc[0].type = IPA_IMM_CMD_DESC;
+
+ quota_base.skip_pipeline_clear = false;
+ quota_base.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR;
+ quota_base.offset = ipahal_get_reg_n_ofst(IPA_STAT_QUOTA_BASE_n,
+ ipa3_ctx->ee);
+ quota_base.value = ipa3_ctx->smem_restricted_bytes +
+ IPA_MEM_PART(stats_quota_ofst);
+ quota_base.value_mask = ~0;
+ quota_base_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_REGISTER_WRITE,
+ "a_base, false);
+ if (!quota_base_pyld) {
+ IPAERR("failed to construct register_write imm cmd\n");
+ ret = -ENOMEM;
+ goto destroy_quota_mask;
+ }
+ desc[1].opcode = quota_base_pyld->opcode;
+ desc[1].pyld = quota_base_pyld->data;
+ desc[1].len = quota_base_pyld->len;
+ desc[1].type = IPA_IMM_CMD_DESC;
+
+ cmd.is_read = false;
+ cmd.skip_pipeline_clear = false;
+ cmd.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR;
+ cmd.size = pyld->len;
+ cmd.system_addr = dma_address;
+ cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
+ IPA_MEM_PART(stats_quota_ofst);
+ cmd_pyld = ipahal_construct_imm_cmd(
+ IPA_IMM_CMD_DMA_SHARED_MEM, &cmd, false);
+ if (!cmd_pyld) {
+ IPAERR("failed to construct dma_shared_mem imm cmd\n");
+ ret = -ENOMEM;
+ goto destroy_quota_base;
+ }
+ desc[2].opcode = cmd_pyld->opcode;
+ desc[2].pyld = cmd_pyld->data;
+ desc[2].len = cmd_pyld->len;
+ desc[2].type = IPA_IMM_CMD_DESC;
+
+ ret = ipa3_send_cmd(3, desc);
+ if (ret) {
+ IPAERR("failed to send immediate command (error %d)\n", ret);
+ goto destroy_imm;
+ }
+
+ ret = 0;
+
+destroy_imm:
+ ipahal_destroy_imm_cmd(cmd_pyld);
+destroy_quota_base:
+ ipahal_destroy_imm_cmd(quota_base_pyld);
+destroy_quota_mask:
+ ipahal_destroy_imm_cmd(quota_mask_pyld);
+unmap:
+ dma_unmap_single(ipa3_ctx->pdev, dma_address, pyld->len, DMA_TO_DEVICE);
+destroy_init_pyld:
+ ipahal_destroy_stats_init_pyld(pyld);
+ return ret;
+}
+
+int ipa_get_quota_stats(struct ipa_quota_stats_all *out)
+{
+ int i;
+ int ret;
+ struct ipahal_stats_get_offset_quota get_offset = { { 0 } };
+ struct ipahal_stats_offset offset = { 0 };
+ struct ipahal_imm_cmd_dma_shared_mem cmd = { 0 };
+ struct ipahal_imm_cmd_pyld *cmd_pyld;
+ struct ipa_mem_buffer mem;
+ struct ipa3_desc desc = { 0 };
+ struct ipahal_stats_quota_all *stats;
+
+ if (!ipa3_ctx->hw_stats.enabled)
+ return 0;
+
+ get_offset.init = ipa3_ctx->hw_stats.quota.init;
+ ret = ipahal_stats_get_offset(IPAHAL_HW_STATS_QUOTA, &get_offset,
+ &offset);
+ if (ret) {
+ IPAERR("failed to get offset from hal %d\n", ret);
+ return ret;
+ }
+
+ IPADBG_LOW("offset = %d size = %d\n", offset.offset, offset.size);
+
+ mem.size = offset.size;
+ mem.base = dma_alloc_coherent(ipa3_ctx->pdev,
+ mem.size,
+ &mem.phys_base,
+ GFP_KERNEL);
+ if (!mem.base) {
+ IPAERR("fail to alloc DMA memory");
+ return ret;
+ }
+
+ cmd.is_read = true;
+ cmd.clear_after_read = true;
+ cmd.skip_pipeline_clear = false;
+ cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
+ cmd.size = mem.size;
+ cmd.system_addr = mem.phys_base;
+ cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
+ IPA_MEM_PART(stats_quota_ofst) + offset.offset;
+ cmd_pyld = ipahal_construct_imm_cmd(
+ IPA_IMM_CMD_DMA_SHARED_MEM, &cmd, false);
+ if (!cmd_pyld) {
+ IPAERR("failed to construct dma_shared_mem imm cmd\n");
+ ret = -ENOMEM;
+ goto free_dma_mem;
+ }
+ desc.opcode = cmd_pyld->opcode;
+ desc.pyld = cmd_pyld->data;
+ desc.len = cmd_pyld->len;
+ desc.type = IPA_IMM_CMD_DESC;
+
+ ret = ipa3_send_cmd(1, &desc);
+ if (ret) {
+ IPAERR("failed to send immediate command (error %d)\n", ret);
+ goto destroy_imm;
+ }
+
+ stats = kzalloc(sizeof(*stats), GFP_KERNEL);
+ if (!stats) {
+ IPADBG("failed to alloc memory\n");
+ ret = -ENOMEM;
+ goto destroy_imm;
+ }
+
+ ret = ipahal_parse_stats(IPAHAL_HW_STATS_QUOTA,
+ &ipa3_ctx->hw_stats.quota.init, mem.base, stats);
+ if (ret) {
+ IPAERR("failed to parse stats (error %d)\n", ret);
+ goto free_stats;
+ }
+
+ /*
+ * update driver cache.
+ * the stats were read from hardware with clear_after_read meaning
+ * hardware stats are 0 now
+ */
+ for (i = 0; i < IPA_CLIENT_MAX; i++) {
+ int ep_idx = ipa3_get_ep_mapping(i);
+
+ if (ep_idx == -1 || ep_idx >= IPA3_MAX_NUM_PIPES)
+ continue;
+
+ if (ipa3_ctx->ep[ep_idx].client != i)
+ continue;
+
+ ipa3_ctx->hw_stats.quota.stats.client[i].num_ipv4_bytes +=
+ stats->stats[ep_idx].num_ipv4_bytes;
+ ipa3_ctx->hw_stats.quota.stats.client[i].num_ipv4_pkts +=
+ stats->stats[ep_idx].num_ipv4_pkts;
+ ipa3_ctx->hw_stats.quota.stats.client[i].num_ipv6_bytes +=
+ stats->stats[ep_idx].num_ipv6_bytes;
+ ipa3_ctx->hw_stats.quota.stats.client[i].num_ipv6_pkts +=
+ stats->stats[ep_idx].num_ipv6_pkts;
+ }
+
+ /* copy results to out parameter */
+ if (out)
+ *out = ipa3_ctx->hw_stats.quota.stats;
+ ret = 0;
+free_stats:
+ kfree(stats);
+destroy_imm:
+ ipahal_destroy_imm_cmd(cmd_pyld);
+free_dma_mem:
+ dma_free_coherent(ipa3_ctx->pdev, mem.size, mem.base, mem.phys_base);
+ return ret;
+
+}
+
+int ipa_reset_quota_stats(enum ipa_client_type client)
+{
+ int ret;
+ struct ipa_quota_stats *stats;
+
+ if (!ipa3_ctx->hw_stats.enabled)
+ return 0;
+
+ if (client >= IPA_CLIENT_MAX) {
+ IPAERR("invalid client %d\n", client);
+ return -EINVAL;
+ }
+
+ /* reading stats will reset them in hardware */
+ ret = ipa_get_quota_stats(NULL);
+ if (ret) {
+ IPAERR("ipa_get_quota_stats failed %d\n", ret);
+ return ret;
+ }
+
+ /* reset driver's cache */
+ stats = &ipa3_ctx->hw_stats.quota.stats.client[client];
+ memset(stats, 0, sizeof(*stats));
+ return 0;
+}
+
+int ipa_reset_all_quota_stats(void)
+{
+ int ret;
+ struct ipa_quota_stats_all *stats;
+
+ if (!ipa3_ctx->hw_stats.enabled)
+ return 0;
+
+ /* reading stats will reset them in hardware */
+ ret = ipa_get_quota_stats(NULL);
+ if (ret) {
+ IPAERR("ipa_get_quota_stats failed %d\n", ret);
+ return ret;
+ }
+
+ /* reset driver's cache */
+ stats = &ipa3_ctx->hw_stats.quota.stats;
+ memset(stats, 0, sizeof(*stats));
+ return 0;
+}
+
+int ipa_init_teth_stats(struct ipa_teth_stats_endpoints *in)
+{
+ struct ipahal_stats_init_pyld *pyld;
+ struct ipahal_imm_cmd_dma_shared_mem cmd = { 0 };
+ struct ipahal_imm_cmd_pyld *cmd_pyld;
+ struct ipahal_imm_cmd_register_write teth_base = {0};
+ struct ipahal_imm_cmd_pyld *teth_base_pyld;
+ struct ipahal_imm_cmd_register_write teth_mask = { 0 };
+ struct ipahal_imm_cmd_pyld *teth_mask_pyld;
+ struct ipa3_desc desc[3] = { {0} };
+ dma_addr_t dma_address;
+ int ret;
+ int i;
+
+ if (!ipa3_ctx->hw_stats.enabled)
+ return 0;
+
+ if (!in || !in->prod_mask) {
+ IPAERR("invalid params\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < IPA_STATS_MAX_PIPE_BIT; i++) {
+ if ((in->prod_mask & (1 << i)) && !in->dst_ep_mask[i]) {
+ IPAERR("prod %d doesn't have cons\n", i);
+ return -EINVAL;
+ }
+ }
+ IPADBG_LOW("prod_mask=0x%x\n", in->prod_mask);
+
+ /* reset driver's cache */
+ memset(&ipa3_ctx->hw_stats.teth.init, 0,
+ sizeof(ipa3_ctx->hw_stats.teth.init));
+ for (i = 0; i < IPA_CLIENT_MAX; i++)
+ memset(&ipa3_ctx->hw_stats.teth.prod_stats[i], 0,
+ sizeof(ipa3_ctx->hw_stats.teth.prod_stats[i]));
+ ipa3_ctx->hw_stats.teth.init.prod_bitmask = in->prod_mask;
+ memcpy(ipa3_ctx->hw_stats.teth.init.cons_bitmask, in->dst_ep_mask,
+ sizeof(ipa3_ctx->hw_stats.teth.init.cons_bitmask));
+
+
+ pyld = ipahal_stats_generate_init_pyld(IPAHAL_HW_STATS_TETHERING,
+ &ipa3_ctx->hw_stats.teth.init, false);
+ if (!pyld) {
+ IPAERR("failed to generate pyld\n");
+ return -EPERM;
+ }
+
+ if (pyld->len > IPA_MEM_PART(stats_tethering_size)) {
+ IPAERR("SRAM partition too small: %d needed %d\n",
+ IPA_MEM_PART(stats_tethering_size), pyld->len);
+ ret = -EPERM;
+ goto destroy_init_pyld;
+ }
+
+ dma_address = dma_map_single(ipa3_ctx->pdev,
+ pyld->data,
+ pyld->len,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(ipa3_ctx->pdev, dma_address)) {
+ IPAERR("failed to DMA map\n");
+ ret = -EPERM;
+ goto destroy_init_pyld;
+ }
+
+ /* setting the registers and init the stats pyld are done atomically */
+ teth_mask.skip_pipeline_clear = false;
+ teth_mask.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR;
+ teth_mask.offset = ipahal_get_reg_n_ofst(IPA_STAT_TETHERING_MASK_n,
+ ipa3_ctx->ee);
+ teth_mask.value = in->prod_mask;
+ teth_mask.value_mask = ~0;
+ teth_mask_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_REGISTER_WRITE,
+ &teth_mask, false);
+ if (!teth_mask_pyld) {
+ IPAERR("failed to construct register_write imm cmd\n");
+ ret = -ENOMEM;
+ goto unmap;
+ }
+ desc[0].opcode = teth_mask_pyld->opcode;
+ desc[0].pyld = teth_mask_pyld->data;
+ desc[0].len = teth_mask_pyld->len;
+ desc[0].type = IPA_IMM_CMD_DESC;
+
+ teth_base.skip_pipeline_clear = false;
+ teth_base.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR;
+ teth_base.offset = ipahal_get_reg_n_ofst(IPA_STAT_TETHERING_BASE_n,
+ ipa3_ctx->ee);
+ teth_base.value = ipa3_ctx->smem_restricted_bytes +
+ IPA_MEM_PART(stats_tethering_ofst);
+ teth_base.value_mask = ~0;
+ teth_base_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_REGISTER_WRITE,
+ &teth_base, false);
+ if (!teth_base_pyld) {
+ IPAERR("failed to construct register_write imm cmd\n");
+ ret = -ENOMEM;
+ goto destroy_teth_mask;
+ }
+ desc[1].opcode = teth_base_pyld->opcode;
+ desc[1].pyld = teth_base_pyld->data;
+ desc[1].len = teth_base_pyld->len;
+ desc[1].type = IPA_IMM_CMD_DESC;
+
+ cmd.is_read = false;
+ cmd.skip_pipeline_clear = false;
+ cmd.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR;
+ cmd.size = pyld->len;
+ cmd.system_addr = dma_address;
+ cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
+ IPA_MEM_PART(stats_tethering_ofst);
+ cmd_pyld = ipahal_construct_imm_cmd(
+ IPA_IMM_CMD_DMA_SHARED_MEM, &cmd, false);
+ if (!cmd_pyld) {
+ IPAERR("failed to construct dma_shared_mem imm cmd\n");
+ ret = -ENOMEM;
+ goto destroy_teth_base;
+ }
+ desc[2].opcode = cmd_pyld->opcode;
+ desc[2].pyld = cmd_pyld->data;
+ desc[2].len = cmd_pyld->len;
+ desc[2].type = IPA_IMM_CMD_DESC;
+
+ ret = ipa3_send_cmd(3, desc);
+ if (ret) {
+ IPAERR("failed to send immediate command (error %d)\n", ret);
+ goto destroy_imm;
+ }
+
+ ret = 0;
+
+destroy_imm:
+ ipahal_destroy_imm_cmd(cmd_pyld);
+destroy_teth_base:
+ ipahal_destroy_imm_cmd(teth_base_pyld);
+destroy_teth_mask:
+ ipahal_destroy_imm_cmd(teth_mask_pyld);
+unmap:
+ dma_unmap_single(ipa3_ctx->pdev, dma_address, pyld->len, DMA_TO_DEVICE);
+destroy_init_pyld:
+ ipahal_destroy_stats_init_pyld(pyld);
+ return ret;
+}
+
+int ipa_get_teth_stats(enum ipa_client_type prod,
+ struct ipa_quota_stats_all *out)
+{
+ int i, j;
+ int ret;
+ struct ipahal_stats_get_offset_tethering get_offset = { { 0 } };
+ struct ipahal_stats_offset offset = {0};
+ struct ipahal_imm_cmd_dma_shared_mem cmd = { 0 };
+ struct ipahal_imm_cmd_pyld *cmd_pyld;
+ struct ipa_mem_buffer mem;
+ struct ipa3_desc desc = { 0 };
+ struct ipahal_stats_tethering_all *stats;
+
+ if (!ipa3_ctx->hw_stats.enabled)
+ return 0;
+
+ if (!IPA_CLIENT_IS_PROD(prod) || ipa3_get_ep_mapping(prod) == -1) {
+ IPAERR("invalid prod %d\n", prod);
+ return -EINVAL;
+ }
+
+ get_offset.init = ipa3_ctx->hw_stats.teth.init;
+ ret = ipahal_stats_get_offset(IPAHAL_HW_STATS_TETHERING, &get_offset,
+ &offset);
+ if (ret) {
+ IPAERR("failed to get offset from hal %d\n", ret);
+ return ret;
+ }
+
+ IPADBG_LOW("offset = %d size = %d\n", offset.offset, offset.size);
+
+ mem.size = offset.size;
+ mem.base = dma_alloc_coherent(ipa3_ctx->pdev,
+ mem.size,
+ &mem.phys_base,
+ GFP_KERNEL);
+ if (!mem.base) {
+ IPAERR("fail to alloc DMA memory\n");
+ return ret;
+ }
+
+ cmd.is_read = true;
+ cmd.clear_after_read = true;
+ cmd.skip_pipeline_clear = false;
+ cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
+ cmd.size = mem.size;
+ cmd.system_addr = mem.phys_base;
+ cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
+ IPA_MEM_PART(stats_tethering_ofst) + offset.offset;
+ cmd_pyld = ipahal_construct_imm_cmd(
+ IPA_IMM_CMD_DMA_SHARED_MEM, &cmd, false);
+ if (!cmd_pyld) {
+ IPAERR("failed to construct dma_shared_mem imm cmd\n");
+ ret = -ENOMEM;
+ goto free_dma_mem;
+ }
+ desc.opcode = cmd_pyld->opcode;
+ desc.pyld = cmd_pyld->data;
+ desc.len = cmd_pyld->len;
+ desc.type = IPA_IMM_CMD_DESC;
+
+ ret = ipa3_send_cmd(1, &desc);
+ if (ret) {
+ IPAERR("failed to send immediate command (error %d)\n", ret);
+ goto destroy_imm;
+ }
+
+ stats = kzalloc(sizeof(*stats), GFP_KERNEL);
+ if (!stats) {
+ IPADBG("failed to alloc memory\n");
+ ret = -ENOMEM;
+ goto destroy_imm;
+ }
+
+ ret = ipahal_parse_stats(IPAHAL_HW_STATS_TETHERING,
+ &ipa3_ctx->hw_stats.teth.init, mem.base, stats);
+ if (ret) {
+ IPAERR("failed to parse stats (error %d)\n", ret);
+ goto free_stats;
+ }
+
+ /*
+ * update driver cache.
+ * the stats were read from hardware with clear_after_read meaning
+ * hardware stats are 0 now
+ */
+ for (i = 0; i < IPA_CLIENT_MAX; i++) {
+ for (j = 0; j < IPA_CLIENT_MAX; j++) {
+ struct ipa_hw_stats_teth *sw_stats =
+ &ipa3_ctx->hw_stats.teth;
+ int prod_idx = ipa3_get_ep_mapping(i);
+ int cons_idx = ipa3_get_ep_mapping(j);
+
+ if (prod_idx == -1 || prod_idx >= IPA3_MAX_NUM_PIPES)
+ continue;
+
+ if (cons_idx == -1 || cons_idx >= IPA3_MAX_NUM_PIPES)
+ continue;
+
+ if (ipa3_ctx->ep[prod_idx].client != i ||
+ ipa3_ctx->ep[cons_idx].client != j)
+ continue;
+
+ sw_stats->prod_stats[i].client[j].num_ipv4_bytes +=
+ stats->stats[prod_idx][cons_idx].num_ipv4_bytes;
+ sw_stats->prod_stats[i].client[j].num_ipv4_pkts +=
+ stats->stats[prod_idx][cons_idx].num_ipv4_pkts;
+ sw_stats->prod_stats[i].client[j].num_ipv6_bytes +=
+ stats->stats[prod_idx][cons_idx].num_ipv6_bytes;
+ sw_stats->prod_stats[i].client[j].num_ipv6_pkts +=
+ stats->stats[prod_idx][cons_idx].num_ipv6_pkts;
+ }
+ }
+
+ if (!out) {
+ ret = 0;
+ goto free_stats;
+ }
+
+ /* copy results to out parameter */
+ *out = ipa3_ctx->hw_stats.teth.prod_stats[prod];
+
+ ret = 0;
+free_stats:
+ kfree(stats);
+destroy_imm:
+ ipahal_destroy_imm_cmd(cmd_pyld);
+free_dma_mem:
+ dma_free_coherent(ipa3_ctx->pdev, mem.size, mem.base, mem.phys_base);
+ return ret;
+
+}
+
+int ipa_reset_teth_stats(enum ipa_client_type prod, enum ipa_client_type cons)
+{
+ int ret;
+ struct ipa_quota_stats *stats;
+
+ if (!ipa3_ctx->hw_stats.enabled)
+ return 0;
+
+ if (!IPA_CLIENT_IS_PROD(prod) || !IPA_CLIENT_IS_CONS(cons)) {
+ IPAERR("invalid prod %d or cons %d\n", prod, cons);
+ return -EINVAL;
+ }
+
+ /* reading stats will reset them in hardware */
+ ret = ipa_get_teth_stats(prod, NULL);
+ if (ret) {
+ IPAERR("ipa_get_teth_stats failed %d\n", ret);
+ return ret;
+ }
+
+ /* reset driver's cache */
+ stats = &ipa3_ctx->hw_stats.teth.prod_stats[prod].client[cons];
+ memset(stats, 0, sizeof(*stats));
+ return 0;
+}
+
+int ipa_reset_all_cons_teth_stats(enum ipa_client_type prod)
+{
+ int ret;
+ int i;
+ struct ipa_quota_stats *stats;
+
+ if (!ipa3_ctx->hw_stats.enabled)
+ return 0;
+
+ if (!IPA_CLIENT_IS_PROD(prod)) {
+ IPAERR("invalid prod %d\n", prod);
+ return -EINVAL;
+ }
+
+ /* reading stats will reset them in hardware */
+ ret = ipa_get_teth_stats(prod, NULL);
+ if (ret) {
+ IPAERR("ipa_get_teth_stats failed %d\n", ret);
+ return ret;
+ }
+
+ /* reset driver's cache */
+ for (i = 0; i < IPA_CLIENT_MAX; i++) {
+ stats = &ipa3_ctx->hw_stats.teth.prod_stats[prod].client[i];
+ memset(stats, 0, sizeof(*stats));
+ }
+
+ return 0;
+}
+
+int ipa_reset_all_teth_stats(void)
+{
+ int i;
+ int ret;
+ struct ipa_quota_stats_all *stats;
+
+ if (!ipa3_ctx->hw_stats.enabled)
+ return 0;
+
+ /* reading stats will reset them in hardware */
+ for (i = 0; i < IPA_CLIENT_MAX; i++) {
+ if (IPA_CLIENT_IS_PROD(i) && ipa3_get_ep_mapping(i) != -1) {
+ ret = ipa_get_teth_stats(i, NULL);
+ if (ret) {
+ IPAERR("ipa_get_teth_stats failed %d\n", ret);
+ return ret;
+ }
+ /* a single iteration will reset all hardware stats */
+ break;
+ }
+ }
+
+ /* reset driver's cache */
+ for (i = 0; i < IPA_CLIENT_MAX; i++) {
+ stats = &ipa3_ctx->hw_stats.teth.prod_stats[i];
+ memset(stats, 0, sizeof(*stats));
+ }
+
+ return 0;
+}
+
+int ipa_flt_rt_stats_add_rule_id(enum ipa_ip_type ip, bool filtering,
+ u16 rule_id)
+{
+ int rule_idx, rule_bit;
+ u32 *bmsk_ptr;
+
+ if (!ipa3_ctx->hw_stats.enabled)
+ return 0;
+
+ if (ip < 0 || ip >= IPA_IP_MAX) {
+ IPAERR("wrong ip type %d\n", ip);
+ return -EINVAL;
+ }
+
+ rule_idx = rule_id / 32;
+ rule_bit = rule_id % 32;
+
+ if (rule_idx >= IPAHAL_MAX_RULE_ID_32) {
+ IPAERR("invalid rule_id %d\n", rule_id);
+ return -EINVAL;
+ }
+
+ if (ip == IPA_IP_v4 && filtering)
+ bmsk_ptr =
+ ipa3_ctx->hw_stats.flt_rt.flt_v4_init.rule_id_bitmask;
+ else if (ip == IPA_IP_v4)
+ bmsk_ptr =
+ ipa3_ctx->hw_stats.flt_rt.rt_v4_init.rule_id_bitmask;
+ else if (ip == IPA_IP_v6 && filtering)
+ bmsk_ptr =
+ ipa3_ctx->hw_stats.flt_rt.flt_v6_init.rule_id_bitmask;
+ else
+ bmsk_ptr =
+ ipa3_ctx->hw_stats.flt_rt.rt_v6_init.rule_id_bitmask;
+
+ bmsk_ptr[rule_idx] |= (1 << rule_bit);
+
+ return 0;
+}
+
+int ipa_flt_rt_stats_start(enum ipa_ip_type ip, bool filtering)
+{
+ struct ipahal_stats_init_pyld *pyld;
+ int smem_ofst, smem_size, stats_base, start_id_ofst, end_id_ofst;
+ int start_id, end_id;
+ struct ipahal_stats_init_flt_rt *init;
+ struct ipahal_imm_cmd_dma_shared_mem cmd = { 0 };
+ struct ipahal_imm_cmd_pyld *cmd_pyld;
+ struct ipahal_imm_cmd_register_write flt_rt_base = {0};
+ struct ipahal_imm_cmd_pyld *flt_rt_base_pyld;
+ struct ipahal_imm_cmd_register_write flt_rt_start_id = {0};
+ struct ipahal_imm_cmd_pyld *flt_rt_start_id_pyld;
+ struct ipahal_imm_cmd_register_write flt_rt_end_id = { 0 };
+ struct ipahal_imm_cmd_pyld *flt_rt_end_id_pyld;
+ struct ipa3_desc desc[4] = { {0} };
+ dma_addr_t dma_address;
+ int ret;
+
+ if (!ipa3_ctx->hw_stats.enabled)
+ return 0;
+
+ if (ip == IPA_IP_v4 && filtering) {
+ init = &ipa3_ctx->hw_stats.flt_rt.flt_v4_init;
+ smem_ofst = IPA_MEM_PART(stats_flt_v4_ofst);
+ smem_size = IPA_MEM_PART(stats_flt_v4_size);
+ stats_base = ipahal_get_reg_ofst(IPA_STAT_FILTER_IPV4_BASE);
+ start_id_ofst =
+ ipahal_get_reg_ofst(IPA_STAT_FILTER_IPV4_START_ID);
+ end_id_ofst = ipahal_get_reg_ofst(IPA_STAT_FILTER_IPV4_END_ID);
+ } else if (ip == IPA_IP_v4) {
+ init = &ipa3_ctx->hw_stats.flt_rt.rt_v4_init;
+ smem_ofst = IPA_MEM_PART(stats_rt_v4_ofst);
+ smem_size = IPA_MEM_PART(stats_rt_v4_size);
+ stats_base = ipahal_get_reg_ofst(IPA_STAT_ROUTER_IPV4_BASE);
+ start_id_ofst =
+ ipahal_get_reg_ofst(IPA_STAT_ROUTER_IPV4_START_ID);
+ end_id_ofst = ipahal_get_reg_ofst(IPA_STAT_ROUTER_IPV4_END_ID);
+ } else if (ip == IPA_IP_v6 && filtering) {
+ init = &ipa3_ctx->hw_stats.flt_rt.flt_v6_init;
+ smem_ofst = IPA_MEM_PART(stats_flt_v6_ofst);
+ smem_size = IPA_MEM_PART(stats_flt_v6_size);
+ stats_base = ipahal_get_reg_ofst(IPA_STAT_FILTER_IPV6_BASE);
+ start_id_ofst =
+ ipahal_get_reg_ofst(IPA_STAT_FILTER_IPV6_START_ID);
+ end_id_ofst = ipahal_get_reg_ofst(IPA_STAT_FILTER_IPV6_END_ID);
+ } else {
+ init = &ipa3_ctx->hw_stats.flt_rt.rt_v6_init;
+ smem_ofst = IPA_MEM_PART(stats_rt_v6_ofst);
+ smem_size = IPA_MEM_PART(stats_rt_v6_size);
+ stats_base = ipahal_get_reg_ofst(IPA_STAT_ROUTER_IPV6_BASE);
+ start_id_ofst =
+ ipahal_get_reg_ofst(IPA_STAT_ROUTER_IPV6_START_ID);
+ end_id_ofst = ipahal_get_reg_ofst(IPA_STAT_ROUTER_IPV6_END_ID);
+ }
+
+ for (start_id = 0; start_id < IPAHAL_MAX_RULE_ID_32; start_id++) {
+ if (init->rule_id_bitmask[start_id])
+ break;
+ }
+
+ if (start_id == IPAHAL_MAX_RULE_ID_32) {
+ IPAERR("empty rule ids\n");
+ return -EINVAL;
+ }
+
+ /* every rule_id_bitmask contains 32 rules */
+ start_id *= 32;
+
+ for (end_id = IPAHAL_MAX_RULE_ID_32 - 1; end_id >= 0; end_id--) {
+ if (init->rule_id_bitmask[end_id])
+ break;
+ }
+ end_id = (end_id + 1) * 32 - 1;
+
+ pyld = ipahal_stats_generate_init_pyld(IPAHAL_HW_STATS_FNR, init,
+ false);
+ if (!pyld) {
+ IPAERR("failed to generate pyld\n");
+ return -EPERM;
+ }
+
+ if (pyld->len > smem_size) {
+ IPAERR("SRAM partition too small: %d needed %d\n",
+ smem_size, pyld->len);
+ ret = -EPERM;
+ goto destroy_init_pyld;
+ }
+
+ dma_address = dma_map_single(ipa3_ctx->pdev,
+ pyld->data,
+ pyld->len,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(ipa3_ctx->pdev, dma_address)) {
+ IPAERR("failed to DMA map\n");
+ ret = -EPERM;
+ goto destroy_init_pyld;
+ }
+
+ /* setting the registers and init the stats pyld are done atomically */
+ flt_rt_start_id.skip_pipeline_clear = false;
+ flt_rt_start_id.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR;
+ flt_rt_start_id.offset = start_id_ofst;
+ flt_rt_start_id.value = start_id;
+ flt_rt_start_id.value_mask = 0x3FF;
+ flt_rt_start_id_pyld = ipahal_construct_imm_cmd(
+ IPA_IMM_CMD_REGISTER_WRITE, &flt_rt_start_id, false);
+ if (!flt_rt_start_id_pyld) {
+ IPAERR("failed to construct register_write imm cmd\n");
+ ret = -ENOMEM;
+ goto unmap;
+ }
+ desc[0].opcode = flt_rt_start_id_pyld->opcode;
+ desc[0].pyld = flt_rt_start_id_pyld->data;
+ desc[0].len = flt_rt_start_id_pyld->len;
+ desc[0].type = IPA_IMM_CMD_DESC;
+
+ flt_rt_end_id.skip_pipeline_clear = false;
+ flt_rt_end_id.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR;
+ flt_rt_end_id.offset = end_id_ofst;
+ flt_rt_end_id.value = end_id;
+ flt_rt_end_id.value_mask = 0x3FF;
+ flt_rt_end_id_pyld = ipahal_construct_imm_cmd(
+ IPA_IMM_CMD_REGISTER_WRITE, &flt_rt_end_id, false);
+ if (!flt_rt_end_id_pyld) {
+ IPAERR("failed to construct register_write imm cmd\n");
+ ret = -ENOMEM;
+ goto destroy_flt_rt_start_id;
+ }
+ desc[1].opcode = flt_rt_end_id_pyld->opcode;
+ desc[1].pyld = flt_rt_end_id_pyld->data;
+ desc[1].len = flt_rt_end_id_pyld->len;
+ desc[1].type = IPA_IMM_CMD_DESC;
+
+ flt_rt_base.skip_pipeline_clear = false;
+ flt_rt_base.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR;
+ flt_rt_base.offset = stats_base;
+ flt_rt_base.value = ipa3_ctx->smem_restricted_bytes +
+ smem_ofst;
+ flt_rt_base.value_mask = ~0;
+ flt_rt_base_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_REGISTER_WRITE,
+ &flt_rt_base, false);
+ if (!flt_rt_base_pyld) {
+ IPAERR("failed to construct register_write imm cmd\n");
+ ret = -ENOMEM;
+ goto destroy_flt_rt_end_id;
+ }
+ desc[2].opcode = flt_rt_base_pyld->opcode;
+ desc[2].pyld = flt_rt_base_pyld->data;
+ desc[2].len = flt_rt_base_pyld->len;
+ desc[2].type = IPA_IMM_CMD_DESC;
+
+ cmd.is_read = false;
+ cmd.skip_pipeline_clear = false;
+ cmd.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR;
+ cmd.size = pyld->len;
+ cmd.system_addr = dma_address;
+ cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
+ smem_ofst;
+ cmd_pyld = ipahal_construct_imm_cmd(
+ IPA_IMM_CMD_DMA_SHARED_MEM, &cmd, false);
+ if (!cmd_pyld) {
+ IPAERR("failed to construct dma_shared_mem imm cmd\n");
+ ret = -ENOMEM;
+ goto destroy_flt_rt_base;
+ }
+ desc[3].opcode = cmd_pyld->opcode;
+ desc[3].pyld = cmd_pyld->data;
+ desc[3].len = cmd_pyld->len;
+ desc[3].type = IPA_IMM_CMD_DESC;
+
+ ret = ipa3_send_cmd(4, desc);
+ if (ret) {
+ IPAERR("failed to send immediate command (error %d)\n", ret);
+ goto destroy_imm;
+ }
+
+ ret = 0;
+
+destroy_imm:
+ ipahal_destroy_imm_cmd(cmd_pyld);
+destroy_flt_rt_base:
+ ipahal_destroy_imm_cmd(flt_rt_base_pyld);
+destroy_flt_rt_end_id:
+ ipahal_destroy_imm_cmd(flt_rt_end_id_pyld);
+destroy_flt_rt_start_id:
+ ipahal_destroy_imm_cmd(flt_rt_start_id_pyld);
+unmap:
+ dma_unmap_single(ipa3_ctx->pdev, dma_address, pyld->len, DMA_TO_DEVICE);
+destroy_init_pyld:
+ ipahal_destroy_stats_init_pyld(pyld);
+ return ret;
+}
+
+int ipa_flt_rt_stats_clear_rule_ids(enum ipa_ip_type ip, bool filtering)
+{
+ struct ipahal_stats_init_flt_rt *init;
+ int i;
+
+ if (!ipa3_ctx->hw_stats.enabled)
+ return 0;
+
+ if (ip < 0 || ip >= IPA_IP_MAX) {
+ IPAERR("wrong ip type %d\n", ip);
+ return -EINVAL;
+ }
+
+ if (ip == IPA_IP_v4 && filtering)
+ init = &ipa3_ctx->hw_stats.flt_rt.flt_v4_init;
+ else if (ip == IPA_IP_v4)
+ init = &ipa3_ctx->hw_stats.flt_rt.rt_v4_init;
+ else if (ip == IPA_IP_v6 && filtering)
+ init = &ipa3_ctx->hw_stats.flt_rt.flt_v6_init;
+ else
+ init = &ipa3_ctx->hw_stats.flt_rt.rt_v6_init;
+
+ for (i = 0; i < IPAHAL_MAX_RULE_ID_32; i++)
+ init->rule_id_bitmask[i] = 0;
+
+ return 0;
+}
+
+static int __ipa_get_flt_rt_stats(enum ipa_ip_type ip, bool filtering,
+ u16 rule_id, struct ipa_flt_rt_stats *out)
+{
+ int ret;
+ int smem_ofst;
+ bool clear = false;
+ struct ipahal_stats_get_offset_flt_rt *get_offset;
+ struct ipahal_stats_offset offset = { 0 };
+ struct ipahal_imm_cmd_dma_shared_mem cmd = { 0 };
+ struct ipahal_imm_cmd_pyld *cmd_pyld;
+ struct ipa_mem_buffer mem;
+ struct ipa3_desc desc = { 0 };
+ struct ipahal_stats_flt_rt stats;
+
+ if (rule_id >= IPAHAL_MAX_RULE_ID_32 * 32) {
+ IPAERR("invalid rule_id %d\n", rule_id);
+ return -EINVAL;
+ }
+
+ if (out == NULL)
+ clear = true;
+
+ get_offset = kzalloc(sizeof(*get_offset), GFP_KERNEL);
+ if (!get_offset) {
+ IPADBG("no mem\n");
+ return -ENOMEM;
+ }
+
+ if (ip == IPA_IP_v4 && filtering) {
+ get_offset->init = ipa3_ctx->hw_stats.flt_rt.flt_v4_init;
+ smem_ofst = IPA_MEM_PART(stats_flt_v4_ofst);
+ } else if (ip == IPA_IP_v4) {
+ get_offset->init = ipa3_ctx->hw_stats.flt_rt.rt_v4_init;
+ smem_ofst = IPA_MEM_PART(stats_rt_v4_ofst);
+ } else if (ip == IPA_IP_v6 && filtering) {
+ get_offset->init = ipa3_ctx->hw_stats.flt_rt.flt_v6_init;
+ smem_ofst = IPA_MEM_PART(stats_flt_v6_ofst);
+ } else {
+ get_offset->init = ipa3_ctx->hw_stats.flt_rt.rt_v6_init;
+ smem_ofst = IPA_MEM_PART(stats_rt_v6_ofst);
+ }
+
+ get_offset->rule_id = rule_id;
+
+ ret = ipahal_stats_get_offset(IPAHAL_HW_STATS_FNR, get_offset,
+ &offset);
+ if (ret) {
+ IPAERR("failed to get offset from hal %d\n", ret);
+ goto free_offset;
+ }
+
+ IPADBG_LOW("offset = %d size = %d\n", offset.offset, offset.size);
+
+ mem.size = offset.size;
+ mem.base = dma_alloc_coherent(ipa3_ctx->pdev,
+ mem.size,
+ &mem.phys_base,
+ GFP_KERNEL);
+ if (!mem.base) {
+ IPAERR("fail to alloc DMA memory\n");
+ goto free_offset;
+ }
+
+ cmd.is_read = true;
+ cmd.clear_after_read = clear;
+ cmd.skip_pipeline_clear = false;
+ cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
+ cmd.size = mem.size;
+ cmd.system_addr = mem.phys_base;
+ cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
+ smem_ofst + offset.offset;
+ cmd_pyld = ipahal_construct_imm_cmd(
+ IPA_IMM_CMD_DMA_SHARED_MEM, &cmd, false);
+ if (!cmd_pyld) {
+ IPAERR("failed to construct dma_shared_mem imm cmd\n");
+ ret = -ENOMEM;
+ goto free_dma_mem;
+ }
+ desc.opcode = cmd_pyld->opcode;
+ desc.pyld = cmd_pyld->data;
+ desc.len = cmd_pyld->len;
+ desc.type = IPA_IMM_CMD_DESC;
+
+ ret = ipa3_send_cmd(1, &desc);
+ if (ret) {
+ IPAERR("failed to send immediate command (error %d)\n", ret);
+ goto destroy_imm;
+ }
+
+ ret = ipahal_parse_stats(IPAHAL_HW_STATS_FNR,
+ &get_offset->init, mem.base, &stats);
+ if (ret) {
+ IPAERR("failed to parse stats (error %d)\n", ret);
+ goto destroy_imm;
+ }
+
+ if (out) {
+ out->num_pkts = stats.num_packets;
+ out->num_pkts_hash = stats.num_packets_hash;
+ }
+
+ ret = 0;
+
+destroy_imm:
+ ipahal_destroy_imm_cmd(cmd_pyld);
+free_dma_mem:
+ dma_free_coherent(ipa3_ctx->pdev, mem.size, mem.base, mem.phys_base);
+free_offset:
+ kfree(get_offset);
+ return ret;
+
+}
+
+
+int ipa_get_flt_rt_stats(enum ipa_ip_type ip, bool filtering, u16 rule_id,
+ struct ipa_flt_rt_stats *out)
+{
+ if (!ipa3_ctx->hw_stats.enabled)
+ return 0;
+
+ if (ip < 0 || ip >= IPA_IP_MAX) {
+ IPAERR("wrong ip type %d\n", ip);
+ return -EINVAL;
+ }
+
+ return __ipa_get_flt_rt_stats(ip, filtering, rule_id, out);
+}
+
+int ipa_reset_flt_rt_stats(enum ipa_ip_type ip, bool filtering, u16 rule_id)
+{
+ if (!ipa3_ctx->hw_stats.enabled)
+ return 0;
+
+ if (ip < 0 || ip >= IPA_IP_MAX) {
+ IPAERR("wrong ip type %d\n", ip);
+ return -EINVAL;
+ }
+
+ return __ipa_get_flt_rt_stats(ip, filtering, rule_id, NULL);
+}
+
+int ipa_reset_all_flt_rt_stats(enum ipa_ip_type ip, bool filtering)
+{
+ struct ipahal_stats_init_flt_rt *init;
+ int i;
+
+ if (!ipa3_ctx->hw_stats.enabled)
+ return 0;
+
+ if (ip < 0 || ip >= IPA_IP_MAX) {
+ IPAERR("wrong ip type %d\n", ip);
+ return -EINVAL;
+ }
+
+ if (ip == IPA_IP_v4 && filtering)
+ init = &ipa3_ctx->hw_stats.flt_rt.flt_v4_init;
+ else if (ip == IPA_IP_v4)
+ init = &ipa3_ctx->hw_stats.flt_rt.rt_v4_init;
+ else if (ip == IPA_IP_v6 && filtering)
+ init = &ipa3_ctx->hw_stats.flt_rt.flt_v6_init;
+ else
+ init = &ipa3_ctx->hw_stats.flt_rt.rt_v6_init;
+
+ for (i = 0; i < IPAHAL_MAX_RULE_ID_32 * 32; i++) {
+ int idx = i / 32;
+ int bit = i % 32;
+
+ if (init->rule_id_bitmask[idx] & (1 << bit))
+ __ipa_get_flt_rt_stats(ip, filtering, i, NULL);
+ }
+
+ return 0;
+}
+
+int ipa_init_drop_stats(u32 pipe_bitmask)
+{
+ struct ipahal_stats_init_pyld *pyld;
+ struct ipahal_imm_cmd_dma_shared_mem cmd = { 0 };
+ struct ipahal_imm_cmd_pyld *cmd_pyld;
+ struct ipahal_imm_cmd_register_write drop_base = {0};
+ struct ipahal_imm_cmd_pyld *drop_base_pyld;
+ struct ipahal_imm_cmd_register_write drop_mask = {0};
+ struct ipahal_imm_cmd_pyld *drop_mask_pyld;
+ struct ipa3_desc desc[3] = { {0} };
+ dma_addr_t dma_address;
+ int ret;
+
+ if (!ipa3_ctx->hw_stats.enabled)
+ return 0;
+
+ /* reset driver's cache */
+ memset(&ipa3_ctx->hw_stats.drop, 0, sizeof(ipa3_ctx->hw_stats.drop));
+ ipa3_ctx->hw_stats.drop.init.enabled_bitmask = pipe_bitmask;
+ IPADBG_LOW("pipe_bitmask=0x%x\n", pipe_bitmask);
+
+ pyld = ipahal_stats_generate_init_pyld(IPAHAL_HW_STATS_DROP,
+ &ipa3_ctx->hw_stats.drop.init, false);
+ if (!pyld) {
+ IPAERR("failed to generate pyld\n");
+ return -EPERM;
+ }
+
+ if (pyld->len > IPA_MEM_PART(stats_drop_size)) {
+ IPAERR("SRAM partition too small: %d needed %d\n",
+ IPA_MEM_PART(stats_drop_size), pyld->len);
+ ret = -EPERM;
+ goto destroy_init_pyld;
+ }
+
+ dma_address = dma_map_single(ipa3_ctx->pdev,
+ pyld->data,
+ pyld->len,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(ipa3_ctx->pdev, dma_address)) {
+ IPAERR("failed to DMA map\n");
+ ret = -EPERM;
+ goto destroy_init_pyld;
+ }
+
+ /* setting the registers and init the stats pyld are done atomically */
+ drop_mask.skip_pipeline_clear = false;
+ drop_mask.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR;
+ drop_mask.offset = ipahal_get_reg_n_ofst(IPA_STAT_DROP_CNT_MASK_n,
+ ipa3_ctx->ee);
+ drop_mask.value = pipe_bitmask;
+ drop_mask.value_mask = ~0;
+ drop_mask_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_REGISTER_WRITE,
+ &drop_mask, false);
+ if (!drop_mask_pyld) {
+ IPAERR("failed to construct register_write imm cmd\n");
+ ret = -ENOMEM;
+ goto unmap;
+ }
+ desc[0].opcode = drop_mask_pyld->opcode;
+ desc[0].pyld = drop_mask_pyld->data;
+ desc[0].len = drop_mask_pyld->len;
+ desc[0].type = IPA_IMM_CMD_DESC;
+
+ drop_base.skip_pipeline_clear = false;
+ drop_base.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR;
+ drop_base.offset = ipahal_get_reg_n_ofst(IPA_STAT_DROP_CNT_BASE_n,
+ ipa3_ctx->ee);
+ drop_base.value = ipa3_ctx->smem_restricted_bytes +
+ IPA_MEM_PART(stats_drop_ofst);
+ drop_base.value_mask = ~0;
+ drop_base_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_REGISTER_WRITE,
+ &drop_base, false);
+ if (!drop_base_pyld) {
+ IPAERR("failed to construct register_write imm cmd\n");
+ ret = -ENOMEM;
+ goto destroy_drop_mask;
+ }
+ desc[1].opcode = drop_base_pyld->opcode;
+ desc[1].pyld = drop_base_pyld->data;
+ desc[1].len = drop_base_pyld->len;
+ desc[1].type = IPA_IMM_CMD_DESC;
+
+ cmd.is_read = false;
+ cmd.skip_pipeline_clear = false;
+ cmd.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR;
+ cmd.size = pyld->len;
+ cmd.system_addr = dma_address;
+ cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
+ IPA_MEM_PART(stats_drop_ofst);
+ cmd_pyld = ipahal_construct_imm_cmd(
+ IPA_IMM_CMD_DMA_SHARED_MEM, &cmd, false);
+ if (!cmd_pyld) {
+ IPAERR("failed to construct dma_shared_mem imm cmd\n");
+ ret = -ENOMEM;
+ goto destroy_drop_base;
+ }
+ desc[2].opcode = cmd_pyld->opcode;
+ desc[2].pyld = cmd_pyld->data;
+ desc[2].len = cmd_pyld->len;
+ desc[2].type = IPA_IMM_CMD_DESC;
+
+ ret = ipa3_send_cmd(3, desc);
+ if (ret) {
+ IPAERR("failed to send immediate command (error %d)\n", ret);
+ goto destroy_imm;
+ }
+
+ ret = 0;
+
+destroy_imm:
+ ipahal_destroy_imm_cmd(cmd_pyld);
+destroy_drop_base:
+ ipahal_destroy_imm_cmd(drop_base_pyld);
+destroy_drop_mask:
+ ipahal_destroy_imm_cmd(drop_mask_pyld);
+unmap:
+ dma_unmap_single(ipa3_ctx->pdev, dma_address, pyld->len, DMA_TO_DEVICE);
+destroy_init_pyld:
+ ipahal_destroy_stats_init_pyld(pyld);
+ return ret;
+}
+
+int ipa_get_drop_stats(struct ipa_drop_stats_all *out)
+{
+ int i;
+ int ret;
+ struct ipahal_stats_get_offset_drop get_offset = { { 0 } };
+ struct ipahal_stats_offset offset = { 0 };
+ struct ipahal_imm_cmd_dma_shared_mem cmd = { 0 };
+ struct ipahal_imm_cmd_pyld *cmd_pyld;
+ struct ipa_mem_buffer mem;
+ struct ipa3_desc desc = { 0 };
+ struct ipahal_stats_drop_all *stats;
+
+ if (!ipa3_ctx->hw_stats.enabled)
+ return 0;
+
+ get_offset.init = ipa3_ctx->hw_stats.drop.init;
+ ret = ipahal_stats_get_offset(IPAHAL_HW_STATS_DROP, &get_offset,
+ &offset);
+ if (ret) {
+ IPAERR("failed to get offset from hal %d\n", ret);
+ return ret;
+ }
+
+ IPADBG_LOW("offset = %d size = %d\n", offset.offset, offset.size);
+
+ mem.size = offset.size;
+ mem.base = dma_alloc_coherent(ipa3_ctx->pdev,
+ mem.size,
+ &mem.phys_base,
+ GFP_KERNEL);
+ if (!mem.base) {
+ IPAERR("fail to alloc DMA memory\n");
+ return ret;
+ }
+
+ cmd.is_read = true;
+ cmd.clear_after_read = true;
+ cmd.skip_pipeline_clear = false;
+ cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
+ cmd.size = mem.size;
+ cmd.system_addr = mem.phys_base;
+ cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
+ IPA_MEM_PART(stats_drop_ofst) + offset.offset;
+ cmd_pyld = ipahal_construct_imm_cmd(
+ IPA_IMM_CMD_DMA_SHARED_MEM, &cmd, false);
+ if (!cmd_pyld) {
+ IPAERR("failed to construct dma_shared_mem imm cmd\n");
+ ret = -ENOMEM;
+ goto free_dma_mem;
+ }
+ desc.opcode = cmd_pyld->opcode;
+ desc.pyld = cmd_pyld->data;
+ desc.len = cmd_pyld->len;
+ desc.type = IPA_IMM_CMD_DESC;
+
+ ret = ipa3_send_cmd(1, &desc);
+ if (ret) {
+ IPAERR("failed to send immediate command (error %d)\n", ret);
+ goto destroy_imm;
+ }
+
+ stats = kzalloc(sizeof(*stats), GFP_KERNEL);
+ if (!stats) {
+ IPADBG("failed to alloc memory\n");
+ ret = -ENOMEM;
+ goto destroy_imm;
+ }
+
+ ret = ipahal_parse_stats(IPAHAL_HW_STATS_DROP,
+ &ipa3_ctx->hw_stats.drop.init, mem.base, stats);
+ if (ret) {
+ IPAERR("failed to parse stats (error %d)\n", ret);
+ goto free_stats;
+ }
+
+ /*
+ * update driver cache.
+ * the stats were read from hardware with clear_after_read meaning
+ * hardware stats are 0 now
+ */
+ for (i = 0; i < IPA_CLIENT_MAX; i++) {
+ int ep_idx = ipa3_get_ep_mapping(i);
+
+ if (ep_idx == -1 || ep_idx >= IPA3_MAX_NUM_PIPES)
+ continue;
+
+ if (ipa3_ctx->ep[ep_idx].client != i)
+ continue;
+
+ ipa3_ctx->hw_stats.drop.stats.client[i].drop_byte_cnt +=
+ stats->stats[ep_idx].drop_byte_cnt;
+ ipa3_ctx->hw_stats.drop.stats.client[i].drop_packet_cnt +=
+ stats->stats[ep_idx].drop_packet_cnt;
+ }
+
+
+ if (!out) {
+ ret = 0;
+ goto free_stats;
+ }
+
+ /* copy results to out parameter */
+ *out = ipa3_ctx->hw_stats.drop.stats;
+
+ ret = 0;
+free_stats:
+ kfree(stats);
+destroy_imm:
+ ipahal_destroy_imm_cmd(cmd_pyld);
+free_dma_mem:
+ dma_free_coherent(ipa3_ctx->pdev, mem.size, mem.base, mem.phys_base);
+ return ret;
+
+}
+
+int ipa_reset_drop_stats(enum ipa_client_type client)
+{
+ int ret;
+ struct ipa_drop_stats *stats;
+
+ if (client >= IPA_CLIENT_MAX) {
+ IPAERR("invalid client %d\n", client);
+ return -EINVAL;
+ }
+
+ /* reading stats will reset them in hardware */
+ ret = ipa_get_drop_stats(NULL);
+ if (ret) {
+ IPAERR("ipa_get_drop_stats failed %d\n", ret);
+ return ret;
+ }
+
+ /* reset driver's cache */
+ stats = &ipa3_ctx->hw_stats.drop.stats.client[client];
+ memset(stats, 0, sizeof(*stats));
+ return 0;
+}
+
+int ipa_reset_all_drop_stats(void)
+{
+ int ret;
+ struct ipa_drop_stats_all *stats;
+
+ if (!ipa3_ctx->hw_stats.enabled)
+ return 0;
+
+ /* reading stats will reset them in hardware */
+ ret = ipa_get_drop_stats(NULL);
+ if (ret) {
+ IPAERR("ipa_get_drop_stats failed %d\n", ret);
+ return ret;
+ }
+
+ /* reset driver's cache */
+ stats = &ipa3_ctx->hw_stats.drop.stats;
+ memset(stats, 0, sizeof(*stats));
+ return 0;
+}
+
+
+#ifndef CONFIG_DEBUG_FS
+int ipa_debugfs_init_stats(struct dentry *parent) { return 0; }
+#else
+#define IPA_MAX_MSG_LEN 4096
+static char dbg_buff[IPA_MAX_MSG_LEN];
+
+static ssize_t ipa_debugfs_reset_quota_stats(struct file *file,
+ const char __user *ubuf, size_t count, loff_t *ppos)
+{
+ unsigned long missing;
+ s8 client = 0;
+ int ret;
+
+ mutex_lock(&ipa3_ctx->lock);
+ if (sizeof(dbg_buff) < count + 1) {
+ ret = -EFAULT;
+ goto bail;
+ }
+
+ missing = copy_from_user(dbg_buff, ubuf, count);
+ if (missing) {
+ ret = -EFAULT;
+ goto bail;
+ }
+
+ dbg_buff[count] = '\0';
+ if (kstrtos8(dbg_buff, 0, &client)) {
+ ret = -EFAULT;
+ goto bail;
+ }
+
+ if (client == -1)
+ ipa_reset_all_quota_stats();
+ else
+ ipa_reset_quota_stats(client);
+
+ ret = count;
+bail:
+ mutex_unlock(&ipa3_ctx->lock);
+ return ret;
+}
+
+static ssize_t ipa_debugfs_print_quota_stats(struct file *file,
+ char __user *ubuf, size_t count, loff_t *ppos)
+{
+ int nbytes = 0;
+ struct ipa_quota_stats_all *out;
+ int i;
+ int res;
+
+ out = kzalloc(sizeof(*out), GFP_KERNEL);
+ if (!out)
+ return -ENOMEM;
+
+ mutex_lock(&ipa3_ctx->lock);
+ res = ipa_get_quota_stats(out);
+ if (res) {
+ mutex_unlock(&ipa3_ctx->lock);
+ kfree(out);
+ return res;
+ }
+ for (i = 0; i < IPA_CLIENT_MAX; i++) {
+ int ep_idx = ipa3_get_ep_mapping(i);
+
+ if (ep_idx == -1)
+ continue;
+
+ if (IPA_CLIENT_IS_TEST(i))
+ continue;
+
+ if (!(ipa3_ctx->hw_stats.quota.init.enabled_bitmask &
+ (1 << ep_idx)))
+ continue;
+
+ nbytes += scnprintf(dbg_buff + nbytes,
+ IPA_MAX_MSG_LEN - nbytes,
+ "%s:\n",
+ ipa_clients_strings[i]);
+ nbytes += scnprintf(dbg_buff + nbytes,
+ IPA_MAX_MSG_LEN - nbytes,
+ "num_ipv4_bytes=%llu\n",
+ out->client[i].num_ipv4_bytes);
+ nbytes += scnprintf(dbg_buff + nbytes,
+ IPA_MAX_MSG_LEN - nbytes,
+ "num_ipv6_bytes=%llu\n",
+ out->client[i].num_ipv6_bytes);
+ nbytes += scnprintf(dbg_buff + nbytes,
+ IPA_MAX_MSG_LEN - nbytes,
+ "num_ipv4_pkts=%u\n",
+ out->client[i].num_ipv4_pkts);
+ nbytes += scnprintf(dbg_buff + nbytes,
+ IPA_MAX_MSG_LEN - nbytes,
+ "num_ipv6_pkts=%u\n",
+ out->client[i].num_ipv6_pkts);
+ nbytes += scnprintf(dbg_buff + nbytes,
+ IPA_MAX_MSG_LEN - nbytes,
+ "\n");
+
+ }
+ mutex_unlock(&ipa3_ctx->lock);
+ kfree(out);
+
+ return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes);
+}
+
+static ssize_t ipa_debugfs_reset_tethering_stats(struct file *file,
+ const char __user *ubuf, size_t count, loff_t *ppos)
+{
+ unsigned long missing;
+ s8 client = 0;
+ int ret;
+
+ mutex_lock(&ipa3_ctx->lock);
+ if (sizeof(dbg_buff) < count + 1) {
+ ret = -EFAULT;
+ goto bail;
+ }
+
+ missing = copy_from_user(dbg_buff, ubuf, count);
+ if (missing) {
+ ret = -EFAULT;
+ goto bail;
+ }
+
+ dbg_buff[count] = '\0';
+ if (kstrtos8(dbg_buff, 0, &client)) {
+ ret = -EFAULT;
+ goto bail;
+ }
+
+ if (client == -1)
+ ipa_reset_all_teth_stats();
+ else
+ ipa_reset_all_cons_teth_stats(client);
+
+ ret = count;
+bail:
+ mutex_unlock(&ipa3_ctx->lock);
+ return ret;
+}
+
+static ssize_t ipa_debugfs_print_tethering_stats(struct file *file,
+ char __user *ubuf, size_t count, loff_t *ppos)
+{
+ int nbytes = 0;
+ struct ipa_quota_stats_all *out;
+ int i, j;
+ int res;
+
+ out = kzalloc(sizeof(*out), GFP_KERNEL);
+ if (!out)
+ return -ENOMEM;
+
+ mutex_lock(&ipa3_ctx->lock);
+ for (i = 0; i < IPA_CLIENT_MAX; i++) {
+ int ep_idx = ipa3_get_ep_mapping(i);
+
+ if (ep_idx == -1)
+ continue;
+
+ if (!IPA_CLIENT_IS_PROD(i))
+ continue;
+
+ if (IPA_CLIENT_IS_TEST(i))
+ continue;
+
+ if (!(ipa3_ctx->hw_stats.teth.init.prod_bitmask &
+ (1 << ep_idx)))
+ continue;
+
+ res = ipa_get_teth_stats(i, out);
+ if (res) {
+ mutex_unlock(&ipa3_ctx->lock);
+ kfree(out);
+ return res;
+ }
+
+ for (j = 0; j < IPA_CLIENT_MAX; j++) {
+ int cons_idx = ipa3_get_ep_mapping(j);
+
+ if (cons_idx == -1)
+ continue;
+
+ if (IPA_CLIENT_IS_TEST(j))
+ continue;
+
+ if (!(ipa3_ctx->hw_stats.teth.init.cons_bitmask[ep_idx]
+ & (1 << cons_idx)))
+ continue;
+
+ nbytes += scnprintf(dbg_buff + nbytes,
+ IPA_MAX_MSG_LEN - nbytes,
+ "%s->%s:\n",
+ ipa_clients_strings[i],
+ ipa_clients_strings[j]);
+ nbytes += scnprintf(dbg_buff + nbytes,
+ IPA_MAX_MSG_LEN - nbytes,
+ "num_ipv4_bytes=%llu\n",
+ out->client[j].num_ipv4_bytes);
+ nbytes += scnprintf(dbg_buff + nbytes,
+ IPA_MAX_MSG_LEN - nbytes,
+ "num_ipv6_bytes=%llu\n",
+ out->client[j].num_ipv6_bytes);
+ nbytes += scnprintf(dbg_buff + nbytes,
+ IPA_MAX_MSG_LEN - nbytes,
+ "num_ipv4_pkts=%u\n",
+ out->client[j].num_ipv4_pkts);
+ nbytes += scnprintf(dbg_buff + nbytes,
+ IPA_MAX_MSG_LEN - nbytes,
+ "num_ipv6_pkts=%u\n",
+ out->client[j].num_ipv6_pkts);
+ nbytes += scnprintf(dbg_buff + nbytes,
+ IPA_MAX_MSG_LEN - nbytes,
+ "\n");
+ }
+ }
+ mutex_unlock(&ipa3_ctx->lock);
+ kfree(out);
+
+ return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes);
+}
+
+static ssize_t ipa_debugfs_control_flt_rt_stats(enum ipa_ip_type ip,
+ bool filtering, struct file *file,
+ const char __user *ubuf, size_t count, loff_t *ppos)
+{
+ unsigned long missing;
+ u16 rule_id = 0;
+ int ret;
+
+ mutex_lock(&ipa3_ctx->lock);
+ if (sizeof(dbg_buff) < count + 1) {
+ ret = -EFAULT;
+ goto bail;
+ }
+
+ missing = copy_from_user(dbg_buff, ubuf, count);
+ if (missing) {
+ ret = -EFAULT;
+ goto bail;
+ }
+
+ dbg_buff[count] = '\0';
+ if (strcmp(dbg_buff, "start\n") == 0) {
+ ipa_flt_rt_stats_start(ip, filtering);
+ } else if (strcmp(dbg_buff, "clear\n") == 0) {
+ ipa_flt_rt_stats_clear_rule_ids(ip, filtering);
+ } else if (strcmp(dbg_buff, "reset\n") == 0) {
+ ipa_reset_all_flt_rt_stats(ip, filtering);
+ } else {
+ if (kstrtou16(dbg_buff, 0, &rule_id)) {
+ ret = -EFAULT;
+ goto bail;
+ }
+ ipa_flt_rt_stats_add_rule_id(ip, filtering, rule_id);
+ }
+
+ ret = count;
+bail:
+ mutex_unlock(&ipa3_ctx->lock);
+ return ret;
+}
+
+static ssize_t ipa_debugfs_print_flt_rt_stats(enum ipa_ip_type ip,
+ bool filtering, struct file *file,
+ char __user *ubuf, size_t count, loff_t *ppos)
+{
+ int nbytes = 0;
+ struct ipahal_stats_init_flt_rt *init;
+ struct ipa_flt_rt_stats out;
+ int i;
+ int res;
+
+ if (ip == IPA_IP_v4 && filtering)
+ init = &ipa3_ctx->hw_stats.flt_rt.flt_v4_init;
+ else if (ip == IPA_IP_v4)
+ init = &ipa3_ctx->hw_stats.flt_rt.rt_v4_init;
+ else if (ip == IPA_IP_v6 && filtering)
+ init = &ipa3_ctx->hw_stats.flt_rt.flt_v6_init;
+ else
+ init = &ipa3_ctx->hw_stats.flt_rt.rt_v6_init;
+
+ mutex_lock(&ipa3_ctx->lock);
+ for (i = 0; i < IPAHAL_MAX_RULE_ID_32 * 32; i++) {
+ int idx = i / 32;
+ int bit = i % 32;
+
+ if (init->rule_id_bitmask[idx] & (1 << bit)) {
+ res = ipa_get_flt_rt_stats(ip, filtering, i, &out);
+ if (res) {
+ mutex_unlock(&ipa3_ctx->lock);
+ return res;
+ }
+
+ nbytes += scnprintf(dbg_buff + nbytes,
+ IPA_MAX_MSG_LEN - nbytes,
+ "rule_id: %d\n", i);
+ nbytes += scnprintf(dbg_buff + nbytes,
+ IPA_MAX_MSG_LEN - nbytes,
+ "num_pkts: %d\n",
+ out.num_pkts);
+ nbytes += scnprintf(dbg_buff + nbytes,
+ IPA_MAX_MSG_LEN - nbytes,
+ "num_pkts_hash: %d\n",
+ out.num_pkts_hash);
+ nbytes += scnprintf(dbg_buff + nbytes,
+ IPA_MAX_MSG_LEN - nbytes,
+ "\n");
+ }
+ }
+
+ mutex_unlock(&ipa3_ctx->lock);
+
+ return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes);
+}
+
+static ssize_t ipa_debugfs_reset_drop_stats(struct file *file,
+ const char __user *ubuf, size_t count, loff_t *ppos)
+{
+ unsigned long missing;
+ s8 client = 0;
+ int ret;
+
+ mutex_lock(&ipa3_ctx->lock);
+ if (sizeof(dbg_buff) < count + 1) {
+ ret = -EFAULT;
+ goto bail;
+ }
+
+ missing = copy_from_user(dbg_buff, ubuf, count);
+ if (missing) {
+ ret = -EFAULT;
+ goto bail;
+ }
+
+ dbg_buff[count] = '\0';
+ if (kstrtos8(dbg_buff, 0, &client)) {
+ ret = -EFAULT;
+ goto bail;
+ }
+
+ if (client == -1)
+ ipa_reset_all_drop_stats();
+ else
+ ipa_reset_drop_stats(client);
+
+ ret = count;
+bail:
+ mutex_unlock(&ipa3_ctx->lock);
+ return count;
+}
+
+static ssize_t ipa_debugfs_print_drop_stats(struct file *file,
+ char __user *ubuf, size_t count, loff_t *ppos)
+{
+ int nbytes = 0;
+ struct ipa_drop_stats_all *out;
+ int i;
+ int res;
+
+ out = kzalloc(sizeof(*out), GFP_KERNEL);
+ if (!out)
+ return -ENOMEM;
+
+ mutex_lock(&ipa3_ctx->lock);
+ res = ipa_get_drop_stats(out);
+ if (res) {
+ mutex_unlock(&ipa3_ctx->lock);
+ kfree(out);
+ return res;
+ }
+
+ for (i = 0; i < IPA_CLIENT_MAX; i++) {
+ int ep_idx = ipa3_get_ep_mapping(i);
+
+ if (ep_idx == -1)
+ continue;
+
+ if (!IPA_CLIENT_IS_CONS(i))
+ continue;
+
+ if (IPA_CLIENT_IS_TEST(i))
+ continue;
+
+ if (!(ipa3_ctx->hw_stats.drop.init.enabled_bitmask &
+ (1 << ep_idx)))
+ continue;
+
+
+ nbytes += scnprintf(dbg_buff + nbytes,
+ IPA_MAX_MSG_LEN - nbytes,
+ "%s:\n",
+ ipa_clients_strings[i]);
+
+ nbytes += scnprintf(dbg_buff + nbytes,
+ IPA_MAX_MSG_LEN - nbytes,
+ "drop_byte_cnt=%u\n",
+ out->client[i].drop_byte_cnt);
+
+ nbytes += scnprintf(dbg_buff + nbytes,
+ IPA_MAX_MSG_LEN - nbytes,
+ "drop_packet_cnt=%u\n",
+ out->client[i].drop_packet_cnt);
+ nbytes += scnprintf(dbg_buff + nbytes,
+ IPA_MAX_MSG_LEN - nbytes,
+ "\n");
+ }
+ mutex_unlock(&ipa3_ctx->lock);
+ kfree(out);
+
+ return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes);
+}
+
+static ssize_t ipa_debugfs_control_flt_v4_stats(struct file *file,
+ const char __user *ubuf, size_t count, loff_t *ppos)
+{
+ return ipa_debugfs_control_flt_rt_stats(IPA_IP_v4, true, file, ubuf,
+ count, ppos);
+}
+
+static ssize_t ipa_debugfs_control_flt_v6_stats(struct file *file,
+ const char __user *ubuf, size_t count, loff_t *ppos)
+{
+ return ipa_debugfs_control_flt_rt_stats(IPA_IP_v6, true, file, ubuf,
+ count, ppos);
+}
+
+static ssize_t ipa_debugfs_control_rt_v4_stats(struct file *file,
+ const char __user *ubuf, size_t count, loff_t *ppos)
+{
+ return ipa_debugfs_control_flt_rt_stats(IPA_IP_v4, false, file, ubuf,
+ count, ppos);
+}
+
+static ssize_t ipa_debugfs_control_rt_v6_stats(struct file *file,
+ const char __user *ubuf, size_t count, loff_t *ppos)
+{
+ return ipa_debugfs_control_flt_rt_stats(IPA_IP_v6, false, file, ubuf,
+ count, ppos);
+}
+
+static ssize_t ipa_debugfs_print_flt_v4_stats(struct file *file,
+ char __user *ubuf, size_t count, loff_t *ppos)
+{
+ return ipa_debugfs_print_flt_rt_stats(IPA_IP_v4, true, file, ubuf,
+ count, ppos);
+}
+
+static ssize_t ipa_debugfs_print_flt_v6_stats(struct file *file,
+ char __user *ubuf, size_t count, loff_t *ppos)
+{
+ return ipa_debugfs_print_flt_rt_stats(IPA_IP_v6, true, file, ubuf,
+ count, ppos);
+}
+
+static ssize_t ipa_debugfs_print_rt_v4_stats(struct file *file,
+ char __user *ubuf, size_t count, loff_t *ppos)
+{
+ return ipa_debugfs_print_flt_rt_stats(IPA_IP_v4, false, file, ubuf,
+ count, ppos);
+}
+
+static ssize_t ipa_debugfs_print_rt_v6_stats(struct file *file,
+ char __user *ubuf, size_t count, loff_t *ppos)
+{
+ return ipa_debugfs_print_flt_rt_stats(IPA_IP_v6, false, file, ubuf,
+ count, ppos);
+}
+
+static const struct file_operations ipa3_quota_ops = {
+ .read = ipa_debugfs_print_quota_stats,
+ .write = ipa_debugfs_reset_quota_stats,
+};
+
+static const struct file_operations ipa3_tethering_ops = {
+ .read = ipa_debugfs_print_tethering_stats,
+ .write = ipa_debugfs_reset_tethering_stats,
+};
+
+static const struct file_operations ipa3_flt_v4_ops = {
+ .read = ipa_debugfs_print_flt_v4_stats,
+ .write = ipa_debugfs_control_flt_v4_stats,
+};
+
+static const struct file_operations ipa3_flt_v6_ops = {
+ .read = ipa_debugfs_print_flt_v6_stats,
+ .write = ipa_debugfs_control_flt_v6_stats,
+};
+
+static const struct file_operations ipa3_rt_v4_ops = {
+ .read = ipa_debugfs_print_rt_v4_stats,
+ .write = ipa_debugfs_control_rt_v4_stats,
+};
+
+static const struct file_operations ipa3_rt_v6_ops = {
+ .read = ipa_debugfs_print_rt_v6_stats,
+ .write = ipa_debugfs_control_rt_v6_stats,
+};
+
+static const struct file_operations ipa3_drop_ops = {
+ .read = ipa_debugfs_print_drop_stats,
+ .write = ipa_debugfs_reset_drop_stats,
+};
+
+
+int ipa_debugfs_init_stats(struct dentry *parent)
+{
+ const mode_t read_write_mode = 0664;
+ struct dentry *file;
+ struct dentry *dent;
+
+ if (!ipa3_ctx->hw_stats.enabled)
+ return 0;
+
+ dent = debugfs_create_dir("hw_stats", parent);
+ if (IS_ERR_OR_NULL(dent)) {
+ IPAERR("fail to create folder in debug_fs\n");
+ return -EFAULT;
+ }
+
+ file = debugfs_create_file("quota", read_write_mode, dent, NULL,
+ &ipa3_quota_ops);
+ if (IS_ERR_OR_NULL(file)) {
+ IPAERR("fail to create file %s\n", "quota");
+ goto fail;
+ }
+
+ file = debugfs_create_file("drop", read_write_mode, dent, NULL,
+ &ipa3_drop_ops);
+ if (IS_ERR_OR_NULL(file)) {
+ IPAERR("fail to create file %s\n", "drop");
+ goto fail;
+ }
+
+ file = debugfs_create_file("tethering", read_write_mode, dent, NULL,
+ &ipa3_tethering_ops);
+ if (IS_ERR_OR_NULL(file)) {
+ IPAERR("fail to create file %s\n", "tethering");
+ goto fail;
+ }
+
+ file = debugfs_create_file("flt_v4", read_write_mode, dent, NULL,
+ &ipa3_flt_v4_ops);
+ if (IS_ERR_OR_NULL(file)) {
+ IPAERR("fail to create file %s\n", "flt_v4");
+ goto fail;
+ }
+
+ file = debugfs_create_file("flt_v6", read_write_mode, dent, NULL,
+ &ipa3_flt_v6_ops);
+ if (IS_ERR_OR_NULL(file)) {
+ IPAERR("fail to create file %s\n", "flt_v6");
+ goto fail;
+ }
+
+ file = debugfs_create_file("rt_v4", read_write_mode, dent, NULL,
+ &ipa3_rt_v4_ops);
+ if (IS_ERR_OR_NULL(file)) {
+ IPAERR("fail to create file %s\n", "rt_v4");
+ goto fail;
+ }
+
+ file = debugfs_create_file("rt_v6", read_write_mode, dent, NULL,
+ &ipa3_rt_v6_ops);
+ if (IS_ERR_OR_NULL(file)) {
+ IPAERR("fail to create file %s\n", "rt_v6");
+ goto fail;
+ }
+
+ return 0;
+fail:
+ debugfs_remove_recursive(dent);
+ return -EFAULT;
+}
+#endif
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
index 1bed1c8..43fd4d1 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
@@ -33,6 +33,7 @@
#include "ipahal/ipahal_reg.h"
#include "ipahal/ipahal.h"
#include "ipahal/ipahal_fltrt.h"
+#include "ipahal/ipahal_hw_stats.h"
#include "../ipa_common_i.h"
#include "ipa_uc_offload_i.h"
@@ -100,6 +101,18 @@
} \
} while (0)
+#define IPAERR_RL(fmt, args...) \
+ do { \
+ pr_err_ratelimited(DRV_NAME " %s:%d " fmt, __func__,\
+ __LINE__, ## args);\
+ if (ipa3_ctx) { \
+ IPA_IPC_LOGGING(ipa3_ctx->logbuf, \
+ DRV_NAME " %s:%d " fmt, ## args); \
+ IPA_IPC_LOGGING(ipa3_ctx->logbuf_low, \
+ DRV_NAME " %s:%d " fmt, ## args); \
+ } \
+ } while (0)
+
#define WLAN_AMPDU_TX_EP 15
#define WLAN_PROD_TX_EP 19
#define WLAN1_CONS_RX_EP 14
@@ -175,6 +188,7 @@
};
struct ipa3_active_clients_log_ctx {
+ spinlock_t lock;
char *log_buffer[IPA3_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES];
int log_head;
int log_tail;
@@ -238,7 +252,7 @@
* @curr_mem: current routing tables block in sys memory
* @prev_mem: previous routing table block in sys memory
* @id: routing table id
- * @rule_ids: idr structure that holds the rule_id for each rule
+ * @rule_ids: common idr structure that holds the rule_id for each rule
*/
struct ipa3_rt_tbl {
struct list_head link;
@@ -254,7 +268,7 @@
struct ipa_mem_buffer curr_mem[IPA_RULE_TYPE_MAX];
struct ipa_mem_buffer prev_mem[IPA_RULE_TYPE_MAX];
int id;
- struct idr rule_ids;
+ struct idr *rule_ids;
};
/**
@@ -341,7 +355,7 @@
struct list_head link;
u32 cookie;
enum ipa_hdr_proc_type type;
- union ipa_l2tp_hdr_proc_ctx_params l2tp_params;
+ struct ipa_l2tp_hdr_proc_ctx_params l2tp_params;
struct ipa3_hdr_proc_ctx_offset_entry *offset_entry;
struct ipa3_hdr_entry *hdr;
u32 ref_cnt;
@@ -376,7 +390,7 @@
* @end: the last header index
* @curr_mem: current filter tables block in sys memory
* @prev_mem: previous filter table block in sys memory
- * @rule_ids: idr structure that holds the rule_id for each rule
+ * @rule_ids: common idr structure that holds the rule_id for each rule
*/
struct ipa3_flt_tbl {
struct list_head head_flt_rule_list;
@@ -386,7 +400,7 @@
struct ipa_mem_buffer curr_mem[IPA_RULE_TYPE_MAX];
struct ipa_mem_buffer prev_mem[IPA_RULE_TYPE_MAX];
bool sticky_rear;
- struct idr rule_ids;
+ struct idr *rule_ids;
};
/**
@@ -420,10 +434,12 @@
* struct ipa3_rt_tbl_set - collection of routing tables
* @head_rt_tbl_list: collection of routing tables
* @tbl_cnt: number of routing tables
+ * @rule_ids: idr structure that holds the rule_id for each rule
*/
struct ipa3_rt_tbl_set {
struct list_head head_rt_tbl_list;
u32 tbl_cnt;
+ struct idr rule_ids;
};
/**
@@ -1022,6 +1038,56 @@
struct ipahal_imm_cmd_pyld *cmd_pyld;
};
+struct ipa_quota_stats {
+ u64 num_ipv4_bytes;
+ u64 num_ipv6_bytes;
+ u32 num_ipv4_pkts;
+ u32 num_ipv6_pkts;
+};
+
+struct ipa_quota_stats_all {
+ struct ipa_quota_stats client[IPA_CLIENT_MAX];
+};
+
+struct ipa_drop_stats {
+ u32 drop_packet_cnt;
+ u32 drop_byte_cnt;
+};
+
+struct ipa_drop_stats_all {
+ struct ipa_drop_stats client[IPA_CLIENT_MAX];
+};
+
+struct ipa_hw_stats_quota {
+ struct ipahal_stats_init_quota init;
+ struct ipa_quota_stats_all stats;
+};
+
+struct ipa_hw_stats_teth {
+ struct ipahal_stats_init_tethering init;
+ struct ipa_quota_stats_all prod_stats[IPA_CLIENT_MAX];
+};
+
+struct ipa_hw_stats_flt_rt {
+ struct ipahal_stats_init_flt_rt flt_v4_init;
+ struct ipahal_stats_init_flt_rt flt_v6_init;
+ struct ipahal_stats_init_flt_rt rt_v4_init;
+ struct ipahal_stats_init_flt_rt rt_v6_init;
+};
+
+struct ipa_hw_stats_drop {
+ struct ipahal_stats_init_drop init;
+ struct ipa_drop_stats_all stats;
+};
+
+struct ipa_hw_stats {
+ bool enabled;
+ struct ipa_hw_stats_quota quota;
+ struct ipa_hw_stats_teth teth;
+ struct ipa_hw_stats_flt_rt flt_rt;
+ struct ipa_hw_stats_drop drop;
+};
+
/**
* struct ipa3_context - IPA context
* @class: pointer to the struct class
@@ -1035,6 +1101,7 @@
* @ep_flt_num: End-points supporting filtering number
* @resume_on_connect: resume ep on ipa connect
* @flt_tbl: list of all IPA filter tables
+ * @flt_rule_ids: idr structure that holds the rule_id for each rule
* @mode: IPA operating mode
* @mmio: iomem
* @ipa_wrapper_base: IPA wrapper base address
@@ -1120,6 +1187,7 @@
u32 ep_flt_num;
bool resume_on_connect[IPA_CLIENT_MAX];
struct ipa3_flt_tbl flt_tbl[IPA3_MAX_NUM_PIPES][IPA_IP_MAX];
+ struct idr flt_rule_ids[IPA_IP_MAX];
void __iomem *mmio;
u32 ipa_wrapper_base;
u32 ipa_wrapper_size;
@@ -1234,6 +1302,7 @@
u32 ipa_tz_unlock_reg_num;
struct ipa_tz_unlock_reg_info *ipa_tz_unlock_reg;
struct ipa_dma_task_info dma_task_info;
+ struct ipa_hw_stats hw_stats;
};
struct ipa3_plat_drv_res {
@@ -1346,6 +1415,48 @@
* +-------------------------+
* | CANARY |
* +-------------------------+
+ * | QUOTA STATS |
+ * +-------------------------+
+ * | CANARY |
+ * +-------------------------+
+ * | CANARY |
+ * +-------------------------+
+ * | TETH STATS |
+ * +-------------------------+
+ * | CANARY |
+ * +-------------------------+
+ * | CANARY |
+ * +-------------------------+
+ * | V4 FLT STATS |
+ * +-------------------------+
+ * | CANARY |
+ * +-------------------------+
+ * | CANARY |
+ * +-------------------------+
+ * | V6 FLT STATS |
+ * +-------------------------+
+ * | CANARY |
+ * +-------------------------+
+ * | CANARY |
+ * +-------------------------+
+ * | V4 RT STATS |
+ * +-------------------------+
+ * | CANARY |
+ * +-------------------------+
+ * | CANARY |
+ * +-------------------------+
+ * | V6 RT STATS |
+ * +-------------------------+
+ * | CANARY |
+ * +-------------------------+
+ * | CANARY |
+ * +-------------------------+
+ * | DROP STATS |
+ * +-------------------------+
+ * | CANARY |
+ * +-------------------------+
+ * | CANARY |
+ * +-------------------------+
* | MODEM MEM |
* +-------------------------+
* | CANARY |
@@ -1428,6 +1539,20 @@
u32 uc_event_ring_size;
u32 pdn_config_ofst;
u32 pdn_config_size;
+ u32 stats_quota_ofst;
+ u32 stats_quota_size;
+ u32 stats_tethering_ofst;
+ u32 stats_tethering_size;
+ u32 stats_flt_v4_ofst;
+ u32 stats_flt_v4_size;
+ u32 stats_flt_v6_ofst;
+ u32 stats_flt_v6_size;
+ u32 stats_rt_v4_ofst;
+ u32 stats_rt_v4_size;
+ u32 stats_rt_v6_ofst;
+ u32 stats_rt_v6_size;
+ u32 stats_drop_ofst;
+ u32 stats_drop_size;
};
struct ipa3_controller {
@@ -1875,10 +2000,6 @@
void *private_data,
void *interrupt_data);
-
-int ipa_bridge_init(void);
-void ipa_bridge_cleanup(void);
-
ssize_t ipa3_read(struct file *filp, char __user *buf, size_t count,
loff_t *f_pos);
int ipa3_pull_msg(struct ipa_msg_meta *meta, char *buff, size_t count);
@@ -1978,6 +2099,65 @@
(enum ipa_client_type client);
void ipa3_uc_rg10_write_reg(enum ipahal_reg_name reg, u32 n, u32 val);
+/* Hardware stats */
+
+#define IPA_STATS_MAX_PIPE_BIT 32
+
+struct ipa_teth_stats_endpoints {
+ u32 prod_mask;
+ u32 dst_ep_mask[IPA_STATS_MAX_PIPE_BIT];
+};
+
+struct ipa_flt_rt_stats {
+ u32 num_pkts;
+ u32 num_pkts_hash;
+};
+
+int ipa_hw_stats_init(void);
+
+int ipa_debugfs_init_stats(struct dentry *parent);
+
+int ipa_init_quota_stats(u32 pipe_bitmask);
+
+int ipa_get_quota_stats(struct ipa_quota_stats_all *out);
+
+int ipa_reset_quota_stats(enum ipa_client_type client);
+
+int ipa_reset_all_quota_stats(void);
+
+int ipa_init_drop_stats(u32 pipe_bitmask);
+
+int ipa_get_drop_stats(struct ipa_drop_stats_all *out);
+
+int ipa_reset_drop_stats(enum ipa_client_type client);
+
+int ipa_reset_all_drop_stats(void);
+
+int ipa_init_teth_stats(struct ipa_teth_stats_endpoints *in);
+
+int ipa_get_teth_stats(enum ipa_client_type prod,
+ struct ipa_quota_stats_all *out);
+
+int ipa_reset_teth_stats(enum ipa_client_type prod, enum ipa_client_type cons);
+
+int ipa_reset_all_cons_teth_stats(enum ipa_client_type prod);
+
+int ipa_reset_all_teth_stats(void);
+
+int ipa_flt_rt_stats_add_rule_id(enum ipa_ip_type ip, bool filtering,
+ u16 rule_id);
+
+int ipa_flt_rt_stats_start(enum ipa_ip_type ip, bool filtering);
+
+int ipa_flt_rt_stats_clear_rule_ids(enum ipa_ip_type ip, bool filtering);
+
+int ipa_get_flt_rt_stats(enum ipa_ip_type ip, bool filtering, u16 rule_id,
+ struct ipa_flt_rt_stats *out);
+
+int ipa_reset_flt_rt_stats(enum ipa_ip_type ip, bool filtering, u16 rule_id);
+
+int ipa_reset_all_flt_rt_stats(enum ipa_ip_type ip, bool filtering);
+
u32 ipa3_get_num_pipes(void);
struct ipa_smmu_cb_ctx *ipa3_get_smmu_ctx(void);
struct ipa_smmu_cb_ctx *ipa3_get_wlan_smmu_ctx(void);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c b/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c
index 38e8d4e..2bd7b79 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c
@@ -227,7 +227,7 @@
if (strnlen(lookup->name, IPA_RESOURCE_NAME_MAX) ==
IPA_RESOURCE_NAME_MAX) {
- IPAERR("Interface name too long. (%s)\n", lookup->name);
+ IPAERR_RL("Interface name too long. (%s)\n", lookup->name);
return result;
}
@@ -268,7 +268,7 @@
}
if (strnlen(tx->name, IPA_RESOURCE_NAME_MAX) == IPA_RESOURCE_NAME_MAX) {
- IPAERR("Interface name too long. (%s)\n", tx->name);
+ IPAERR_RL("Interface name too long. (%s)\n", tx->name);
return result;
}
@@ -315,7 +315,7 @@
}
if (strnlen(rx->name, IPA_RESOURCE_NAME_MAX) == IPA_RESOURCE_NAME_MAX) {
- IPAERR("Interface name too long. (%s)\n", rx->name);
+ IPAERR_RL("Interface name too long. (%s)\n", rx->name);
return result;
}
@@ -410,13 +410,13 @@
if (meta == NULL || (buff == NULL && callback != NULL) ||
(buff != NULL && callback == NULL)) {
- IPAERR("invalid param meta=%p buff=%p, callback=%p\n",
+ IPAERR_RL("invalid param meta=%p buff=%p, callback=%p\n",
meta, buff, callback);
return -EINVAL;
}
if (meta->msg_type >= IPA_EVENT_MAX_NUM) {
- IPAERR("unsupported message type %d\n", meta->msg_type);
+ IPAERR_RL("unsupported message type %d\n", meta->msg_type);
return -EINVAL;
}
@@ -640,7 +640,7 @@
int result = -EINVAL;
if (meta == NULL || buff == NULL || !count) {
- IPAERR("invalid param name=%p buff=%p count=%zu\n",
+ IPAERR_RL("invalid param name=%p buff=%p count=%zu\n",
meta, buff, count);
return result;
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c b/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c
index a153f2d..958fc6c 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c
@@ -253,8 +253,8 @@
mutex_lock(&nat_ctx->lock);
if (strcmp(mem->dev_name, NAT_DEV_NAME)) {
- IPAERR("Nat device name mismatch\n");
- IPAERR("Expect: %s Recv: %s\n", NAT_DEV_NAME, mem->dev_name);
+ IPAERR_RL("Nat device name mismatch\n");
+ IPAERR_RL("Expect: %s Recv: %s\n", NAT_DEV_NAME, mem->dev_name);
result = -EPERM;
goto bail;
}
@@ -273,7 +273,7 @@
if (mem->size <= 0 ||
nat_ctx->is_dev_init == true) {
- IPAERR("Invalid Parameters or device is already init\n");
+ IPAERR_RL("Invalid Parameters or device is already init\n");
result = -EPERM;
goto bail;
}
@@ -371,7 +371,7 @@
/* check for integer overflow */
if (init->ipv4_rules_offset >
UINT_MAX - (TBL_ENTRY_SIZE * (init->table_entries + 1))) {
- IPAERR("Detected overflow\n");
+ IPAERR_RL("Detected overflow\n");
return -EPERM;
}
/* Check Table Entry offset is not
@@ -380,8 +380,8 @@
tmp = init->ipv4_rules_offset +
(TBL_ENTRY_SIZE * (init->table_entries + 1));
if (tmp > ipa3_ctx->nat_mem.size) {
- IPAERR("Table rules offset not valid\n");
- IPAERR("offset:%d entrys:%d size:%zu mem_size:%zu\n",
+ IPAERR_RL("Table rules offset not valid\n");
+ IPAERR_RL("offset:%d entrys:%d size:%zu mem_size:%zu\n",
init->ipv4_rules_offset, (init->table_entries + 1),
tmp, ipa3_ctx->nat_mem.size);
return -EPERM;
@@ -389,8 +389,8 @@
/* check for integer overflow */
if (init->expn_rules_offset >
- UINT_MAX - (TBL_ENTRY_SIZE * init->expn_table_entries)) {
- IPAERR("Detected overflow\n");
+ (UINT_MAX - (TBL_ENTRY_SIZE * init->expn_table_entries))) {
+ IPAERR_RL("Detected overflow\n");
return -EPERM;
}
/* Check Expn Table Entry offset is not
@@ -399,8 +399,8 @@
tmp = init->expn_rules_offset +
(TBL_ENTRY_SIZE * init->expn_table_entries);
if (tmp > ipa3_ctx->nat_mem.size) {
- IPAERR("Expn Table rules offset not valid\n");
- IPAERR("offset:%d entrys:%d size:%zu mem_size:%zu\n",
+ IPAERR_RL("Expn Table rules offset not valid\n");
+ IPAERR_RL("offset:%d entrys:%d size:%zu mem_size:%zu\n",
init->expn_rules_offset, init->expn_table_entries,
tmp, ipa3_ctx->nat_mem.size);
return -EPERM;
@@ -409,7 +409,7 @@
/* check for integer overflow */
if (init->index_offset >
UINT_MAX - (INDX_TBL_ENTRY_SIZE * (init->table_entries + 1))) {
- IPAERR("Detected overflow\n");
+ IPAERR_RL("Detected overflow\n");
return -EPERM;
}
/* Check Indx Table Entry offset is not
@@ -418,8 +418,8 @@
tmp = init->index_offset +
(INDX_TBL_ENTRY_SIZE * (init->table_entries + 1));
if (tmp > ipa3_ctx->nat_mem.size) {
- IPAERR("Indx Table rules offset not valid\n");
- IPAERR("offset:%d entrys:%d size:%zu mem_size:%zu\n",
+ IPAERR_RL("Indx Table rules offset not valid\n");
+ IPAERR_RL("offset:%d entrys:%d size:%zu mem_size:%zu\n",
init->index_offset, (init->table_entries + 1),
tmp, ipa3_ctx->nat_mem.size);
return -EPERM;
@@ -428,7 +428,7 @@
/* check for integer overflow */
if (init->index_expn_offset >
UINT_MAX - (INDX_TBL_ENTRY_SIZE * init->expn_table_entries)) {
- IPAERR("Detected overflow\n");
+ IPAERR_RL("Detected overflow\n");
return -EPERM;
}
/* Check Expn Table entry offset is not
@@ -437,8 +437,8 @@
tmp = init->index_expn_offset +
(INDX_TBL_ENTRY_SIZE * init->expn_table_entries);
if (tmp > ipa3_ctx->nat_mem.size) {
- IPAERR("Indx Expn Table rules offset not valid\n");
- IPAERR("offset:%d entrys:%d size:%zu mem_size:%zu\n",
+ IPAERR_RL("Indx Expn Table rules offset not valid\n");
+ IPAERR_RL("offset:%d entrys:%d size:%zu mem_size:%zu\n",
init->index_expn_offset, init->expn_table_entries,
tmp, ipa3_ctx->nat_mem.size);
return -EPERM;
@@ -476,16 +476,16 @@
(init->expn_rules_offset > offset) ||
(init->index_offset > offset) ||
(init->index_expn_offset > offset)) {
- IPAERR("Failed due to integer overflow\n");
- IPAERR("nat.mem.dma_handle: 0x%pa\n",
+ IPAERR_RL("Failed due to integer overflow\n");
+ IPAERR_RL("nat.mem.dma_handle: 0x%pa\n",
&ipa3_ctx->nat_mem.dma_handle);
- IPAERR("ipv4_rules_offset: 0x%x\n",
+ IPAERR_RL("ipv4_rules_offset: 0x%x\n",
init->ipv4_rules_offset);
- IPAERR("expn_rules_offset: 0x%x\n",
+ IPAERR_RL("expn_rules_offset: 0x%x\n",
init->expn_rules_offset);
- IPAERR("index_offset: 0x%x\n",
+ IPAERR_RL("index_offset: 0x%x\n",
init->index_offset);
- IPAERR("index_expn_offset: 0x%x\n",
+ IPAERR_RL("index_expn_offset: 0x%x\n",
init->index_expn_offset);
result = -EPERM;
goto destroy_imm_cmd;
@@ -544,7 +544,7 @@
cmd_pyld[num_cmd] = ipahal_construct_imm_cmd(
IPA_IMM_CMD_IP_V4_NAT_INIT, &cmd, false);
if (!cmd_pyld[num_cmd]) {
- IPAERR("Fail to construct ip_v4_nat_init imm cmd\n");
+ IPAERR_RL("Fail to construct ip_v4_nat_init imm cmd\n");
result = -EPERM;
goto destroy_imm_cmd;
}
@@ -747,7 +747,7 @@
IPADBG("\n");
if (dma->entries <= 0) {
- IPAERR("Invalid number of commands %d\n",
+ IPAERR_RL("Invalid number of commands %d\n",
dma->entries);
ret = -EPERM;
goto bail;
@@ -755,7 +755,7 @@
for (cnt = 0; cnt < dma->entries; cnt++) {
if (dma->dma[cnt].table_index >= 1) {
- IPAERR("Invalid table index %d\n",
+ IPAERR_RL("Invalid table index %d\n",
dma->dma[cnt].table_index);
ret = -EPERM;
goto bail;
@@ -766,7 +766,7 @@
if (dma->dma[cnt].offset >=
(ipa3_ctx->nat_mem.size_base_tables + 1) *
NAT_TABLE_ENTRY_SIZE_BYTE) {
- IPAERR("Invalid offset %d\n",
+ IPAERR_RL("Invalid offset %d\n",
dma->dma[cnt].offset);
ret = -EPERM;
goto bail;
@@ -778,7 +778,7 @@
if (dma->dma[cnt].offset >=
ipa3_ctx->nat_mem.size_expansion_tables *
NAT_TABLE_ENTRY_SIZE_BYTE) {
- IPAERR("Invalid offset %d\n",
+ IPAERR_RL("Invalid offset %d\n",
dma->dma[cnt].offset);
ret = -EPERM;
goto bail;
@@ -790,7 +790,7 @@
if (dma->dma[cnt].offset >=
(ipa3_ctx->nat_mem.size_base_tables + 1) *
NAT_INTEX_TABLE_ENTRY_SIZE_BYTE) {
- IPAERR("Invalid offset %d\n",
+ IPAERR_RL("Invalid offset %d\n",
dma->dma[cnt].offset);
ret = -EPERM;
goto bail;
@@ -802,7 +802,7 @@
if (dma->dma[cnt].offset >=
ipa3_ctx->nat_mem.size_expansion_tables *
NAT_INTEX_TABLE_ENTRY_SIZE_BYTE) {
- IPAERR("Invalid offset %d\n",
+ IPAERR_RL("Invalid offset %d\n",
dma->dma[cnt].offset);
ret = -EPERM;
goto bail;
@@ -811,7 +811,7 @@
break;
default:
- IPAERR("Invalid base_addr %d\n",
+ IPAERR_RL("Invalid base_addr %d\n",
dma->dma[cnt].base_addr);
ret = -EPERM;
goto bail;
@@ -853,7 +853,7 @@
cmd.data = dma->dma[cnt].data;
cmd_pyld = ipahal_construct_imm_cmd(cmd_name, &cmd, false);
if (!cmd_pyld) {
- IPAERR("Fail to construct nat_dma imm cmd\n");
+ IPAERR_RL("Fail to construct nat_dma imm cmd\n");
continue;
}
desc[1].type = IPA_IMM_CMD_DESC;
@@ -1016,7 +1016,7 @@
cmd_pyld = ipahal_construct_imm_cmd(
IPA_IMM_CMD_IP_V4_NAT_INIT, &cmd, false);
if (!cmd_pyld) {
- IPAERR("Fail to construct ip_v4_nat_init imm cmd\n");
+ IPAERR_RL("Fail to construct ip_v4_nat_init imm cmd\n");
result = -EPERM;
goto destroy_regwrt_imm_cmd;
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c
index 80c3996..61bccc6 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c
@@ -808,6 +808,11 @@
return -EINVAL;
}
+ if (req->source_pipe_index == -1) {
+ IPAWANERR("Source pipe index invalid\n");
+ return -EINVAL;
+ }
+
mutex_lock(&ipa3_qmi_lock);
if (ipa3_qmi_ctx != NULL) {
/* cache the qmi_filter_request */
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
index 234b945..ef0158e 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
@@ -694,7 +694,7 @@
struct ipa3_rt_tbl_set *set;
if (strnlen(name, IPA_RESOURCE_NAME_MAX) == IPA_RESOURCE_NAME_MAX) {
- IPAERR("Name too long: %s\n", name);
+ IPAERR_RL("Name too long: %s\n", name);
return NULL;
}
@@ -720,7 +720,7 @@
struct ipa3_rt_tbl *entry;
if (in->ip >= IPA_IP_MAX) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
return -EINVAL;
}
@@ -746,7 +746,7 @@
int max_tbl_indx;
if (name == NULL) {
- IPAERR("no tbl name\n");
+ IPAERR_RL("no tbl name\n");
goto error;
}
@@ -759,7 +759,7 @@
max(IPA_MEM_PART(v6_modem_rt_index_hi),
IPA_MEM_PART(v6_apps_rt_index_hi));
} else {
- IPAERR("bad ip family type\n");
+ IPAERR_RL("bad ip family type\n");
goto error;
}
@@ -801,7 +801,7 @@
!ipa3_ctx->ip4_rt_tbl_nhash_lcl :
!ipa3_ctx->ip6_rt_tbl_nhash_lcl;
set->tbl_cnt++;
- idr_init(&entry->rule_ids);
+ entry->rule_ids = &set->rule_ids;
list_add(&entry->link, &set->head_rt_tbl_list);
IPADBG("add rt tbl idx=%d tbl_cnt=%d ip=%d\n", entry->idx,
@@ -820,7 +820,7 @@
ipa_insert_failed:
set->tbl_cnt--;
list_del(&entry->link);
- idr_destroy(&entry->rule_ids);
+ idr_destroy(entry->rule_ids);
fail_rt_idx_alloc:
entry->cookie = 0;
kmem_cache_free(ipa3_ctx->rt_tbl_cache, entry);
@@ -835,12 +835,12 @@
struct ipa3_rt_tbl_set *rset;
if (entry == NULL || (entry->cookie != IPA_RT_TBL_COOKIE)) {
- IPAERR("bad parms\n");
+ IPAERR_RL("bad parms\n");
return -EINVAL;
}
id = entry->id;
if (ipa3_id_find(id) == NULL) {
- IPAERR("lookup failed\n");
+ IPAERR_RL("lookup failed\n");
return -EPERM;
}
@@ -855,7 +855,7 @@
rset = &ipa3_ctx->reap_rt_tbl_set[ip];
- idr_destroy(&entry->rule_ids);
+ entry->rule_ids = NULL;
if (entry->in_sys[IPA_RULE_HASHABLE] ||
entry->in_sys[IPA_RULE_NON_HASHABLE]) {
list_move(&entry->link, &rset->head_rt_tbl_list);
@@ -923,7 +923,7 @@
(*(entry))->tbl = tbl;
(*(entry))->hdr = hdr;
(*(entry))->proc_ctx = proc_ctx;
- id = ipa3_alloc_rule_id(&tbl->rule_ids);
+ id = ipa3_alloc_rule_id(tbl->rule_ids);
if (id < 0) {
IPAERR("failed to allocate rule id\n");
WARN_ON(1);
@@ -967,7 +967,7 @@
entry->hdr->ref_cnt--;
else if (entry->proc_ctx)
entry->proc_ctx->ref_cnt--;
- idr_remove(&tbl->rule_ids, entry->rule_id);
+ idr_remove(tbl->rule_ids, entry->rule_id);
list_del(&entry->link);
kmem_cache_free(ipa3_ctx->rt_rule_cache, entry);
return -EPERM;
@@ -987,7 +987,7 @@
tbl = __ipa_add_rt_tbl(ip, name);
if (tbl == NULL || (tbl->cookie != IPA_RT_TBL_COOKIE)) {
- IPAERR("failed adding rt tbl name = %s\n",
+ IPAERR_RL("failed adding rt tbl name = %s\n",
name ? name : "");
goto error;
}
@@ -997,8 +997,8 @@
*/
if (!strcmp(tbl->name, IPA_DFLT_RT_TBL_NAME) &&
(tbl->rule_cnt > 0) && (at_rear != 0)) {
- IPAERR("cannot add rule at end of tbl rule_cnt=%d at_rear=%d\n",
- tbl->rule_cnt, at_rear);
+ IPAERR_RL("cannot add rule at end of tbl rule_cnt=%d at_rear=%d"
+ , tbl->rule_cnt, at_rear);
goto error;
}
@@ -1068,7 +1068,7 @@
int ret;
if (rules == NULL || rules->num_rules == 0 || rules->ip >= IPA_IP_MAX) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
return -EINVAL;
}
@@ -1078,7 +1078,7 @@
&rules->rules[i].rule,
rules->rules[i].at_rear,
&rules->rules[i].rt_rule_hdl)) {
- IPAERR("failed to add rt rule %d\n", i);
+ IPAERR_RL("failed to add rt rule %d\n", i);
rules->rules[i].status = IPA_RT_STATUS_OF_ADD_FAILED;
} else {
rules->rules[i].status = 0;
@@ -1114,7 +1114,7 @@
struct ipa3_rt_entry *entry = NULL;
if (rules == NULL || rules->num_rules == 0 || rules->ip >= IPA_IP_MAX) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
return -EINVAL;
}
@@ -1122,28 +1122,28 @@
tbl = __ipa3_find_rt_tbl(rules->ip, rules->rt_tbl_name);
if (tbl == NULL || (tbl->cookie != IPA_RT_TBL_COOKIE)) {
- IPAERR("failed finding rt tbl name = %s\n",
+ IPAERR_RL("failed finding rt tbl name = %s\n",
rules->rt_tbl_name ? rules->rt_tbl_name : "");
ret = -EINVAL;
goto bail;
}
if (tbl->rule_cnt <= 0) {
- IPAERR("tbl->rule_cnt <= 0");
+ IPAERR_RL("tbl->rule_cnt <= 0");
ret = -EINVAL;
goto bail;
}
entry = ipa3_id_find(rules->add_after_hdl);
if (!entry) {
- IPAERR("failed finding rule %d in rt tbls\n",
+ IPAERR_RL("failed finding rule %d in rt tbls\n",
rules->add_after_hdl);
ret = -EINVAL;
goto bail;
}
if (entry->tbl != tbl) {
- IPAERR("given rt rule does not match the table\n");
+ IPAERR_RL("given rt rule does not match the table\n");
ret = -EINVAL;
goto bail;
}
@@ -1154,7 +1154,7 @@
*/
if (!strcmp(tbl->name, IPA_DFLT_RT_TBL_NAME) &&
(&entry->link == tbl->head_rt_rule_list.prev)) {
- IPAERR("cannot add rule at end of tbl rule_cnt=%d\n",
+ IPAERR_RL("cannot add rule at end of tbl rule_cnt=%d\n",
tbl->rule_cnt);
ret = -EINVAL;
goto bail;
@@ -1171,7 +1171,7 @@
&rules->rules[i].rule,
&rules->rules[i].rt_rule_hdl,
&entry)) {
- IPAERR("failed to add rt rule %d\n", i);
+ IPAERR_RL("failed to add rt rule %d\n", i);
rules->rules[i].status = IPA_RT_STATUS_OF_ADD_FAILED;
} else {
rules->rules[i].status = 0;
@@ -1180,7 +1180,7 @@
if (rules->commit)
if (ipa3_ctx->ctrl->ipa3_commit_rt(rules->ip)) {
- IPAERR("failed to commit\n");
+ IPAERR_RL("failed to commit\n");
ret = -EPERM;
goto bail;
}
@@ -1201,12 +1201,12 @@
entry = ipa3_id_find(rule_hdl);
if (entry == NULL) {
- IPAERR("lookup failed\n");
+ IPAERR_RL("lookup failed\n");
return -EINVAL;
}
if (entry->cookie != IPA_RT_RULE_COOKIE) {
- IPAERR("bad params\n");
+ IPAERR_RL("bad params\n");
return -EINVAL;
}
@@ -1219,10 +1219,10 @@
IPADBG("del rt rule tbl_idx=%d rule_cnt=%d rule_id=%d\n ref_cnt=%u",
entry->tbl->idx, entry->tbl->rule_cnt,
entry->rule_id, entry->tbl->ref_cnt);
- idr_remove(&entry->tbl->rule_ids, entry->rule_id);
+ idr_remove(entry->tbl->rule_ids, entry->rule_id);
if (entry->tbl->rule_cnt == 0 && entry->tbl->ref_cnt == 0) {
if (__ipa_del_rt_tbl(entry->tbl))
- IPAERR("fail to del RT tbl\n");
+ IPAERR_RL("fail to del RT tbl\n");
}
entry->cookie = 0;
id = entry->id;
@@ -1249,14 +1249,14 @@
int ret;
if (hdls == NULL || hdls->num_hdls == 0 || hdls->ip >= IPA_IP_MAX) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
return -EINVAL;
}
mutex_lock(&ipa3_ctx->lock);
for (i = 0; i < hdls->num_hdls; i++) {
if (__ipa3_del_rt_rule(hdls->hdl[i].hdl)) {
- IPAERR("failed to del rt rule %i\n", i);
+ IPAERR_RL("failed to del rt rule %i\n", i);
hdls->hdl[i].status = IPA_RT_STATUS_OF_DEL_FAILED;
} else {
hdls->hdl[i].status = 0;
@@ -1289,7 +1289,7 @@
int ret;
if (ip >= IPA_IP_MAX) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
return -EINVAL;
}
@@ -1333,7 +1333,7 @@
int id;
if (ip >= IPA_IP_MAX) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
return -EINVAL;
}
@@ -1349,7 +1349,7 @@
* filtering rules point to routing tables
*/
if (ipa3_reset_flt(ip))
- IPAERR("fail to reset flt ip=%d\n", ip);
+ IPAERR_RL("fail to reset flt ip=%d\n", ip);
set = &ipa3_ctx->rt_tbl_set[ip];
rset = &ipa3_ctx->reap_rt_tbl_set[ip];
@@ -1378,7 +1378,7 @@
else if (rule->proc_ctx)
__ipa3_release_hdr_proc_ctx(rule->proc_ctx->id);
rule->cookie = 0;
- idr_remove(&tbl->rule_ids, rule->rule_id);
+ idr_remove(tbl->rule_ids, rule->rule_id);
id = rule->id;
kmem_cache_free(ipa3_ctx->rt_rule_cache, rule);
@@ -1395,7 +1395,7 @@
/* do not remove the "default" routing tbl which has index 0 */
if (tbl->idx != apps_start_idx) {
- idr_destroy(&tbl->rule_ids);
+ tbl->rule_ids = NULL;
if (tbl->in_sys[IPA_RULE_HASHABLE] ||
tbl->in_sys[IPA_RULE_NON_HASHABLE]) {
list_move(&tbl->link, &rset->head_rt_tbl_list);
@@ -1438,21 +1438,27 @@
int result = -EFAULT;
if (lookup == NULL || lookup->ip >= IPA_IP_MAX) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
return -EINVAL;
}
mutex_lock(&ipa3_ctx->lock);
entry = __ipa3_find_rt_tbl(lookup->ip, lookup->name);
if (entry && entry->cookie == IPA_RT_TBL_COOKIE) {
+ if (entry->ref_cnt == U32_MAX) {
+ IPAERR("fail: ref count crossed limit\n");
+ goto ret;
+ }
entry->ref_cnt++;
lookup->hdl = entry->id;
/* commit for get */
if (ipa3_ctx->ctrl->ipa3_commit_rt(lookup->ip))
- IPAERR("fail to commit RT tbl\n");
+ IPAERR_RL("fail to commit RT tbl\n");
result = 0;
}
+
+ret:
mutex_unlock(&ipa3_ctx->lock);
return result;
@@ -1470,18 +1476,18 @@
{
struct ipa3_rt_tbl *entry;
enum ipa_ip_type ip = IPA_IP_MAX;
- int result;
+ int result = 0;
mutex_lock(&ipa3_ctx->lock);
entry = ipa3_id_find(rt_tbl_hdl);
if (entry == NULL) {
- IPAERR("lookup failed\n");
+ IPAERR_RL("lookup failed\n");
result = -EINVAL;
goto ret;
}
if ((entry->cookie != IPA_RT_TBL_COOKIE) || entry->ref_cnt == 0) {
- IPAERR("bad parms\n");
+ IPAERR_RL("bad parms\n");
result = -EINVAL;
goto ret;
}
@@ -1501,10 +1507,10 @@
IPADBG("zero ref_cnt, delete rt tbl (idx=%u)\n",
entry->idx);
if (__ipa_del_rt_tbl(entry))
- IPAERR("fail to del RT tbl\n");
+ IPAERR_RL("fail to del RT tbl\n");
/* commit for put */
if (ipa3_ctx->ctrl->ipa3_commit_rt(ip))
- IPAERR("fail to commit RT tbl\n");
+ IPAERR_RL("fail to commit RT tbl\n");
}
result = 0;
@@ -1525,26 +1531,26 @@
if (rtrule->rule.hdr_hdl) {
hdr = ipa3_id_find(rtrule->rule.hdr_hdl);
if ((hdr == NULL) || (hdr->cookie != IPA_HDR_COOKIE)) {
- IPAERR("rt rule does not point to valid hdr\n");
+ IPAERR_RL("rt rule does not point to valid hdr\n");
goto error;
}
} else if (rtrule->rule.hdr_proc_ctx_hdl) {
proc_ctx = ipa3_id_find(rtrule->rule.hdr_proc_ctx_hdl);
if ((proc_ctx == NULL) ||
(proc_ctx->cookie != IPA_PROC_HDR_COOKIE)) {
- IPAERR("rt rule does not point to valid proc ctx\n");
+ IPAERR_RL("rt rule does not point to valid proc ctx\n");
goto error;
}
}
entry = ipa3_id_find(rtrule->rt_rule_hdl);
if (entry == NULL) {
- IPAERR("lookup failed\n");
+ IPAERR_RL("lookup failed\n");
goto error;
}
if (entry->cookie != IPA_RT_RULE_COOKIE) {
- IPAERR("bad params\n");
+ IPAERR_RL("bad params\n");
goto error;
}
@@ -1585,14 +1591,14 @@
int result;
if (hdls == NULL || hdls->num_rules == 0 || hdls->ip >= IPA_IP_MAX) {
- IPAERR("bad parm\n");
+ IPAERR_RL("bad parm\n");
return -EINVAL;
}
mutex_lock(&ipa3_ctx->lock);
for (i = 0; i < hdls->num_rules; i++) {
if (__ipa_mdfy_rt_rule(&hdls->rules[i])) {
- IPAERR("failed to mdfy rt rule %i\n", i);
+ IPAERR_RL("failed to mdfy rt rule %i\n", i);
hdls->rules[i].status = IPA_RT_STATUS_OF_MDFY_FAILED;
} else {
hdls->rules[i].status = 0;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c
index 60dc04f..c97d2b3 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c
@@ -1668,7 +1668,7 @@
if (clnt_hdl >= ipa3_ctx->ipa_num_pipes ||
ipa3_ctx->ep[clnt_hdl].valid == 0) {
- IPAERR("bad parm, %d\n", clnt_hdl);
+ IPAERR_RL("bad parm, %d\n", clnt_hdl);
return -EINVAL;
}
@@ -1681,7 +1681,7 @@
ep = &ipa3_ctx->ep[clnt_hdl];
if (!(ep->uc_offload_state & IPA_WDI_CONNECTED)) {
- IPAERR("WDI channel bad state %d\n", ep->uc_offload_state);
+ IPAERR_RL("WDI channel bad state %d\n", ep->uc_offload_state);
return -EFAULT;
}
IPA_ACTIVE_CLIENTS_INC_EP(ipa3_get_client_mapping(clnt_hdl));
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index a251359..8fe15bc 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -21,6 +21,7 @@
#include "ipa_i.h"
#include "ipahal/ipahal.h"
#include "ipahal/ipahal_fltrt.h"
+#include "ipahal/ipahal_hw_stats.h"
#include "../ipa_rm_i.h"
#define IPA_V3_0_CLK_RATE_SVS (75 * 1000 * 1000UL)
@@ -1141,7 +1142,7 @@
[IPA_4_0][IPA_CLIENT_ODU_PROD] = {
true, IPA_v4_0_GROUP_UL_DL,
true,
- IPA_DPS_HPS_SEQ_TYPE_DMA_ONLY,
+ IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 1, 0, 8, 16, IPA_EE_AP } },
[IPA_4_0][IPA_CLIENT_ETHERNET_PROD] = {
@@ -1988,7 +1989,7 @@
*/
int ipa3_cfg_filter(u32 disable)
{
- IPAERR("Filter disable is not supported!\n");
+ IPAERR_RL("Filter disable is not supported!\n");
return -EPERM;
}
@@ -2123,7 +2124,7 @@
int ipa_ep_idx;
if (client >= IPA_CLIENT_MAX || client < 0) {
- IPAERR("Bad client number! client =%d\n", client);
+ IPAERR_RL("Bad client number! client =%d\n", client);
return IPA_EP_NOT_ALLOCATED;
}
@@ -3281,19 +3282,19 @@
int result = -EINVAL;
if (param_in->client >= IPA_CLIENT_MAX) {
- IPAERR("bad parm client:%d\n", param_in->client);
+ IPAERR_RL("bad parm client:%d\n", param_in->client);
goto fail;
}
ipa_ep_idx = ipa3_get_ep_mapping(param_in->client);
if (ipa_ep_idx == -1) {
- IPAERR("Invalid client.\n");
+ IPAERR_RL("Invalid client.\n");
goto fail;
}
ep = &ipa3_ctx->ep[ipa_ep_idx];
if (!ep->valid) {
- IPAERR("EP not allocated.\n");
+ IPAERR_RL("EP not allocated.\n");
goto fail;
}
@@ -3307,7 +3308,7 @@
ipa3_ctx->ep[ipa_ep_idx].cfg.meta = meta;
result = ipa3_write_qmapid_wdi_pipe(ipa_ep_idx, meta.qmap_id);
if (result)
- IPAERR("qmap_id %d write failed on ep=%d\n",
+ IPAERR_RL("qmap_id %d write failed on ep=%d\n",
meta.qmap_id, ipa_ep_idx);
result = 0;
}
@@ -4061,7 +4062,7 @@
IPAHAL_FULL_PIPELINE_CLEAR;
reg_write_agg_close.offset =
ipahal_get_reg_ofst(IPA_AGGR_FORCE_CLOSE);
- ipahal_get_aggr_force_close_valmask(1<<i, &valmask);
+ ipahal_get_aggr_force_close_valmask(i, &valmask);
reg_write_agg_close.value = valmask.val;
reg_write_agg_close.value_mask = valmask.mask;
cmd_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_REGISTER_WRITE,
@@ -4455,6 +4456,7 @@
api_ctrl->ipa_create_wdi_mapping = ipa3_create_wdi_mapping;
api_ctrl->ipa_get_gsi_ep_info = ipa3_get_gsi_ep_info;
api_ctrl->ipa_stop_gsi_channel = ipa3_stop_gsi_channel;
+ api_ctrl->ipa_start_gsi_channel = ipa3_start_gsi_channel;
api_ctrl->ipa_register_ipa_ready_cb = ipa3_register_ipa_ready_cb;
api_ctrl->ipa_inc_client_enable_clks = ipa3_inc_client_enable_clks;
api_ctrl->ipa_dec_client_disable_clks = ipa3_dec_client_disable_clks;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/Makefile b/drivers/platform/msm/ipa/ipa_v3/ipahal/Makefile
index b945eb06..67e491b 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/Makefile
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/Makefile
@@ -1,3 +1,3 @@
obj-$(CONFIG_IPA3) += ipa_hal.o
-ipa_hal-y := ipahal.o ipahal_reg.o ipahal_fltrt.o
+ipa_hal-y := ipahal.o ipahal_reg.o ipahal_fltrt.o ipahal_hw_stats.o
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c
index 57d44e3..56fed2a 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c
@@ -15,6 +15,8 @@
#include "ipahal_i.h"
#include "ipahal_reg_i.h"
#include "ipahal_fltrt_i.h"
+#include "ipahal_hw_stats_i.h"
+
struct ipahal_context *ipahal_ctx;
@@ -48,9 +50,6 @@
__stringify(IPAHAL_PKT_STATUS_EXCEPTION_IPV6CT),
};
-#define IPAHAL_MEM_ALLOC(__size, __is_atomic_ctx) \
- (kzalloc((__size), ((__is_atomic_ctx)?GFP_ATOMIC:GFP_KERNEL)))
-
static u16 ipahal_imm_cmd_get_opcode(enum ipahal_imm_cmd_name cmd);
@@ -1167,7 +1166,7 @@
u32 hdr_len, bool is_hdr_proc_ctx,
dma_addr_t phys_base, u32 hdr_base_addr,
struct ipa_hdr_offset_entry *offset_entry,
- union ipa_l2tp_hdr_proc_ctx_params l2tp_params){
+ struct ipa_l2tp_hdr_proc_ctx_params l2tp_params){
if (type == IPA_HDR_PROC_NONE) {
struct ipa_hw_hdr_proc_ctx_add_hdr_seq *ctx;
@@ -1230,6 +1229,17 @@
l2tp_params.hdr_remove_param.hdr_len_remove;
ctx->l2tp_params.l2tp_params.eth_hdr_retained =
l2tp_params.hdr_remove_param.eth_hdr_retained;
+ ctx->l2tp_params.l2tp_params.hdr_ofst_pkt_size_valid =
+ l2tp_params.hdr_remove_param.hdr_ofst_pkt_size_valid;
+ ctx->l2tp_params.l2tp_params.hdr_ofst_pkt_size =
+ l2tp_params.hdr_remove_param.hdr_ofst_pkt_size;
+ ctx->l2tp_params.l2tp_params.hdr_endianness =
+ l2tp_params.hdr_remove_param.hdr_endianness;
+ IPAHAL_DBG("hdr ofst valid: %d, hdr ofst pkt size: %d\n",
+ ctx->l2tp_params.l2tp_params.hdr_ofst_pkt_size_valid,
+ ctx->l2tp_params.l2tp_params.hdr_ofst_pkt_size);
+ IPAHAL_DBG("endianness: %d\n",
+ ctx->l2tp_params.l2tp_params.hdr_endianness);
IPAHAL_DBG("command id %d\n", ctx->l2tp_params.tlv.value);
ctx->end.type = IPA_PROC_CTX_TLV_TYPE_END;
@@ -1304,7 +1314,7 @@
bool is_hdr_proc_ctx, dma_addr_t phys_base,
u32 hdr_base_addr,
struct ipa_hdr_offset_entry *offset_entry,
- union ipa_l2tp_hdr_proc_ctx_params l2tp_params);
+ struct ipa_l2tp_hdr_proc_ctx_params l2tp_params);
int (*ipahal_get_proc_ctx_needed_len)(enum ipa_hdr_proc_type type);
};
@@ -1375,7 +1385,7 @@
void *const base, u32 offset, u32 hdr_len,
bool is_hdr_proc_ctx, dma_addr_t phys_base,
u32 hdr_base_addr, struct ipa_hdr_offset_entry *offset_entry,
- union ipa_l2tp_hdr_proc_ctx_params l2tp_params)
+ struct ipa_l2tp_hdr_proc_ctx_params l2tp_params)
{
IPAHAL_DBG(
"type %d, base %p, offset %d, hdr_len %d, is_hdr_proc_ctx %d, hdr_base_addr %d, offset_entry %p\n"
@@ -1504,6 +1514,12 @@
goto bail_free_ctx;
}
+ if (ipahal_hw_stats_init(ipa_hw_type)) {
+ IPAHAL_ERR("failed to init ipahal hw stats\n");
+ result = -EFAULT;
+ goto bail_free_ctx;
+ }
+
ipahal_debugfs_init();
return 0;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.h
index 0f322b5..56b884b 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.h
@@ -637,7 +637,7 @@
bool is_hdr_proc_ctx, dma_addr_t phys_base,
u32 hdr_base_addr,
struct ipa_hdr_offset_entry *offset_entry,
- union ipa_l2tp_hdr_proc_ctx_params l2tp_params);
+ struct ipa_l2tp_hdr_proc_ctx_params l2tp_params);
/*
* ipahal_get_proc_ctx_needed_len() - calculates the needed length for addition
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.c
index 2253b4b..acc72f0 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.c
@@ -829,6 +829,21 @@
ihl_ofst_meq32 += 2;
}
+ if (attrib->attrib_mask & IPA_FLT_TCP_SYN) {
+ if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
+ ihl_ofst_meq32)) {
+ IPAHAL_ERR("ran out of ihl_meq32 eq\n");
+ goto err;
+ }
+ *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
+ ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
+ /* 12 => offset of SYN after v4 header */
+ extra = ipa_write_8(12, extra);
+ rest = ipa_write_32(0x20000, rest);
+ rest = ipa_write_32(0x20000, rest);
+ ihl_ofst_meq32++;
+ }
+
if (attrib->attrib_mask & IPA_FLT_META_DATA) {
*en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(IPA_METADATA_COMPARE);
rest = ipa_write_32(attrib->meta_data_mask, rest);
@@ -1167,6 +1182,57 @@
ihl_ofst_meq32 += 2;
}
+ if (attrib->attrib_mask & IPA_FLT_TCP_SYN) {
+ if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
+ ihl_ofst_meq32)) {
+ IPAHAL_ERR("ran out of ihl_meq32 eq\n");
+ goto err;
+ }
+ *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
+ ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
+ /* 12 => offset of SYN after v4 header */
+ extra = ipa_write_8(12, extra);
+ rest = ipa_write_32(0x20000, rest);
+ rest = ipa_write_32(0x20000, rest);
+ ihl_ofst_meq32++;
+ }
+
+ if (attrib->attrib_mask & IPA_FLT_TCP_SYN_L2TP) {
+ if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
+ ihl_ofst_meq32) || IPA_IS_RAN_OUT_OF_EQ(
+ ipa3_0_ihl_ofst_meq32, ihl_ofst_meq32 + 1)) {
+ IPAHAL_ERR("ran out of ihl_meq32 eq\n");
+ goto err;
+ }
+ *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
+ ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
+ *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
+ ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32 + 1]);
+
+ /* populate TCP protocol eq */
+ if (attrib->ether_type == 0x0800) {
+ extra = ipa_write_8(30, extra);
+ rest = ipa_write_32(0xFF0000, rest);
+ rest = ipa_write_32(0x60000, rest);
+ } else {
+ extra = ipa_write_8(26, extra);
+ rest = ipa_write_32(0xFF00, rest);
+ rest = ipa_write_32(0x600, rest);
+ }
+
+ /* populate TCP SYN eq */
+ if (attrib->ether_type == 0x0800) {
+ extra = ipa_write_8(54, extra);
+ rest = ipa_write_32(0x20000, rest);
+ rest = ipa_write_32(0x20000, rest);
+ } else {
+ extra = ipa_write_8(74, extra);
+ rest = ipa_write_32(0x20000, rest);
+ rest = ipa_write_32(0x20000, rest);
+ }
+ ihl_ofst_meq32 += 2;
+ }
+
if (attrib->attrib_mask & IPA_FLT_META_DATA) {
*en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(IPA_METADATA_COMPARE);
rest = ipa_write_32(attrib->meta_data_mask, rest);
@@ -1241,6 +1307,27 @@
ihl_ofst_rng16++;
}
+ if (attrib->attrib_mask & IPA_FLT_TCP_SYN_L2TP) {
+ if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_rng16,
+ ihl_ofst_rng16)) {
+ IPAHAL_ERR("ran out of ihl_rng16 eq\n");
+ goto err;
+ }
+ *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
+ ipa3_0_ihl_ofst_rng16[ihl_ofst_rng16]);
+ /* 20 => offset of Ethertype after v4 header */
+ if (attrib->ether_type == 0x0800) {
+ extra = ipa_write_8(21, extra);
+ rest = ipa_write_16(0x0045, rest);
+ rest = ipa_write_16(0x0045, rest);
+ } else {
+ extra = ipa_write_8(20, extra);
+ rest = ipa_write_16(attrib->ether_type, rest);
+ rest = ipa_write_16(attrib->ether_type, rest);
+ }
+ ihl_ofst_rng16++;
+ }
+
if (attrib->attrib_mask & IPA_FLT_FLOW_LABEL) {
*en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(IPA_FL_EQ);
rest = ipa_write_32(attrib->u.v6.flow_label & 0xFFFFF,
@@ -1711,6 +1798,21 @@
ihl_ofst_meq32 += 2;
}
+ if (attrib->attrib_mask & IPA_FLT_TCP_SYN) {
+ if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
+ ihl_ofst_meq32)) {
+ IPAHAL_ERR("ran out of ihl_meq32 eq\n");
+ return -EPERM;
+ }
+ *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
+ ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
+ /* 12 => offset of SYN after v4 header */
+ eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].offset = 12;
+ eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].mask = 0x20000;
+ eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].value = 0x20000;
+ ihl_ofst_meq32++;
+ }
+
if (attrib->attrib_mask & IPA_FLT_TOS_MASKED) {
if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ofst_meq32, ofst_meq32)) {
IPAHAL_ERR("ran out of meq32 eq\n");
@@ -2108,6 +2210,65 @@
ihl_ofst_meq32 += 2;
}
+ if (attrib->attrib_mask & IPA_FLT_TCP_SYN) {
+ if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
+ ihl_ofst_meq32)) {
+ IPAHAL_ERR("ran out of ihl_meq32 eq\n");
+ return -EPERM;
+ }
+ *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
+ ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
+ /* 12 => offset of SYN after v4 header */
+ eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].offset = 12;
+ eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].mask = 0x20000;
+ eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].value = 0x20000;
+ ihl_ofst_meq32++;
+ }
+
+ if (attrib->attrib_mask & IPA_FLT_TCP_SYN_L2TP) {
+ if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
+ ihl_ofst_meq32) || IPA_IS_RAN_OUT_OF_EQ(
+ ipa3_0_ihl_ofst_meq32, ihl_ofst_meq32 + 1)) {
+ IPAHAL_ERR("ran out of ihl_meq32 eq\n");
+ return -EPERM;
+ }
+ *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
+ ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
+ *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
+ ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32 + 1]);
+
+ /* populate TCP protocol eq */
+ if (attrib->ether_type == 0x0800) {
+ eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].offset = 30;
+ eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].mask =
+ 0xFF0000;
+ eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].value =
+ 0x60000;
+ } else {
+ eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].offset = 26;
+ eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].mask =
+ 0xFF00;
+ eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].value =
+ 0x600;
+ }
+
+ /* populate TCP SYN eq */
+ if (attrib->ether_type == 0x0800) {
+ eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].offset = 54;
+ eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].mask =
+ 0x20000;
+ eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].value =
+ 0x20000;
+ } else {
+ eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].offset = 74;
+ eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].mask =
+ 0x20000;
+ eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].value =
+ 0x20000;
+ }
+ ihl_ofst_meq32 += 2;
+ }
+
if (attrib->attrib_mask & IPA_FLT_MAC_ETHER_TYPE) {
if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ofst_meq32, ofst_meq32)) {
IPAHAL_ERR("ran out of meq32 eq\n");
@@ -2250,6 +2411,32 @@
ihl_ofst_rng16++;
}
+ if (attrib->attrib_mask & IPA_FLT_TCP_SYN_L2TP) {
+ if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_rng16,
+ ihl_ofst_rng16)) {
+ IPAHAL_ERR("ran out of ihl_rng16 eq\n");
+ return -EPERM;
+ }
+ *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
+ ipa3_0_ihl_ofst_rng16[ihl_ofst_rng16]);
+ if (attrib->ether_type == 0x0800) {
+ eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].offset
+ = 21;
+ eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].range_low
+ = 0x0045;
+ eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].range_high
+ = 0x0045;
+ } else {
+ eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].offset =
+ 20;
+ eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].range_low
+ = attrib->ether_type;
+ eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].range_high
+ = attrib->ether_type;
+ }
+ ihl_ofst_rng16++;
+ }
+
if (attrib->attrib_mask & IPA_FLT_FLOW_LABEL) {
*en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(IPA_FL_EQ);
eq_atrb->fl_eq_present = 1;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_hw_stats.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_hw_stats.c
new file mode 100644
index 0000000..c711ff4
--- /dev/null
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_hw_stats.c
@@ -0,0 +1,557 @@
+/* Copyright (c) 2017, The Linux Foundation. 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 and
+ * only 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 "ipahal_hw_stats.h"
+#include "ipahal_hw_stats_i.h"
+#include "ipahal_i.h"
+
+struct ipahal_hw_stats_obj {
+ struct ipahal_stats_init_pyld *(*generate_init_pyld)(void *params,
+ bool is_atomic_ctx);
+ int (*get_offset)(void *params, struct ipahal_stats_offset *out);
+ int (*parse_stats)(void *init_params, void *raw_stats,
+ void *parsed_stats);
+};
+
+static int _count_ones(u32 number)
+{
+ int count = 0;
+
+ while (number) {
+ count++;
+ number = number & (number - 1);
+ }
+
+ return count;
+}
+
+static struct ipahal_stats_init_pyld *ipahal_generate_init_pyld_quota(
+ void *params, bool is_atomic_ctx)
+{
+ struct ipahal_stats_init_pyld *pyld;
+ struct ipahal_stats_init_quota *in =
+ (struct ipahal_stats_init_quota *)params;
+ int entries = _count_ones(in->enabled_bitmask);
+
+ IPAHAL_DBG_LOW("entries = %d\n", entries);
+ pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) +
+ entries * sizeof(struct ipahal_stats_quota_hw), is_atomic_ctx);
+ if (!pyld) {
+ IPAHAL_ERR("no mem\n");
+ return NULL;
+ }
+
+ pyld->len = entries * sizeof(struct ipahal_stats_quota_hw);
+ return pyld;
+}
+
+static int ipahal_get_offset_quota(void *params,
+ struct ipahal_stats_offset *out)
+{
+ struct ipahal_stats_get_offset_quota *in =
+ (struct ipahal_stats_get_offset_quota *)params;
+ int entries = _count_ones(in->init.enabled_bitmask);
+
+ IPAHAL_DBG_LOW("\n");
+ out->offset = 0;
+ out->size = entries * sizeof(struct ipahal_stats_quota_hw);
+
+ return 0;
+}
+
+static int ipahal_parse_stats_quota(void *init_params, void *raw_stats,
+ void *parsed_stats)
+{
+ struct ipahal_stats_init_quota *init =
+ (struct ipahal_stats_init_quota *)init_params;
+ struct ipahal_stats_quota_hw *raw_hw =
+ (struct ipahal_stats_quota_hw *)raw_stats;
+ struct ipahal_stats_quota_all *out =
+ (struct ipahal_stats_quota_all *)parsed_stats;
+ int stat_idx = 0;
+ int i;
+
+ memset(out, 0, sizeof(*out));
+ IPAHAL_DBG_LOW("\n");
+ for (i = 0; i < IPAHAL_MAX_PIPES; i++) {
+ if (init->enabled_bitmask & (1 << i)) {
+ IPAHAL_DBG_LOW("pipe %d stat_idx %d\n", i, stat_idx);
+ out->stats[i].num_ipv4_bytes =
+ raw_hw[stat_idx].num_ipv4_bytes;
+ out->stats[i].num_ipv4_pkts =
+ raw_hw[stat_idx].num_ipv4_pkts;
+ out->stats[i].num_ipv6_pkts =
+ raw_hw[stat_idx].num_ipv6_pkts;
+ out->stats[i].num_ipv6_bytes =
+ raw_hw[stat_idx].num_ipv6_bytes;
+ stat_idx++;
+ }
+ }
+
+ return 0;
+}
+
+static struct ipahal_stats_init_pyld *ipahal_generate_init_pyld_tethering(
+ void *params, bool is_atomic_ctx)
+{
+ struct ipahal_stats_init_pyld *pyld;
+ struct ipahal_stats_init_tethering *in =
+ (struct ipahal_stats_init_tethering *)params;
+ int hdr_entries = _count_ones(in->prod_bitmask);
+ int entries = 0;
+ int i;
+ void *pyld_ptr;
+ u32 incremental_offset;
+
+ IPAHAL_DBG_LOW("prod entries = %d\n", hdr_entries);
+ for (i = 0; i < sizeof(in->prod_bitmask) * 8; i++) {
+ if (in->prod_bitmask & (1 << i)) {
+ if (in->cons_bitmask[i] == 0) {
+ IPAHAL_ERR("no cons bitmask for prod %d\n", i);
+ return NULL;
+ }
+ entries += _count_ones(in->cons_bitmask[i]);
+ }
+ }
+ IPAHAL_DBG_LOW("sum all entries = %d\n", entries);
+
+ pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) +
+ hdr_entries * sizeof(struct ipahal_stats_tethering_hdr_hw) +
+ entries * sizeof(struct ipahal_stats_tethering_hw),
+ is_atomic_ctx);
+ if (!pyld) {
+ IPAHAL_ERR("no mem\n");
+ return NULL;
+ }
+
+ pyld->len = hdr_entries * sizeof(struct ipahal_stats_tethering_hdr_hw) +
+ entries * sizeof(struct ipahal_stats_tethering_hw);
+
+ pyld_ptr = pyld->data;
+ incremental_offset =
+ (hdr_entries * sizeof(struct ipahal_stats_tethering_hdr_hw))
+ / 8;
+ for (i = 0; i < sizeof(in->prod_bitmask) * 8; i++) {
+ if (in->prod_bitmask & (1 << i)) {
+ struct ipahal_stats_tethering_hdr_hw *hdr = pyld_ptr;
+
+ hdr->dst_mask = in->cons_bitmask[i];
+ hdr->offset = incremental_offset;
+ IPAHAL_DBG_LOW("hdr->dst_mask=0x%x\n", hdr->dst_mask);
+ IPAHAL_DBG_LOW("hdr->offset=0x%x\n", hdr->offset);
+ /* add the stats entry */
+ incremental_offset += _count_ones(in->cons_bitmask[i]) *
+ sizeof(struct ipahal_stats_tethering_hw) / 8;
+ pyld_ptr += sizeof(*hdr);
+ }
+ }
+
+ return pyld;
+}
+
+static int ipahal_get_offset_tethering(void *params,
+ struct ipahal_stats_offset *out)
+{
+ struct ipahal_stats_get_offset_tethering *in =
+ (struct ipahal_stats_get_offset_tethering *)params;
+ int entries = 0;
+ int i;
+
+ for (i = 0; i < sizeof(in->init.prod_bitmask) * 8; i++) {
+ if (in->init.prod_bitmask & (1 << i)) {
+ if (in->init.cons_bitmask[i] == 0) {
+ IPAHAL_ERR("no cons bitmask for prod %d\n", i);
+ return -EPERM;
+ }
+ entries += _count_ones(in->init.cons_bitmask[i]);
+ }
+ }
+ IPAHAL_DBG_LOW("sum all entries = %d\n", entries);
+
+ /* skip the header */
+ out->offset = _count_ones(in->init.prod_bitmask) *
+ sizeof(struct ipahal_stats_tethering_hdr_hw);
+ out->size = entries * sizeof(struct ipahal_stats_tethering_hw);
+
+ return 0;
+}
+
+static int ipahal_parse_stats_tethering(void *init_params, void *raw_stats,
+ void *parsed_stats)
+{
+ struct ipahal_stats_init_tethering *init =
+ (struct ipahal_stats_init_tethering *)init_params;
+ struct ipahal_stats_tethering_hw *raw_hw =
+ (struct ipahal_stats_tethering_hw *)raw_stats;
+ struct ipahal_stats_tethering_all *out =
+ (struct ipahal_stats_tethering_all *)parsed_stats;
+ int i, j;
+ int stat_idx = 0;
+
+ memset(out, 0, sizeof(*out));
+ IPAHAL_DBG_LOW("\n");
+ for (i = 0; i < IPAHAL_MAX_PIPES; i++) {
+ for (j = 0; j < IPAHAL_MAX_PIPES; j++) {
+ if ((init->prod_bitmask & (1 << i)) &&
+ init->cons_bitmask[i] & (1 << j)) {
+ IPAHAL_DBG_LOW("prod %d cons %d\n", i, j);
+ IPAHAL_DBG_LOW("stat_idx %d\n", stat_idx);
+ out->stats[i][j].num_ipv4_bytes =
+ raw_hw[stat_idx].num_ipv4_bytes;
+ IPAHAL_DBG_LOW("num_ipv4_bytes %lld\n",
+ out->stats[i][j].num_ipv4_bytes);
+ out->stats[i][j].num_ipv4_pkts =
+ raw_hw[stat_idx].num_ipv4_pkts;
+ IPAHAL_DBG_LOW("num_ipv4_pkts %lld\n",
+ out->stats[i][j].num_ipv4_pkts);
+ out->stats[i][j].num_ipv6_pkts =
+ raw_hw[stat_idx].num_ipv6_pkts;
+ IPAHAL_DBG_LOW("num_ipv6_pkts %lld\n",
+ out->stats[i][j].num_ipv6_pkts);
+ out->stats[i][j].num_ipv6_bytes =
+ raw_hw[stat_idx].num_ipv6_bytes;
+ IPAHAL_DBG_LOW("num_ipv6_bytes %lld\n",
+ out->stats[i][j].num_ipv6_bytes);
+ stat_idx++;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static struct ipahal_stats_init_pyld *ipahal_generate_init_pyld_flt_rt(
+ void *params, bool is_atomic_ctx)
+{
+ struct ipahal_stats_init_pyld *pyld;
+ struct ipahal_stats_init_flt_rt *in =
+ (struct ipahal_stats_init_flt_rt *)params;
+ int hdr_entries;
+ int num_rules = 0;
+ int i, start_entry;
+ void *pyld_ptr;
+ u32 incremental_offset;
+
+ for (i = 0; i < IPAHAL_MAX_RULE_ID_32; i++)
+ num_rules += _count_ones(in->rule_id_bitmask[i]);
+
+ if (num_rules == 0) {
+ IPAHAL_ERR("no rule ids provided\n");
+ return NULL;
+ }
+ IPAHAL_DBG_LOW("num_rules = %d\n", num_rules);
+
+ hdr_entries = IPAHAL_MAX_RULE_ID_32;
+ for (i = 0; i < IPAHAL_MAX_RULE_ID_32; i++) {
+ if (in->rule_id_bitmask[i] != 0)
+ break;
+ hdr_entries--;
+ }
+ start_entry = i;
+
+ for (i = IPAHAL_MAX_RULE_ID_32 - 1; i >= start_entry; i--) {
+ if (in->rule_id_bitmask[i] != 0)
+ break;
+ hdr_entries--;
+ }
+ IPAHAL_DBG_LOW("hdr_entries = %d\n", hdr_entries);
+
+ pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) +
+ hdr_entries * sizeof(struct ipahal_stats_flt_rt_hdr_hw) +
+ num_rules * sizeof(struct ipahal_stats_flt_rt_hw),
+ is_atomic_ctx);
+ if (!pyld) {
+ IPAHAL_ERR("no mem\n");
+ return NULL;
+ }
+
+ pyld->len = hdr_entries * sizeof(struct ipahal_stats_flt_rt_hdr_hw) +
+ num_rules * sizeof(struct ipahal_stats_flt_rt_hw);
+
+ pyld_ptr = pyld->data;
+ incremental_offset =
+ (hdr_entries * sizeof(struct ipahal_stats_flt_rt_hdr_hw))
+ / 8;
+ for (i = start_entry; i < hdr_entries; i++) {
+ struct ipahal_stats_flt_rt_hdr_hw *hdr = pyld_ptr;
+
+ hdr->en_mask = in->rule_id_bitmask[i];
+ hdr->cnt_offset = incremental_offset;
+ /* add the stats entry */
+ incremental_offset += _count_ones(in->rule_id_bitmask[i]) *
+ sizeof(struct ipahal_stats_flt_rt_hw) / 8;
+ pyld_ptr += sizeof(*hdr);
+ }
+
+ return pyld;
+}
+
+static int ipahal_get_offset_flt_rt(void *params,
+ struct ipahal_stats_offset *out)
+{
+ struct ipahal_stats_get_offset_flt_rt *in =
+ (struct ipahal_stats_get_offset_flt_rt *)params;
+ int i;
+ int hdr_entries;
+ int skip_rules = 0;
+ int start_entry;
+ int rule_bit = in->rule_id % 32;
+ int rule_idx = in->rule_id / 32;
+
+ if (rule_idx >= IPAHAL_MAX_RULE_ID_32) {
+ IPAHAL_ERR("invalid rule_id %d\n", in->rule_id);
+ return -EPERM;
+ }
+
+ hdr_entries = IPAHAL_MAX_RULE_ID_32;
+ for (i = 0; i < IPAHAL_MAX_RULE_ID_32; i++) {
+ if (in->init.rule_id_bitmask[i] != 0)
+ break;
+ hdr_entries--;
+ }
+
+ if (hdr_entries == 0) {
+ IPAHAL_ERR("no rule ids provided\n");
+ return -EPERM;
+ }
+ start_entry = i;
+
+ for (i = IPAHAL_MAX_RULE_ID_32 - 1; i >= 0; i--) {
+ if (in->init.rule_id_bitmask[i] != 0)
+ break;
+ hdr_entries--;
+ }
+ IPAHAL_DBG_LOW("hdr_entries = %d\n", hdr_entries);
+
+ /* skip the header */
+ out->offset = hdr_entries * sizeof(struct ipahal_stats_flt_rt_hdr_hw);
+
+ /* skip the previous rules */
+ for (i = start_entry; i < rule_idx; i++)
+ skip_rules += _count_ones(in->init.rule_id_bitmask[i]);
+
+ for (i = 0; i < rule_bit; i++)
+ if (in->init.rule_id_bitmask[rule_idx] & (1 << i))
+ skip_rules++;
+
+ out->offset += skip_rules * sizeof(struct ipahal_stats_flt_rt_hw);
+ out->size = sizeof(struct ipahal_stats_flt_rt_hw);
+
+ return 0;
+}
+
+static int ipahal_parse_stats_flt_rt(void *init_params, void *raw_stats,
+ void *parsed_stats)
+{
+ struct ipahal_stats_flt_rt_hw *raw_hw =
+ (struct ipahal_stats_flt_rt_hw *)raw_stats;
+ struct ipahal_stats_flt_rt *out =
+ (struct ipahal_stats_flt_rt *)parsed_stats;
+
+ memset(out, 0, sizeof(*out));
+ IPAHAL_DBG_LOW("\n");
+ out->num_packets = raw_hw->num_packets;
+ out->num_packets_hash = raw_hw->num_packets_hash;
+
+ return 0;
+}
+
+static struct ipahal_stats_init_pyld *ipahal_generate_init_pyld_drop(
+ void *params, bool is_atomic_ctx)
+{
+ struct ipahal_stats_init_pyld *pyld;
+ struct ipahal_stats_init_drop *in =
+ (struct ipahal_stats_init_drop *)params;
+ int entries = _count_ones(in->enabled_bitmask);
+
+ IPAHAL_DBG_LOW("entries = %d\n", entries);
+ pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) +
+ entries * sizeof(struct ipahal_stats_drop_hw), is_atomic_ctx);
+ if (!pyld) {
+ IPAHAL_ERR("no mem\n");
+ return NULL;
+ }
+
+ pyld->len = entries * sizeof(struct ipahal_stats_drop_hw);
+
+ return pyld;
+}
+
+static int ipahal_get_offset_drop(void *params,
+ struct ipahal_stats_offset *out)
+{
+ struct ipahal_stats_get_offset_drop *in =
+ (struct ipahal_stats_get_offset_drop *)params;
+ int entries = _count_ones(in->init.enabled_bitmask);
+
+ IPAHAL_DBG_LOW("\n");
+ out->offset = 0;
+ out->size = entries * sizeof(struct ipahal_stats_drop_hw);
+
+ return 0;
+}
+
+static int ipahal_parse_stats_drop(void *init_params, void *raw_stats,
+ void *parsed_stats)
+{
+ struct ipahal_stats_init_drop *init =
+ (struct ipahal_stats_init_drop *)init_params;
+ struct ipahal_stats_drop_hw *raw_hw =
+ (struct ipahal_stats_drop_hw *)raw_stats;
+ struct ipahal_stats_drop_all *out =
+ (struct ipahal_stats_drop_all *)parsed_stats;
+ int stat_idx = 0;
+ int i;
+
+ memset(out, 0, sizeof(*out));
+ IPAHAL_DBG_LOW("\n");
+ for (i = 0; i < IPAHAL_MAX_PIPES; i++) {
+ if (init->enabled_bitmask & (1 << i)) {
+ out->stats[i].drop_byte_cnt =
+ raw_hw[stat_idx].drop_byte_cnt;
+ out->stats[i].drop_packet_cnt =
+ raw_hw[stat_idx].drop_packet_cnt;
+ stat_idx++;
+ }
+ }
+
+ return 0;
+}
+
+static struct ipahal_hw_stats_obj
+ ipahal_hw_stats_objs[IPA_HW_MAX][IPAHAL_HW_STATS_MAX] = {
+ /* IPAv4 */
+ [IPA_HW_v4_0][IPAHAL_HW_STATS_QUOTA] = {
+ ipahal_generate_init_pyld_quota,
+ ipahal_get_offset_quota,
+ ipahal_parse_stats_quota
+ },
+ [IPA_HW_v4_0][IPAHAL_HW_STATS_TETHERING] = {
+ ipahal_generate_init_pyld_tethering,
+ ipahal_get_offset_tethering,
+ ipahal_parse_stats_tethering
+ },
+ [IPA_HW_v4_0][IPAHAL_HW_STATS_FNR] = {
+ ipahal_generate_init_pyld_flt_rt,
+ ipahal_get_offset_flt_rt,
+ ipahal_parse_stats_flt_rt
+ },
+ [IPA_HW_v4_0][IPAHAL_HW_STATS_DROP] = {
+ ipahal_generate_init_pyld_drop,
+ ipahal_get_offset_drop,
+ ipahal_parse_stats_drop
+ },
+};
+
+int ipahal_hw_stats_init(enum ipa_hw_type ipa_hw_type)
+{
+ int i;
+ int j;
+ struct ipahal_hw_stats_obj zero_obj;
+
+ IPAHAL_DBG_LOW("Entry - HW_TYPE=%d\n", ipa_hw_type);
+
+ if ((ipa_hw_type < 0) || (ipa_hw_type >= IPA_HW_MAX)) {
+ IPAHAL_ERR("invalid IPA HW type (%d)\n", ipa_hw_type);
+ return -EINVAL;
+ }
+
+ memset(&zero_obj, 0, sizeof(zero_obj));
+ for (i = IPA_HW_v4_0 ; i < ipa_hw_type ; i++) {
+ for (j = 0; j < IPAHAL_HW_STATS_MAX; j++) {
+ if (!memcmp(&ipahal_hw_stats_objs[i + 1][j], &zero_obj,
+ sizeof(struct ipahal_hw_stats_obj))) {
+ memcpy(&ipahal_hw_stats_objs[i + 1][j],
+ &ipahal_hw_stats_objs[i][j],
+ sizeof(struct ipahal_hw_stats_obj));
+ } else {
+ /*
+ * explicitly overridden stat.
+ * Check validity
+ */
+ if (!ipahal_hw_stats_objs[i + 1][j].
+ get_offset) {
+ IPAHAL_ERR(
+ "stat=%d get_offset null ver=%d\n",
+ j, i+1);
+ WARN_ON(1);
+ }
+ if (!ipahal_hw_stats_objs[i + 1][j].
+ parse_stats) {
+ IPAHAL_ERR(
+ "stat=%d parse_stats null ver=%d\n",
+ j, i + 1);
+ WARN_ON(1);
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+int ipahal_stats_get_offset(enum ipahal_hw_stats_type type, void *params,
+ struct ipahal_stats_offset *out)
+{
+ if (type < 0 || type >= IPAHAL_HW_STATS_MAX) {
+ IPAHAL_ERR("Invalid type stat=%d\n", type);
+ WARN_ON(1);
+ return -EFAULT;
+ }
+
+ if (!params || !out) {
+ IPAHAL_ERR("Null arg\n");
+ WARN_ON(1);
+ return -EFAULT;
+ }
+
+ return ipahal_hw_stats_objs[ipahal_ctx->hw_type][type].get_offset(
+ params, out);
+}
+
+struct ipahal_stats_init_pyld *ipahal_stats_generate_init_pyld(
+ enum ipahal_hw_stats_type type, void *params, bool is_atomic_ctx)
+{
+ if (type < 0 || type >= IPAHAL_HW_STATS_MAX) {
+ IPAHAL_ERR("Invalid type stat=%d\n", type);
+ WARN_ON(1);
+ return NULL;
+ }
+
+ if (!params) {
+ IPAHAL_ERR("Null arg\n");
+ WARN_ON(1);
+ return NULL;
+ }
+
+ return ipahal_hw_stats_objs[ipahal_ctx->hw_type][type].
+ generate_init_pyld(params, is_atomic_ctx);
+}
+
+int ipahal_parse_stats(enum ipahal_hw_stats_type type, void *init_params,
+ void *raw_stats, void *parsed_stats)
+{
+ if (type < 0 || type >= IPAHAL_HW_STATS_MAX) {
+ IPAHAL_ERR("Invalid type stat=%d\n", type);
+ WARN_ON(1);
+ return -EFAULT;
+ }
+
+ if (!raw_stats || !parsed_stats) {
+ IPAHAL_ERR("Null arg\n");
+ WARN_ON(1);
+ return -EFAULT;
+ }
+
+ return ipahal_hw_stats_objs[ipahal_ctx->hw_type][type].parse_stats(
+ init_params, raw_stats, parsed_stats);
+}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_hw_stats.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_hw_stats.h
new file mode 100644
index 0000000..cbb1dc3
--- /dev/null
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_hw_stats.h
@@ -0,0 +1,248 @@
+/* Copyright (c) 2017, The Linux Foundation. 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 and
+ * only 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 _IPAHAL_HW_STATS_H_
+#define _IPAHAL_HW_STATS_H_
+
+#include <linux/ipa.h>
+
+#define IPAHAL_MAX_PIPES 32
+#define IPAHAL_MAX_RULE_ID_32 (1024 / 32) /* 10 bits of rule id */
+
+enum ipahal_hw_stats_type {
+ IPAHAL_HW_STATS_QUOTA,
+ IPAHAL_HW_STATS_TETHERING,
+ IPAHAL_HW_STATS_FNR,
+ IPAHAL_HW_STATS_DROP,
+ IPAHAL_HW_STATS_MAX
+};
+
+/*
+ * struct ipahal_stats_init_pyld - Statistics initialization payload
+ * @len: length of payload
+ * @data: actual payload data
+ */
+struct ipahal_stats_init_pyld {
+ u16 len;
+ u16 reserved;
+ u8 data[0];
+};
+
+/*
+ * struct ipahal_stats_offset - Statistics offset parameters
+ * @offset: offset of the statistic from beginning of stats table
+ * @size: size of the statistics
+ */
+struct ipahal_stats_offset {
+ u32 offset;
+ u16 size;
+};
+
+/*
+ * struct ipahal_stats_init_quota - Initializations parameters for quota
+ * @enabled_bitmask: bit mask of pipes to be monitored
+ */
+struct ipahal_stats_init_quota {
+ u32 enabled_bitmask;
+};
+
+/*
+ * struct ipahal_stats_get_offset_quota - Get offset parameters for quota
+ * @init: initialization parameters used in initialization of stats
+ */
+struct ipahal_stats_get_offset_quota {
+ struct ipahal_stats_init_quota init;
+};
+
+/*
+ * struct ipahal_stats_quota - Quota statistics
+ * @num_ipv4_bytes: IPv4 bytes
+ * @num_ipv6_bytes: IPv6 bytes
+ * @num_ipv4_pkts: IPv4 packets
+ * @num_ipv6_pkts: IPv6 packets
+ */
+struct ipahal_stats_quota {
+ u64 num_ipv4_bytes;
+ u64 num_ipv6_bytes;
+ u64 num_ipv4_pkts;
+ u64 num_ipv6_pkts;
+};
+
+/*
+ * struct ipahal_stats_quota_all - Quota statistics for all pipes
+ * @stats: array of statistics per pipe
+ */
+struct ipahal_stats_quota_all {
+ struct ipahal_stats_quota stats[IPAHAL_MAX_PIPES];
+};
+
+/*
+ * struct ipahal_stats_init_tethering - Initializations parameters for tethering
+ * @prod_bitmask: bit mask of producer pipes to be monitored
+ * @cons_bitmask: bit mask of consumer pipes to be monitored per producer
+ */
+struct ipahal_stats_init_tethering {
+ u32 prod_bitmask;
+ u32 cons_bitmask[IPAHAL_MAX_PIPES];
+};
+
+/*
+ * struct ipahal_stats_get_offset_tethering - Get offset parameters for
+ * tethering
+ * @init: initialization parameters used in initialization of stats
+ */
+struct ipahal_stats_get_offset_tethering {
+ struct ipahal_stats_init_tethering init;
+};
+
+/*
+ * struct ipahal_stats_tethering - Tethering statistics
+ * @num_ipv4_bytes: IPv4 bytes
+ * @num_ipv6_bytes: IPv6 bytes
+ * @num_ipv4_pkts: IPv4 packets
+ * @num_ipv6_pkts: IPv6 packets
+ */
+struct ipahal_stats_tethering {
+ u64 num_ipv4_bytes;
+ u64 num_ipv6_bytes;
+ u64 num_ipv4_pkts;
+ u64 num_ipv6_pkts;
+};
+
+/*
+ * struct ipahal_stats_tethering_all - Tethering statistics for all pipes
+ * @stats: matrix of statistics per pair of pipes
+ */
+struct ipahal_stats_tethering_all {
+ struct ipahal_stats_tethering
+ stats[IPAHAL_MAX_PIPES][IPAHAL_MAX_PIPES];
+};
+
+/*
+ * struct ipahal_stats_init_flt_rt - Initializations parameters for flt_rt
+ * @rule_id_bitmask: array describes which rule ids to monitor.
+ * rule_id bit is determined by:
+ * index to the array => rule_id / 32
+ * bit to enable => rule_id % 32
+ */
+struct ipahal_stats_init_flt_rt {
+ u32 rule_id_bitmask[IPAHAL_MAX_RULE_ID_32];
+};
+
+/*
+ * struct ipahal_stats_get_offset_flt_rt - Get offset parameters for flt_rt
+ * @init: initialization parameters used in initialization of stats
+ * @rule_id: rule_id to get the offset for
+ */
+struct ipahal_stats_get_offset_flt_rt {
+ struct ipahal_stats_init_flt_rt init;
+ u32 rule_id;
+};
+
+/*
+ * struct ipahal_stats_flt_rt - flt_rt statistics
+ * @num_packets: Total number of packets hit this rule
+ * @num_packets_hash: Total number of packets hit this rule in hash table
+ */
+struct ipahal_stats_flt_rt {
+ u32 num_packets;
+ u32 num_packets_hash;
+};
+
+/*
+ * struct ipahal_stats_init_drop - Initializations parameters for Drop
+ * @enabled_bitmask: bit mask of pipes to be monitored
+ */
+struct ipahal_stats_init_drop {
+ u32 enabled_bitmask;
+};
+
+/*
+ * struct ipahal_stats_get_offset_drop - Get offset parameters for Drop
+ * @init: initialization parameters used in initialization of stats
+ */
+struct ipahal_stats_get_offset_drop {
+ struct ipahal_stats_init_drop init;
+};
+
+/*
+ * struct ipahal_stats_drop - Packet Drop statistics
+ * @drop_packet_cnt: number of packets dropped
+ * @drop_byte_cnt: number of bytes dropped
+ */
+struct ipahal_stats_drop {
+ u32 drop_packet_cnt;
+ u32 drop_byte_cnt;
+};
+
+/*
+ * struct ipahal_stats_drop_all - Drop statistics for all pipes
+ * @stats: array of statistics per pipes
+ */
+struct ipahal_stats_drop_all {
+ struct ipahal_stats_drop stats[IPAHAL_MAX_PIPES];
+};
+
+/*
+ * ipahal_stats_generate_init_pyld - Generate the init payload for stats
+ * @type: type of stats
+ * @params: init_pyld parameters based of stats type
+ * @is_atomic_ctx: is calling context atomic ?
+ *
+ * This function will generate the initialization payload for a particular
+ * statistic in hardware. IPA driver is expected to use this payload to
+ * initialize the SRAM.
+ *
+ * Return: pointer to ipahal_stats_init_pyld on success or NULL on failure.
+ */
+struct ipahal_stats_init_pyld *ipahal_stats_generate_init_pyld(
+ enum ipahal_hw_stats_type type, void *params, bool is_atomic_ctx);
+
+/*
+ * ipahal_destroy_stats_init_pyld() - Destroy/Release bulk that was built
+ * by the ipahal_stats_generate_init_pyld function.
+ */
+static inline void ipahal_destroy_stats_init_pyld(
+ struct ipahal_stats_init_pyld *pyld)
+{
+ kfree(pyld);
+}
+
+/*
+ * ipahal_stats_get_offset - Get the offset / size of payload for stats
+ * @type: type of stats
+ * @params: get_offset parameters based of stats type
+ * @out: out parameter for the offset and size.
+ *
+ * This function will return the offset of the counter from beginning of
+ * the table.IPA driver is expected to read this portion in SRAM and pass
+ * it to ipahal_parse_stats() to interprete the stats.
+ *
+ * Return: 0 on success and negative on failure
+ */
+int ipahal_stats_get_offset(enum ipahal_hw_stats_type type, void *params,
+ struct ipahal_stats_offset *out);
+
+/*
+ * ipahal_parse_stats - parse statistics
+ * @type: type of stats
+ * @init_params: init_pyld parameters used on init
+ * @raw_stats: stats read from IPA SRAM
+ * @parsed_stats: pointer to parsed stats based on type
+ *
+ * Return: 0 on success and negative on failure
+ */
+int ipahal_parse_stats(enum ipahal_hw_stats_type type, void *init_params,
+ void *raw_stats, void *parsed_stats);
+
+
+#endif /* _IPAHAL_HW_STATS_H_ */
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_hw_stats_i.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_hw_stats_i.h
new file mode 100644
index 0000000..3bb761d
--- /dev/null
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_hw_stats_i.h
@@ -0,0 +1,55 @@
+/* Copyright (c) 2017, The Linux Foundation. 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 and
+ * only 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 _IPAHAL_HW_STATS_I_H_
+#define _IPAHAL_HW_STATS_I_H_
+
+#include "ipahal_hw_stats.h"
+
+int ipahal_hw_stats_init(enum ipa_hw_type ipa_hw_type);
+
+struct ipahal_stats_quota_hw {
+ u64 num_ipv4_bytes;
+ u64 num_ipv4_pkts:32;
+ u64 num_ipv6_pkts:32;
+ u64 num_ipv6_bytes;
+};
+
+struct ipahal_stats_tethering_hdr_hw {
+ u64 dst_mask:32;
+ u64 offset:32;
+};
+
+struct ipahal_stats_tethering_hw {
+ u64 num_ipv4_bytes;
+ u64 num_ipv4_pkts:32;
+ u64 num_ipv6_pkts:32;
+ u64 num_ipv6_bytes;
+};
+
+struct ipahal_stats_flt_rt_hdr_hw {
+ u64 en_mask:32;
+ u64 reserved:16;
+ u64 cnt_offset:16;
+};
+
+struct ipahal_stats_flt_rt_hw {
+ u64 num_packets_hash:32;
+ u64 num_packets:32;
+};
+
+struct ipahal_stats_drop_hw {
+ u64 drop_byte_cnt:40;
+ u64 drop_packet_cnt:24;
+};
+
+#endif /* _IPAHAL_HW_STATS_I_H_ */
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_i.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_i.h
index 1c4b287..5eb1aef 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_i.h
@@ -46,6 +46,9 @@
IPAHAL_DRV_NAME " %s:%d " fmt, ## args); \
} while (0)
+#define IPAHAL_MEM_ALLOC(__size, __is_atomic_ctx) \
+ (kzalloc((__size), ((__is_atomic_ctx) ? GFP_ATOMIC : GFP_KERNEL)))
+
/*
* struct ipahal_context - HAL global context data
* @hw_type: IPA H/W type/version.
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c
index 0dccb5b..dc71414 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c
@@ -87,6 +87,24 @@
__stringify(IPA_DPS_SEQUENCER_FIRST),
__stringify(IPA_HPS_SEQUENCER_FIRST),
__stringify(IPA_CLKON_CFG),
+ __stringify(IPA_STAT_QUOTA_BASE_n),
+ __stringify(IPA_STAT_QUOTA_MASK_n),
+ __stringify(IPA_STAT_TETHERING_BASE_n),
+ __stringify(IPA_STAT_TETHERING_MASK_n),
+ __stringify(IPA_STAT_FILTER_IPV4_BASE),
+ __stringify(IPA_STAT_FILTER_IPV6_BASE),
+ __stringify(IPA_STAT_ROUTER_IPV4_BASE),
+ __stringify(IPA_STAT_ROUTER_IPV6_BASE),
+ __stringify(IPA_STAT_FILTER_IPV4_START_ID),
+ __stringify(IPA_STAT_FILTER_IPV6_START_ID),
+ __stringify(IPA_STAT_ROUTER_IPV4_START_ID),
+ __stringify(IPA_STAT_ROUTER_IPV6_START_ID),
+ __stringify(IPA_STAT_FILTER_IPV4_END_ID),
+ __stringify(IPA_STAT_FILTER_IPV6_END_ID),
+ __stringify(IPA_STAT_ROUTER_IPV4_END_ID),
+ __stringify(IPA_STAT_ROUTER_IPV6_END_ID),
+ __stringify(IPA_STAT_DROP_CNT_BASE_n),
+ __stringify(IPA_STAT_DROP_CNT_MASK_n),
};
static void ipareg_construct_dummy(enum ipahal_reg_name reg,
@@ -1510,6 +1528,60 @@
ipareg_construct_endp_init_conn_track_n,
ipareg_parse_dummy,
0x00000850, 0x70},
+ [IPA_HW_v4_0][IPA_STAT_QUOTA_BASE_n] = {
+ ipareg_construct_dummy, ipareg_parse_dummy,
+ 0x00000700, 0x4 },
+ [IPA_HW_v4_0][IPA_STAT_QUOTA_MASK_n] = {
+ ipareg_construct_dummy, ipareg_parse_dummy,
+ 0x00000708, 0x4 },
+ [IPA_HW_v4_0][IPA_STAT_TETHERING_BASE_n] = {
+ ipareg_construct_dummy, ipareg_parse_dummy,
+ 0x00000710, 0x4 },
+ [IPA_HW_v4_0][IPA_STAT_TETHERING_MASK_n] = {
+ ipareg_construct_dummy, ipareg_parse_dummy,
+ 0x00000718, 0x4 },
+ [IPA_HW_v4_0][IPA_STAT_FILTER_IPV4_BASE] = {
+ ipareg_construct_dummy, ipareg_parse_dummy,
+ 0x00000720, 0x0 },
+ [IPA_HW_v4_0][IPA_STAT_FILTER_IPV6_BASE] = {
+ ipareg_construct_dummy, ipareg_parse_dummy,
+ 0x00000724, 0x0 },
+ [IPA_HW_v4_0][IPA_STAT_ROUTER_IPV4_BASE] = {
+ ipareg_construct_dummy, ipareg_parse_dummy,
+ 0x00000728, 0x0 },
+ [IPA_HW_v4_0][IPA_STAT_ROUTER_IPV6_BASE] = {
+ ipareg_construct_dummy, ipareg_parse_dummy,
+ 0x0000072C, 0x0 },
+ [IPA_HW_v4_0][IPA_STAT_FILTER_IPV4_START_ID] = {
+ ipareg_construct_dummy, ipareg_parse_dummy,
+ 0x00000730, 0x0 },
+ [IPA_HW_v4_0][IPA_STAT_FILTER_IPV6_START_ID] = {
+ ipareg_construct_dummy, ipareg_parse_dummy,
+ 0x00000734, 0x0 },
+ [IPA_HW_v4_0][IPA_STAT_ROUTER_IPV4_START_ID] = {
+ ipareg_construct_dummy, ipareg_parse_dummy,
+ 0x00000738, 0x0 },
+ [IPA_HW_v4_0][IPA_STAT_ROUTER_IPV6_START_ID] = {
+ ipareg_construct_dummy, ipareg_parse_dummy,
+ 0x0000073C, 0x0 },
+ [IPA_HW_v4_0][IPA_STAT_FILTER_IPV4_END_ID] = {
+ ipareg_construct_dummy, ipareg_parse_dummy,
+ 0x00000740, 0x0 },
+ [IPA_HW_v4_0][IPA_STAT_FILTER_IPV6_END_ID] = {
+ ipareg_construct_dummy, ipareg_parse_dummy,
+ 0x00000744, 0x0 },
+ [IPA_HW_v4_0][IPA_STAT_ROUTER_IPV4_END_ID] = {
+ ipareg_construct_dummy, ipareg_parse_dummy,
+ 0x00000748, 0x0 },
+ [IPA_HW_v4_0][IPA_STAT_ROUTER_IPV6_END_ID] = {
+ ipareg_construct_dummy, ipareg_parse_dummy,
+ 0x0000074C, 0x0 },
+ [IPA_HW_v4_0][IPA_STAT_DROP_CNT_BASE_n] = {
+ ipareg_construct_dummy, ipareg_parse_dummy,
+ 0x00000750, 0x4 },
+ [IPA_HW_v4_0][IPA_STAT_DROP_CNT_MASK_n] = {
+ ipareg_construct_dummy, ipareg_parse_dummy,
+ 0x00000758, 0x4 },
};
/*
@@ -1853,6 +1925,11 @@
IPA_AGGR_FORCE_CLOSE_AGGR_FORCE_CLOSE_PIPE_BITMAP_BMSK_V4_0;
}
+ if (ep_idx > (sizeof(valmask->val) * 8 - 1)) {
+ IPAHAL_ERR("too big ep_idx %d\n", ep_idx);
+ ipa_assert();
+ return;
+ }
IPA_SETFIELD_IN_REG(valmask->val, 1 << ep_idx, shft, bmsk);
valmask->mask = bmsk << shft;
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h
index 3df49ce..a2864cd 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h
@@ -90,6 +90,24 @@
IPA_DPS_SEQUENCER_FIRST,
IPA_HPS_SEQUENCER_FIRST,
IPA_CLKON_CFG,
+ IPA_STAT_QUOTA_BASE_n,
+ IPA_STAT_QUOTA_MASK_n,
+ IPA_STAT_TETHERING_BASE_n,
+ IPA_STAT_TETHERING_MASK_n,
+ IPA_STAT_FILTER_IPV4_BASE,
+ IPA_STAT_FILTER_IPV6_BASE,
+ IPA_STAT_ROUTER_IPV4_BASE,
+ IPA_STAT_ROUTER_IPV6_BASE,
+ IPA_STAT_FILTER_IPV4_START_ID,
+ IPA_STAT_FILTER_IPV6_START_ID,
+ IPA_STAT_ROUTER_IPV4_START_ID,
+ IPA_STAT_ROUTER_IPV6_START_ID,
+ IPA_STAT_FILTER_IPV4_END_ID,
+ IPA_STAT_FILTER_IPV6_END_ID,
+ IPA_STAT_ROUTER_IPV4_END_ID,
+ IPA_STAT_ROUTER_IPV6_END_ID,
+ IPA_STAT_DROP_CNT_BASE_n,
+ IPA_STAT_DROP_CNT_MASK_n,
IPA_REG_MAX,
};
diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
index b19c71a..b119a69 100644
--- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
@@ -702,6 +702,11 @@
/* send ipa_fltr_installed_notif_req_msg_v01 to Q6*/
req->source_pipe_index =
ipa3_get_ep_mapping(IPA_CLIENT_APPS_WAN_PROD);
+ if (req->source_pipe_index == IPA_EP_NOT_ALLOCATED) {
+ IPAWANERR("ep mapping failed\n");
+ retval = -EFAULT;
+ }
+
req->install_status = QMI_RESULT_SUCCESS_V01;
req->rule_id_valid = 1;
req->rule_id_len = rmnet_ipa3_ctx->num_q6_rules;
@@ -1927,7 +1932,9 @@
if (ret < 0)
IPAWANERR("Error deleting resource %d, ret=%d\n",
IPA_RM_RESOURCE_Q6_PROD, ret);
- destroy_workqueue(rmnet_ipa3_ctx->rm_q6_wq);
+
+ if (rmnet_ipa3_ctx->rm_q6_wq)
+ destroy_workqueue(rmnet_ipa3_ctx->rm_q6_wq);
}
static void ipa3_wake_tx_queue(struct work_struct *work)
@@ -2267,7 +2274,10 @@
IPAWANERR("Error deleting resource %d, ret=%d\n",
IPA_RM_RESOURCE_WWAN_0_PROD, ret);
create_rsrc_err:
- ipa3_q6_deinitialize_rm();
+
+ if (!atomic_read(&rmnet_ipa3_ctx->is_ssr))
+ ipa3_q6_deinitialize_rm();
+
q6_init_err:
free_netdev(dev);
rmnet_ipa3_ctx->wwan_priv = NULL;
diff --git a/drivers/platform/msm/ipa/test/Makefile b/drivers/platform/msm/ipa/test/Makefile
index c20fd2b..af46bf2 100644
--- a/drivers/platform/msm/ipa/test/Makefile
+++ b/drivers/platform/msm/ipa/test/Makefile
@@ -1,2 +1,2 @@
obj-$(CONFIG_IPA_UT) += ipa_ut_mod.o
-ipa_ut_mod-y := ipa_ut_framework.o ipa_test_example.o ipa_test_mhi.o ipa_test_dma.o
+ipa_ut_mod-y := ipa_ut_framework.o ipa_test_example.o ipa_test_mhi.o ipa_test_dma.o ipa_test_hw_stats.o
diff --git a/drivers/platform/msm/ipa/test/ipa_test_hw_stats.c b/drivers/platform/msm/ipa/test/ipa_test_hw_stats.c
new file mode 100644
index 0000000..d37920e
--- /dev/null
+++ b/drivers/platform/msm/ipa/test/ipa_test_hw_stats.c
@@ -0,0 +1,330 @@
+/* Copyright (c) 2017, The Linux Foundation. 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 and
+ * only 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 "ipa_ut_framework.h"
+#include <linux/netdevice.h>
+
+struct ipa_test_hw_stats_ctx {
+ u32 odu_prod_hdl;
+ u32 odu_cons_hdl;
+ u32 rt4_usb;
+ u32 rt6_usb;
+ u32 rt4_odu_cons;
+ u32 rt6_odu_cons;
+ atomic_t odu_pending;
+};
+
+static struct ipa_test_hw_stats_ctx *ctx;
+
+static int ipa_test_hw_stats_suite_setup(void **ppriv)
+{
+ IPA_UT_DBG("Start Setup\n");
+
+ if (!ctx)
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+
+ return 0;
+}
+
+static int ipa_test_hw_stats_suite_teardown(void *priv)
+{
+ IPA_UT_DBG("Start Teardown\n");
+
+ return 0;
+}
+
+static void odu_prod_notify(void *priv, enum ipa_dp_evt_type evt,
+ unsigned long data)
+{
+ struct sk_buff *skb = (struct sk_buff *)data;
+
+ switch (evt) {
+ case IPA_RECEIVE:
+ dev_kfree_skb_any(skb);
+ break;
+ case IPA_WRITE_DONE:
+ atomic_dec(&ctx->odu_pending);
+ dev_kfree_skb_any(skb);
+ break;
+ default:
+ IPA_UT_ERR("unexpected evt %d\n", evt);
+ }
+}
+static void odu_cons_notify(void *priv, enum ipa_dp_evt_type evt,
+ unsigned long data)
+{
+ struct sk_buff *skb = (struct sk_buff *)data;
+ int ret;
+
+ switch (evt) {
+ case IPA_RECEIVE:
+ if (atomic_read(&ctx->odu_pending) >= 64)
+ msleep(20);
+ atomic_inc(&ctx->odu_pending);
+ skb_put(skb, 100);
+ ret = ipa_tx_dp(IPA_CLIENT_ODU_PROD, skb, NULL);
+ while (ret) {
+ msleep(100);
+ ret = ipa_tx_dp(IPA_CLIENT_ODU_PROD, skb, NULL);
+ }
+ break;
+ case IPA_WRITE_DONE:
+ dev_kfree_skb_any(skb);
+ break;
+ default:
+ IPA_UT_ERR("unexpected evt %d\n", evt);
+ }
+}
+
+static int ipa_test_hw_stats_configure(void *priv)
+{
+ struct ipa_sys_connect_params odu_prod_params;
+ struct ipa_sys_connect_params odu_emb_cons_params;
+ int res;
+
+ /* first connect all additional pipe */
+ memset(&odu_prod_params, 0, sizeof(odu_prod_params));
+ memset(&odu_emb_cons_params, 0, sizeof(odu_emb_cons_params));
+
+ odu_prod_params.client = IPA_CLIENT_ODU_PROD;
+ odu_prod_params.desc_fifo_sz = 0x1000;
+ odu_prod_params.priv = NULL;
+ odu_prod_params.notify = odu_prod_notify;
+ res = ipa_setup_sys_pipe(&odu_prod_params,
+ &ctx->odu_prod_hdl);
+ if (res) {
+ IPA_UT_ERR("fail to setup sys pipe ODU_PROD %d\n", res);
+ return res;
+ }
+
+ odu_emb_cons_params.client = IPA_CLIENT_ODU_EMB_CONS;
+ odu_emb_cons_params.desc_fifo_sz = 0x1000;
+ odu_emb_cons_params.priv = NULL;
+ odu_emb_cons_params.notify = odu_cons_notify;
+ res = ipa_setup_sys_pipe(&odu_emb_cons_params,
+ &ctx->odu_cons_hdl);
+ if (res) {
+ IPA_UT_ERR("fail to setup sys pipe ODU_EMB_CONS %d\n", res);
+ ipa_teardown_sys_pipe(ctx->odu_prod_hdl);
+ return res;
+ }
+
+ IPA_UT_INFO("Configured. Please connect USB RNDIS now\n");
+
+ return 0;
+}
+
+static int ipa_test_hw_stats_add_FnR(void *priv)
+{
+ struct ipa_ioc_add_rt_rule *rt_rule;
+ struct ipa_ioc_add_flt_rule *flt_rule;
+ struct ipa_ioc_get_rt_tbl rt_lookup;
+ int ret;
+
+ rt_rule = kzalloc(sizeof(*rt_rule) + 1 * sizeof(struct ipa_rt_rule_add),
+ GFP_KERNEL);
+ if (!rt_rule) {
+ IPA_UT_DBG("no mem\n");
+ return -ENOMEM;
+ }
+
+ flt_rule = kzalloc(sizeof(*flt_rule) +
+ 1 * sizeof(struct ipa_flt_rule_add), GFP_KERNEL);
+ if (!flt_rule) {
+ IPA_UT_DBG("no mem\n");
+ ret = -ENOMEM;
+ goto free_rt;
+ }
+
+ rt_rule->commit = 1;
+ rt_rule->ip = IPA_IP_v4;
+ rt_lookup.ip = rt_rule->ip;
+ strlcpy(rt_rule->rt_tbl_name, "V4_RT_TO_USB_CONS",
+ IPA_RESOURCE_NAME_MAX);
+ strlcpy(rt_lookup.name, rt_rule->rt_tbl_name, IPA_RESOURCE_NAME_MAX);
+ rt_rule->num_rules = 1;
+ rt_rule->rules[0].rule.dst = IPA_CLIENT_USB_CONS;
+ rt_rule->rules[0].rule.attrib.attrib_mask = IPA_FLT_DST_PORT;
+ rt_rule->rules[0].rule.attrib.dst_port = 5002;
+ rt_rule->rules[0].rule.hashable = true;
+ if (ipa_add_rt_rule(rt_rule) || rt_rule->rules[0].status) {
+ IPA_UT_ERR("failed to install V4 rules\n");
+ ret = -EFAULT;
+ goto free_flt;
+ }
+ if (ipa_get_rt_tbl(&rt_lookup)) {
+ IPA_UT_ERR("failed to query V4 rules\n");
+ ret = -EFAULT;
+ goto free_flt;
+ }
+ ctx->rt4_usb = rt_lookup.hdl;
+
+ memset(rt_rule, 0, sizeof(*rt_rule));
+ rt_rule->commit = 1;
+ rt_rule->ip = IPA_IP_v6;
+ rt_lookup.ip = rt_rule->ip;
+ strlcpy(rt_rule->rt_tbl_name, "V6_RT_TO_USB_CONS",
+ IPA_RESOURCE_NAME_MAX);
+ strlcpy(rt_lookup.name, rt_rule->rt_tbl_name, IPA_RESOURCE_NAME_MAX);
+ rt_rule->num_rules = 1;
+ rt_rule->rules[0].rule.dst = IPA_CLIENT_USB_CONS;
+ rt_rule->rules[0].rule.attrib.attrib_mask = IPA_FLT_DST_PORT;
+ rt_rule->rules[0].rule.attrib.dst_port = 5002;
+ rt_rule->rules[0].rule.hashable = true;
+ if (ipa_add_rt_rule(rt_rule) || rt_rule->rules[0].status) {
+ IPA_UT_ERR("failed to install V4 rules\n");
+ ret = -EFAULT;
+ goto free_flt;
+ }
+ if (ipa_get_rt_tbl(&rt_lookup)) {
+ IPA_UT_ERR("failed to query V4 rules\n");
+ ret = -EFAULT;
+ goto free_flt;
+ }
+ ctx->rt6_usb = rt_lookup.hdl;
+
+ memset(rt_rule, 0, sizeof(*rt_rule));
+ rt_rule->commit = 1;
+ rt_rule->ip = IPA_IP_v4;
+ rt_lookup.ip = rt_rule->ip;
+ strlcpy(rt_rule->rt_tbl_name, "V4_RT_TO_ODU_CONS",
+ IPA_RESOURCE_NAME_MAX);
+ strlcpy(rt_lookup.name, rt_rule->rt_tbl_name, IPA_RESOURCE_NAME_MAX);
+ rt_rule->num_rules = 1;
+ rt_rule->rules[0].rule.dst = IPA_CLIENT_ODU_EMB_CONS;
+ rt_rule->rules[0].rule.attrib.attrib_mask = IPA_FLT_DST_PORT;
+ rt_rule->rules[0].rule.attrib.dst_port = 5002;
+ rt_rule->rules[0].rule.hashable = true;
+ if (ipa_add_rt_rule(rt_rule) || rt_rule->rules[0].status) {
+ IPA_UT_ERR("failed to install V4 rules\n");
+ ret = -EFAULT;
+ goto free_flt;
+ }
+ if (ipa_get_rt_tbl(&rt_lookup)) {
+ IPA_UT_ERR("failed to query V4 rules\n");
+ return -EFAULT;
+ }
+ ctx->rt4_odu_cons = rt_lookup.hdl;
+
+ memset(rt_rule, 0, sizeof(*rt_rule));
+ rt_rule->commit = 1;
+ rt_rule->ip = IPA_IP_v6;
+ rt_lookup.ip = rt_rule->ip;
+ strlcpy(rt_rule->rt_tbl_name, "V6_RT_TO_ODU_CONS",
+ IPA_RESOURCE_NAME_MAX);
+ strlcpy(rt_lookup.name, rt_rule->rt_tbl_name, IPA_RESOURCE_NAME_MAX);
+ rt_rule->num_rules = 1;
+ rt_rule->rules[0].rule.dst = IPA_CLIENT_ODU_EMB_CONS;
+ rt_rule->rules[0].rule.attrib.attrib_mask = IPA_FLT_DST_PORT;
+ rt_rule->rules[0].rule.attrib.dst_port = 5002;
+ rt_rule->rules[0].rule.hashable = true;
+ if (ipa_add_rt_rule(rt_rule) || rt_rule->rules[0].status) {
+ IPA_UT_ERR("failed to install V4 rules\n");
+ ret = -EFAULT;
+ goto free_flt;
+ }
+ if (ipa_get_rt_tbl(&rt_lookup)) {
+ IPA_UT_ERR("failed to query V4 rules\n");
+ ret = -EFAULT;
+ goto free_flt;
+ }
+ ctx->rt6_odu_cons = rt_lookup.hdl;
+
+ flt_rule->commit = 1;
+ flt_rule->ip = IPA_IP_v4;
+ flt_rule->ep = IPA_CLIENT_USB_PROD;
+ flt_rule->num_rules = 1;
+ flt_rule->rules[0].at_rear = 1;
+ flt_rule->rules[0].rule.action = IPA_PASS_TO_ROUTING;
+ flt_rule->rules[0].rule.attrib.attrib_mask = IPA_FLT_DST_PORT;
+ flt_rule->rules[0].rule.attrib.dst_port = 5002;
+ flt_rule->rules[0].rule.rt_tbl_hdl = ctx->rt4_odu_cons;
+ flt_rule->rules[0].rule.hashable = 1;
+ if (ipa_add_flt_rule(flt_rule) || flt_rule->rules[0].status) {
+ IPA_UT_ERR("failed to install V4 rules\n");
+ ret = -EFAULT;
+ goto free_flt;
+ }
+
+ memset(flt_rule, 0, sizeof(*flt_rule));
+ flt_rule->commit = 1;
+ flt_rule->ip = IPA_IP_v6;
+ flt_rule->ep = IPA_CLIENT_USB_PROD;
+ flt_rule->num_rules = 1;
+ flt_rule->rules[0].at_rear = 1;
+ flt_rule->rules[0].rule.action = IPA_PASS_TO_ROUTING;
+ flt_rule->rules[0].rule.attrib.attrib_mask = IPA_FLT_DST_PORT;
+ flt_rule->rules[0].rule.attrib.dst_port = 5002;
+ flt_rule->rules[0].rule.rt_tbl_hdl = ctx->rt6_odu_cons;
+ flt_rule->rules[0].rule.hashable = 1;
+ if (ipa_add_flt_rule(flt_rule) || flt_rule->rules[0].status) {
+ IPA_UT_ERR("failed to install V6 rules\n");
+ ret = -EFAULT;
+ goto free_flt;
+ }
+
+ memset(flt_rule, 0, sizeof(*flt_rule));
+ flt_rule->commit = 1;
+ flt_rule->ip = IPA_IP_v4;
+ flt_rule->ep = IPA_CLIENT_ODU_PROD;
+ flt_rule->num_rules = 1;
+ flt_rule->rules[0].at_rear = 1;
+ flt_rule->rules[0].rule.action = IPA_PASS_TO_ROUTING;
+ flt_rule->rules[0].rule.attrib.attrib_mask = IPA_FLT_DST_PORT;
+ flt_rule->rules[0].rule.attrib.dst_port = 5002;
+ flt_rule->rules[0].rule.rt_tbl_hdl = ctx->rt4_usb;
+ flt_rule->rules[0].rule.hashable = 1;
+ if (ipa_add_flt_rule(flt_rule) || flt_rule->rules[0].status) {
+ IPA_UT_ERR("failed to install V4 rules\n");
+ ret = -EFAULT;
+ goto free_flt;
+ }
+
+ memset(flt_rule, 0, sizeof(*flt_rule));
+ flt_rule->commit = 1;
+ flt_rule->ip = IPA_IP_v6;
+ flt_rule->ep = IPA_CLIENT_ODU_PROD;
+ flt_rule->num_rules = 1;
+ flt_rule->rules[0].at_rear = 1;
+ flt_rule->rules[0].rule.action = IPA_PASS_TO_ROUTING;
+ flt_rule->rules[0].rule.attrib.attrib_mask = IPA_FLT_DST_PORT;
+ flt_rule->rules[0].rule.attrib.dst_port = 5002;
+ flt_rule->rules[0].rule.rt_tbl_hdl = ctx->rt6_usb;
+ flt_rule->rules[0].rule.hashable = 1;
+ if (ipa_add_flt_rule(flt_rule) || flt_rule->rules[0].status) {
+ IPA_UT_ERR("failed to install V6 rules\n");
+ ret = -EFAULT;
+ goto free_flt;
+ }
+
+ IPA_UT_INFO(
+ "Rules added. Please start data transfer on ports 5001/5002\n");
+ ret = 0;
+free_flt:
+ kfree(flt_rule);
+free_rt:
+ kfree(rt_rule);
+ return ret;
+
+}
+
+/* Suite definition block */
+IPA_UT_DEFINE_SUITE_START(hw_stats, "HW stats test",
+ ipa_test_hw_stats_suite_setup, ipa_test_hw_stats_suite_teardown)
+{
+ IPA_UT_ADD_TEST(configure, "Configure the setup",
+ ipa_test_hw_stats_configure, false, IPA_HW_v4_0, IPA_HW_MAX),
+
+ IPA_UT_ADD_TEST(add_rules, "Add FLT and RT rules",
+ ipa_test_hw_stats_add_FnR, false, IPA_HW_v4_0, IPA_HW_MAX),
+
+} IPA_UT_DEFINE_SUITE_END(hw_stats);
diff --git a/drivers/platform/msm/ipa/test/ipa_ut_suite_list.h b/drivers/platform/msm/ipa/test/ipa_ut_suite_list.h
index 4a9d3b0..823edcf 100644
--- a/drivers/platform/msm/ipa/test/ipa_ut_suite_list.h
+++ b/drivers/platform/msm/ipa/test/ipa_ut_suite_list.h
@@ -23,6 +23,7 @@
IPA_UT_DECLARE_SUITE(mhi);
IPA_UT_DECLARE_SUITE(dma);
IPA_UT_DECLARE_SUITE(example);
+IPA_UT_DECLARE_SUITE(hw_stats);
/**
@@ -34,6 +35,7 @@
IPA_UT_REGISTER_SUITE(mhi),
IPA_UT_REGISTER_SUITE(dma),
IPA_UT_REGISTER_SUITE(example),
+ IPA_UT_REGISTER_SUITE(hw_stats),
} IPA_UT_DEFINE_ALL_SUITES_END;
#endif /* _IPA_UT_SUITE_LIST_H_ */
diff --git a/drivers/platform/msm/msm_ext_display.c b/drivers/platform/msm/msm_ext_display.c
new file mode 100644
index 0000000..3be414b
--- /dev/null
+++ b/drivers/platform/msm/msm_ext_display.c
@@ -0,0 +1,525 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/iopoll.h>
+#include <linux/types.h>
+#include <linux/of_platform.h>
+#include <linux/msm_ext_display.h>
+
+struct msm_ext_disp_list {
+ struct msm_ext_disp_init_data *data;
+ struct list_head list;
+};
+
+struct msm_ext_disp {
+ struct msm_ext_disp_data ext_disp_data;
+ struct platform_device *pdev;
+ enum msm_ext_disp_type current_disp;
+ struct msm_ext_disp_audio_codec_ops *ops;
+ struct extcon_dev audio_sdev;
+ bool audio_session_on;
+ struct list_head display_list;
+ struct mutex lock;
+};
+
+static const unsigned int msm_ext_disp_supported_cable[] = {
+ EXTCON_DISP_DP,
+ EXTCON_DISP_HDMI,
+ EXTCON_NONE,
+};
+
+static int msm_ext_disp_extcon_register(struct msm_ext_disp *ext_disp)
+{
+ int ret = 0;
+
+ if (!ext_disp) {
+ pr_err("invalid params\n");
+ return -EINVAL;
+ }
+
+ memset(&ext_disp->audio_sdev, 0x0, sizeof(ext_disp->audio_sdev));
+ ext_disp->audio_sdev.supported_cable = msm_ext_disp_supported_cable;
+ ext_disp->audio_sdev.dev.parent = &ext_disp->pdev->dev;
+ ret = extcon_dev_register(&ext_disp->audio_sdev);
+ if (ret) {
+ pr_err("audio registration failed");
+ return ret;
+ }
+
+ pr_debug("extcon registration done\n");
+
+ return ret;
+}
+
+static void msm_ext_disp_extcon_unregister(struct msm_ext_disp *ext_disp)
+{
+ if (!ext_disp) {
+ pr_err("Invalid params\n");
+ return;
+ }
+
+ extcon_dev_unregister(&ext_disp->audio_sdev);
+}
+
+static const char *msm_ext_disp_name(enum msm_ext_disp_type type)
+{
+ switch (type) {
+ case EXT_DISPLAY_TYPE_HDMI: return "EXT_DISPLAY_TYPE_HDMI";
+ case EXT_DISPLAY_TYPE_DP: return "EXT_DISPLAY_TYPE_DP";
+ default: return "???";
+ }
+}
+
+static int msm_ext_disp_add_intf_data(struct msm_ext_disp *ext_disp,
+ struct msm_ext_disp_init_data *data)
+{
+ struct msm_ext_disp_list *node;
+
+ if (!ext_disp && !data) {
+ pr_err("Invalid params\n");
+ return -EINVAL;
+ }
+
+ node = kzalloc(sizeof(*node), GFP_KERNEL);
+ if (!node)
+ return -ENOMEM;
+
+ node->data = data;
+ list_add(&node->list, &ext_disp->display_list);
+
+ pr_debug("Added new display (%s)\n", msm_ext_disp_name(data->type));
+
+ return 0;
+}
+
+static int msm_ext_disp_get_intf_data(struct msm_ext_disp *ext_disp,
+ enum msm_ext_disp_type type,
+ struct msm_ext_disp_init_data **data)
+{
+ int ret = 0;
+ struct msm_ext_disp_list *node;
+ struct list_head *position = NULL;
+
+ if (!ext_disp || !data || type < EXT_DISPLAY_TYPE_HDMI ||
+ type >= EXT_DISPLAY_TYPE_MAX) {
+ pr_err("Invalid params\n");
+ ret = -EINVAL;
+ goto end;
+ }
+
+ *data = NULL;
+ list_for_each(position, &ext_disp->display_list) {
+ node = list_entry(position, struct msm_ext_disp_list, list);
+ if (node->data->type == type) {
+ *data = node->data;
+ break;
+ }
+ }
+
+ if (!*data) {
+ pr_err("Display not found (%s)\n", msm_ext_disp_name(type));
+ ret = -ENODEV;
+ }
+end:
+ return ret;
+}
+
+static int msm_ext_disp_process_audio(struct msm_ext_disp *ext_disp,
+ enum msm_ext_disp_type type,
+ enum msm_ext_disp_cable_state new_state)
+{
+ int ret = 0;
+ int state;
+
+ state = ext_disp->audio_sdev.state;
+ ret = extcon_set_state_sync(&ext_disp->audio_sdev,
+ ext_disp->current_disp, !!new_state);
+
+ pr_debug("Audio state %s %d\n",
+ ext_disp->audio_sdev.state == state ?
+ "is same" : "switched to",
+ ext_disp->audio_sdev.state);
+
+ return ret;
+}
+
+static struct msm_ext_disp *msm_ext_disp_validate_and_get(
+ struct platform_device *pdev,
+ enum msm_ext_disp_type type,
+ enum msm_ext_disp_cable_state state)
+{
+ struct msm_ext_disp_data *ext_disp_data;
+ struct msm_ext_disp *ext_disp;
+
+ if (!pdev) {
+ pr_err("invalid platform device\n");
+ goto err;
+ }
+
+ ext_disp_data = platform_get_drvdata(pdev);
+ if (!ext_disp_data) {
+ pr_err("invalid drvdata\n");
+ goto err;
+ }
+
+ ext_disp = container_of(ext_disp_data,
+ struct msm_ext_disp, ext_disp_data);
+
+ if (state < EXT_DISPLAY_CABLE_DISCONNECT ||
+ state >= EXT_DISPLAY_CABLE_STATE_MAX) {
+ pr_err("invalid HPD state (%d)\n", state);
+ goto err;
+ }
+
+ if (state == EXT_DISPLAY_CABLE_CONNECT) {
+ if (ext_disp->current_disp != EXT_DISPLAY_TYPE_MAX &&
+ ext_disp->current_disp != type) {
+ pr_err("invalid interface call\n");
+ goto err;
+ }
+ } else {
+ if (ext_disp->current_disp == EXT_DISPLAY_TYPE_MAX ||
+ ext_disp->current_disp != type) {
+ pr_err("invalid interface call\n");
+ goto err;
+ }
+ }
+ return ext_disp;
+err:
+ return ERR_PTR(-EINVAL);
+}
+
+static int msm_ext_disp_update_audio_ops(struct msm_ext_disp *ext_disp,
+ enum msm_ext_disp_type type,
+ enum msm_ext_disp_cable_state state)
+{
+ int ret = 0;
+ struct msm_ext_disp_init_data *data = NULL;
+
+ ret = msm_ext_disp_get_intf_data(ext_disp, type, &data);
+ if (ret || !data) {
+ pr_err("interface %s not found\n", msm_ext_disp_name(type));
+ goto end;
+ }
+
+ if (state == EXT_DISPLAY_CABLE_CONNECT) {
+ /* connect codec with interface */
+ *ext_disp->ops = data->codec_ops;
+
+ /* update pdev for interface to use */
+ ext_disp->ext_disp_data.intf_pdev = data->pdev;
+ ext_disp->ext_disp_data.intf_data = data->intf_data;
+
+ ext_disp->current_disp = type;
+
+ pr_debug("codec ops set for %s\n", msm_ext_disp_name(type));
+ } else if (state == EXT_DISPLAY_CABLE_DISCONNECT) {
+ *ext_disp->ops = (struct msm_ext_disp_audio_codec_ops){NULL};
+ ext_disp->current_disp = EXT_DISPLAY_TYPE_MAX;
+
+ pr_debug("codec ops cleared for %s\n", msm_ext_disp_name(type));
+ }
+end:
+ return ret;
+}
+
+static int msm_ext_disp_audio_config(struct platform_device *pdev,
+ enum msm_ext_disp_type type,
+ enum msm_ext_disp_cable_state state)
+{
+ int ret = 0;
+ struct msm_ext_disp *ext_disp;
+
+ ext_disp = msm_ext_disp_validate_and_get(pdev, type, state);
+ if (IS_ERR(ext_disp)) {
+ ret = PTR_ERR(ext_disp);
+ goto end;
+ }
+
+ mutex_lock(&ext_disp->lock);
+ ret = msm_ext_disp_update_audio_ops(ext_disp, type, state);
+ mutex_unlock(&ext_disp->lock);
+end:
+ return ret;
+}
+
+static int msm_ext_disp_audio_notify(struct platform_device *pdev,
+ enum msm_ext_disp_type type,
+ enum msm_ext_disp_cable_state state)
+{
+ int ret = 0;
+ struct msm_ext_disp *ext_disp;
+
+ ext_disp = msm_ext_disp_validate_and_get(pdev, type, state);
+ if (IS_ERR(ext_disp)) {
+ ret = PTR_ERR(ext_disp);
+ goto end;
+ }
+
+ mutex_lock(&ext_disp->lock);
+ ret = msm_ext_disp_process_audio(ext_disp, type, state);
+ mutex_unlock(&ext_disp->lock);
+end:
+ return ret;
+}
+
+int msm_hdmi_register_audio_codec(struct platform_device *pdev,
+ struct msm_ext_disp_audio_codec_ops *ops)
+{
+ return msm_ext_disp_register_audio_codec(pdev, ops);
+}
+
+int msm_ext_disp_register_audio_codec(struct platform_device *pdev,
+ struct msm_ext_disp_audio_codec_ops *ops)
+{
+ int ret = 0;
+ struct msm_ext_disp *ext_disp = NULL;
+ struct msm_ext_disp_data *ext_disp_data = NULL;
+
+ if (!pdev || !ops) {
+ pr_err("Invalid params\n");
+ return -EINVAL;
+ }
+
+ ext_disp_data = platform_get_drvdata(pdev);
+ if (!ext_disp_data) {
+ pr_err("Invalid drvdata\n");
+ return -EINVAL;
+ }
+
+ ext_disp = container_of(ext_disp_data, struct msm_ext_disp,
+ ext_disp_data);
+
+ mutex_lock(&ext_disp->lock);
+
+ if ((ext_disp->current_disp != EXT_DISPLAY_TYPE_MAX)
+ && ext_disp->ops) {
+ pr_err("Codec already registered\n");
+ ret = -EINVAL;
+ goto end;
+ }
+
+ ext_disp->ops = ops;
+
+ pr_debug("audio codec registered\n");
+
+end:
+ mutex_unlock(&ext_disp->lock);
+
+ return ret;
+}
+
+static int msm_ext_disp_validate_intf(struct msm_ext_disp_init_data *init_data)
+{
+ if (!init_data) {
+ pr_err("Invalid init_data\n");
+ return -EINVAL;
+ }
+
+ if (!init_data->pdev) {
+ pr_err("Invalid display intf pdev\n");
+ return -EINVAL;
+ }
+
+ if (!init_data->codec_ops.get_audio_edid_blk ||
+ !init_data->codec_ops.cable_status ||
+ !init_data->codec_ops.audio_info_setup) {
+ pr_err("Invalid codec operation pointers\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int msm_ext_disp_register_intf(struct platform_device *pdev,
+ struct msm_ext_disp_init_data *init_data)
+{
+ int ret = 0;
+ struct msm_ext_disp_init_data *data = NULL;
+ struct msm_ext_disp *ext_disp = NULL;
+ struct msm_ext_disp_data *ext_disp_data = NULL;
+
+ if (!pdev || !init_data) {
+ pr_err("Invalid params\n");
+ return -EINVAL;
+ }
+
+ ext_disp_data = platform_get_drvdata(pdev);
+ if (!ext_disp_data) {
+ pr_err("Invalid drvdata\n");
+ return -EINVAL;
+ }
+
+ ext_disp = container_of(ext_disp_data, struct msm_ext_disp,
+ ext_disp_data);
+
+ mutex_lock(&ext_disp->lock);
+
+ ret = msm_ext_disp_validate_intf(init_data);
+ if (ret)
+ goto end;
+
+ ret = msm_ext_disp_get_intf_data(ext_disp, init_data->type, &data);
+ if (!ret) {
+ pr_err("%s already registered\n",
+ msm_ext_disp_name(init_data->type));
+ goto end;
+ }
+
+ ret = msm_ext_disp_add_intf_data(ext_disp, init_data);
+ if (ret)
+ goto end;
+
+ init_data->intf_ops.audio_config = msm_ext_disp_audio_config;
+ init_data->intf_ops.audio_notify = msm_ext_disp_audio_notify;
+
+ pr_debug("%s registered\n", msm_ext_disp_name(init_data->type));
+
+ mutex_unlock(&ext_disp->lock);
+
+ return ret;
+
+end:
+ mutex_unlock(&ext_disp->lock);
+
+ return ret;
+}
+
+static int msm_ext_disp_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct device_node *of_node = NULL;
+ struct msm_ext_disp *ext_disp = NULL;
+
+ if (!pdev) {
+ pr_err("No platform device found\n");
+ ret = -ENODEV;
+ goto end;
+ }
+
+ of_node = pdev->dev.of_node;
+ if (!of_node) {
+ pr_err("No device node found\n");
+ ret = -ENODEV;
+ goto end;
+ }
+
+ ext_disp = devm_kzalloc(&pdev->dev, sizeof(*ext_disp), GFP_KERNEL);
+ if (!ext_disp) {
+ ret = -ENOMEM;
+ goto end;
+ }
+
+ platform_set_drvdata(pdev, &ext_disp->ext_disp_data);
+ ext_disp->pdev = pdev;
+
+ ret = msm_ext_disp_extcon_register(ext_disp);
+ if (ret)
+ goto extcon_dev_failure;
+
+ ret = of_platform_populate(of_node, NULL, NULL, &pdev->dev);
+ if (ret) {
+ pr_err("Failed to add child devices. Error = %d\n", ret);
+ goto child_node_failure;
+ } else {
+ pr_debug("%s: Added child devices.\n", __func__);
+ }
+
+ mutex_init(&ext_disp->lock);
+
+ INIT_LIST_HEAD(&ext_disp->display_list);
+ ext_disp->current_disp = EXT_DISPLAY_TYPE_MAX;
+
+ return ret;
+
+child_node_failure:
+ msm_ext_disp_extcon_unregister(ext_disp);
+extcon_dev_failure:
+ devm_kfree(&ext_disp->pdev->dev, ext_disp);
+end:
+ return ret;
+}
+
+static int msm_ext_disp_remove(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct msm_ext_disp *ext_disp = NULL;
+ struct msm_ext_disp_data *ext_disp_data = NULL;
+
+ if (!pdev) {
+ pr_err("No platform device\n");
+ ret = -ENODEV;
+ goto end;
+ }
+
+ ext_disp_data = platform_get_drvdata(pdev);
+ if (!ext_disp_data) {
+ pr_err("No drvdata found\n");
+ ret = -ENODEV;
+ goto end;
+ }
+
+ ext_disp = container_of(ext_disp_data, struct msm_ext_disp,
+ ext_disp_data);
+
+ msm_ext_disp_extcon_unregister(ext_disp);
+
+ mutex_destroy(&ext_disp->lock);
+ devm_kfree(&ext_disp->pdev->dev, ext_disp);
+
+end:
+ return ret;
+}
+
+static const struct of_device_id msm_ext_dt_match[] = {
+ {.compatible = "qcom,msm-ext-disp",},
+ { /* Sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, msm_ext_dt_match);
+
+static struct platform_driver this_driver = {
+ .probe = msm_ext_disp_probe,
+ .remove = msm_ext_disp_remove,
+ .driver = {
+ .name = "msm-ext-disp",
+ .of_match_table = msm_ext_dt_match,
+ },
+};
+
+static int __init msm_ext_disp_init(void)
+{
+ int ret = 0;
+
+ ret = platform_driver_register(&this_driver);
+ if (ret)
+ pr_err("failed, ret = %d\n", ret);
+
+ return ret;
+}
+
+static void __exit msm_ext_disp_exit(void)
+{
+ platform_driver_unregister(&this_driver);
+}
+
+subsys_initcall(msm_ext_disp_init);
+module_exit(msm_ext_disp_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MSM External Display");
diff --git a/drivers/platform/msm/qcom-geni-se.c b/drivers/platform/msm/qcom-geni-se.c
index 7c77280..2818d56 100644
--- a/drivers/platform/msm/qcom-geni-se.c
+++ b/drivers/platform/msm/qcom-geni-se.c
@@ -293,20 +293,31 @@
static int geni_se_select_gsi_mode(void __iomem *base)
{
- unsigned int io_mode = 0;
unsigned int geni_dma_mode = 0;
unsigned int gsi_event_en = 0;
+ unsigned int common_geni_m_irq_en = 0;
+ unsigned int common_geni_s_irq_en = 0;
+ common_geni_m_irq_en = geni_read_reg(base, SE_GENI_M_IRQ_EN);
+ common_geni_s_irq_en = geni_read_reg(base, SE_GENI_S_IRQ_EN);
+ common_geni_m_irq_en &=
+ ~(M_CMD_DONE_EN | M_TX_FIFO_WATERMARK_EN |
+ M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN);
+ common_geni_s_irq_en &= ~S_CMD_DONE_EN;
geni_dma_mode = geni_read_reg(base, SE_GENI_DMA_MODE_EN);
gsi_event_en = geni_read_reg(base, SE_GSI_EVENT_EN);
- io_mode = geni_read_reg(base, SE_IRQ_EN);
geni_dma_mode |= GENI_DMA_MODE_EN;
- io_mode &= ~(DMA_TX_IRQ_EN | DMA_RX_IRQ_EN);
gsi_event_en |= (DMA_RX_EVENT_EN | DMA_TX_EVENT_EN |
GENI_M_EVENT_EN | GENI_S_EVENT_EN);
- geni_write_reg(io_mode, base, SE_IRQ_EN);
+ geni_write_reg(0, base, SE_IRQ_EN);
+ geni_write_reg(common_geni_s_irq_en, base, SE_GENI_S_IRQ_EN);
+ geni_write_reg(common_geni_m_irq_en, base, SE_GENI_M_IRQ_EN);
+ geni_write_reg(0xFFFFFFFF, base, SE_GENI_M_IRQ_CLEAR);
+ geni_write_reg(0xFFFFFFFF, base, SE_GENI_S_IRQ_CLEAR);
+ geni_write_reg(0xFFFFFFFF, base, SE_DMA_TX_IRQ_CLR);
+ geni_write_reg(0xFFFFFFFF, base, SE_DMA_RX_IRQ_CLR);
geni_write_reg(geni_dma_mode, base, SE_GENI_DMA_MODE_EN);
geni_write_reg(gsi_event_en, base, SE_GSI_EVENT_EN);
return 0;
@@ -691,7 +702,7 @@
struct se_geni_rsc *rsc)
{
unsigned long flags;
- struct se_geni_rsc *tmp;
+ struct se_geni_rsc *tmp = NULL;
struct list_head *ins_list_head;
bool bus_bw_update = false;
int ret = 0;
@@ -709,7 +720,7 @@
list_add(&rsc->ib_list, ins_list_head);
/* Currently inserted node has greater average BW value */
if (ins_list_head == &geni_se_dev->ib_list_head)
- geni_se_dev->cur_ib = tmp->ib;
+ geni_se_dev->cur_ib = rsc->ib;
bus_bw_update = geni_se_check_bus_bw(geni_se_dev);
spin_unlock_irqrestore(&geni_se_dev->ab_ib_lock, flags);
diff --git a/drivers/platform/msm/seemp_core/seemp_logk.c b/drivers/platform/msm/seemp_core/seemp_logk.c
index e55260d..a23f069 100644
--- a/drivers/platform/msm/seemp_core/seemp_logk.c
+++ b/drivers/platform/msm/seemp_core/seemp_logk.c
@@ -30,6 +30,7 @@
#define YEAR_BASE 1900
#define EL2_SCM_ID 0x02001902
+#define KP_EL2_REPORT_REVISION 0x01000101
static struct seemp_logk_dev *slogk_dev;
@@ -610,6 +611,9 @@
/ sizeof(struct el2_report_data_t);
header = (struct el2_report_header_t *) el2_shared_mem;
+ if (header->report_version < KP_EL2_REPORT_REVISION)
+ return -EINVAL;
+
while (!kthread_should_stop()) {
for (i = 1; i < num_entries + 1; i++) {
struct el2_report_data_t *report;
@@ -624,16 +628,18 @@
/* determine legitimacy of report */
if (report->report_valid &&
- report->sequence_number <=
- header->num_incidents &&
(last_sequence_number == 0
|| report->sequence_number >
last_sequence_number)) {
seemp_logk_rtic(report->report_type,
- report->report.incident.actor,
- report->report.incident.asset_id,
- report->report.incident.asset_category,
- report->report.incident.response);
+ ((struct task_struct *) report->actor)
+ ->pid,
+ /* leave this empty until
+ * asset id is provided
+ */
+ "",
+ report->asset_category,
+ report->response);
last_sequence_number = report->sequence_number;
} else {
last_pos = cur_pos - 1;
diff --git a/drivers/platform/msm/seemp_core/seemp_logk.h b/drivers/platform/msm/seemp_core/seemp_logk.h
index 871de0e..eecf4f7 100644
--- a/drivers/platform/msm/seemp_core/seemp_logk.h
+++ b/drivers/platform/msm/seemp_core/seemp_logk.h
@@ -164,39 +164,23 @@
__u64 report_version; /* Version of the EL2 report */
__u64 mp_catalog_version;
/* Version of MP catalogue used for kernel protection */
+ __u64 num_incidents; /* Number of Incidents Observed by EL2 */
__u8 protection_enabled; /* Kernel Assets protected by EL2 */
__u8 pad1;
__u8 pad2;
__u8 pad3;
__u32 pad4;
- __u64 num_incidents; /* Number of Incidents Observed by EL2 */
-};
-
-/* individual report contents */
-union el2_report {
- struct {
- __u8 asset_id[0x20]; /* Asset Identifier */
- __u64 actor;
- /* Actor that caused the Incident. */
- __u8 asset_category; /* Asset Category */
- __u8 response; /* Response From EL2 */
- __u16 pad1;
- __u32 pad2;
- } incident;
- struct {
- __u64 reserved; /* TBD */
- } info;
};
/* individual report */
struct el2_report_data_t {
+ __u64 sequence_number; /* Sequence number of the report */
+ __u64 actor; /* Actor that caused the Incident. */
__u8 report_valid;
/* Flag to indicate whether report instance is valid */
__u8 report_type; /* Report Type */
- __u8 pad1;
- __u8 pad2;
- __u64 sequence_number; /* Sequence number of the report */
- union el2_report report; /* Report Contents */
+ __u8 asset_category; /* Asset Category */
+ __u8 response; /* Response From EL2 */
};
#endif
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index 62e0978..92321ad 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -3095,84 +3095,6 @@
return 0;
}
-static ssize_t
-usb_bam_show_inactivity_timer(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- char *buff = buf;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(bam_enable_strings); i++) {
- buff += snprintf(buff, PAGE_SIZE, "%s: %dms\n",
- bam_enable_strings[i],
- msm_usb_bam[i].inactivity_timer_ms);
- }
-
- return buff - buf;
-}
-
-static ssize_t usb_bam_store_inactivity_timer(struct device *dev,
- struct device_attribute *attr,
- const char *buff, size_t count)
-{
- char buf[USB_BAM_MAX_STR_LEN];
- char *trimmed_buf, *bam_str, *bam_name, *timer;
- int timer_d;
- int bam, ret;
-
- if (strnstr(buff, "help", USB_BAM_MAX_STR_LEN)) {
- pr_info("Usage: <bam_name> <ms>,<bam_name> <ms>,...\n");
- pr_info("\tbam_name: [%s, %s, %s]\n",
- bam_enable_strings[DWC3_CTRL],
- bam_enable_strings[CI_CTRL],
- bam_enable_strings[HSIC_CTRL]);
- pr_info("\tms: time in ms. Use 0 to disable timer\n");
- return count;
- }
-
- strlcpy(buf, buff, sizeof(buf));
- trimmed_buf = strim(buf);
-
- while (trimmed_buf) {
- bam_str = strsep(&trimmed_buf, ",");
- if (bam_str) {
- bam_name = strsep(&bam_str, " ");
- bam = get_bam_type_from_core_name(bam_name);
- if (bam < 0 || bam >= MAX_BAMS) {
- log_event_err("%s: Invalid bam, type=%d ,name=%s\n",
- __func__, bam, bam_name);
- return -EINVAL;
- }
-
- timer = strsep(&bam_str, " ");
-
- if (!timer)
- continue;
-
- ret = kstrtoint(timer, 0, &timer_d);
- if (ret) {
- log_event_err("%s: err:%d with value:(%d)\n",
- __func__, ret, timer_d);
- return ret;
- }
-
- /* Apply new timer setting if bam has running pipes */
- if (msm_usb_bam[bam].inactivity_timer_ms != timer_d) {
- msm_usb_bam[bam].inactivity_timer_ms = timer_d;
- if (msm_usb_bam[bam].pipes_enabled_per_bam > 0
- && !info[bam].in_lpm)
- usb_bam_set_inactivity_timer(bam);
- }
- }
- }
-
- return count;
-}
-
-static DEVICE_ATTR(inactivity_timer, 0600,
- usb_bam_show_inactivity_timer,
- usb_bam_store_inactivity_timer);
-
static int usb_bam_panic_notifier(struct notifier_block *this,
unsigned long event, void *ptr)
{
@@ -3221,12 +3143,6 @@
dev_dbg(&pdev->dev, "usb_bam_probe\n");
- ret = device_create_file(&pdev->dev, &dev_attr_inactivity_timer);
- if (ret) {
- dev_err(&pdev->dev, "failed to create fs node\n");
- return ret;
- }
-
io_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!io_res) {
dev_err(&pdev->dev, "missing BAM memory resource\n");
diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c
index 08e1505..5cbb130 100644
--- a/drivers/power/supply/power_supply_sysfs.c
+++ b/drivers/power/supply/power_supply_sysfs.c
@@ -311,6 +311,8 @@
POWER_SUPPLY_ATTR(hw_current_max),
POWER_SUPPLY_ATTR(real_type),
POWER_SUPPLY_ATTR(pr_swap),
+ POWER_SUPPLY_ATTR(cc_step),
+ POWER_SUPPLY_ATTR(cc_step_sel),
/* Local extensions of type int64_t */
POWER_SUPPLY_ATTR(charge_counter_ext),
/* Properties of type `const char *' */
diff --git a/drivers/power/supply/qcom/Makefile b/drivers/power/supply/qcom/Makefile
index bc19b24..6cc83ab 100644
--- a/drivers/power/supply/qcom/Makefile
+++ b/drivers/power/supply/qcom/Makefile
@@ -2,6 +2,6 @@
obj-$(CONFIG_SMB135X_CHARGER) += smb135x-charger.o pmic-voter.o
obj-$(CONFIG_SMB1355_SLAVE_CHARGER) += smb1355-charger.o pmic-voter.o
obj-$(CONFIG_SMB1351_USB_CHARGER) += smb1351-charger.o pmic-voter.o battery.o
-obj-$(CONFIG_QPNP_SMB2) += qpnp-smb2.o smb-lib.o pmic-voter.o storm-watch.o battery.o
+obj-$(CONFIG_QPNP_SMB2) += step-chg-jeita.o battery.o qpnp-smb2.o smb-lib.o pmic-voter.o storm-watch.o
obj-$(CONFIG_SMB138X_CHARGER) += smb138x-charger.o smb-lib.o pmic-voter.o storm-watch.o battery.o
obj-$(CONFIG_QPNP_QNOVO) += qpnp-qnovo.o battery.o
diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c
index 486e8c3..7f6d346 100644
--- a/drivers/power/supply/qcom/battery.c
+++ b/drivers/power/supply/qcom/battery.c
@@ -1082,6 +1082,8 @@
goto unreg_notifier;
}
+ chip->taper_pct = 100;
+
the_chip = chip;
return 0;
diff --git a/drivers/power/supply/qcom/fg-core.h b/drivers/power/supply/qcom/fg-core.h
index cdd09dd..1595b01 100644
--- a/drivers/power/supply/qcom/fg-core.h
+++ b/drivers/power/supply/qcom/fg-core.h
@@ -49,7 +49,7 @@
#define SRAM_READ "fg_sram_read"
#define SRAM_WRITE "fg_sram_write"
#define PROFILE_LOAD "fg_profile_load"
-#define DELTA_SOC "fg_delta_soc"
+#define TTF_PRIMING "fg_ttf_priming"
/* Delta BSOC irq votable reasons */
#define DELTA_BSOC_IRQ_VOTER "fg_delta_bsoc_irq"
@@ -67,6 +67,7 @@
#define MAX_LINE_LENGTH (ADDR_LEN + (ITEMS_PER_LINE * \
CHARS_PER_ITEM) + 1) \
+#define NUM_PARTITIONS 3
#define FG_SRAM_ADDRESS_MAX 255
#define FG_SRAM_LEN 504
#define PROFILE_LEN 224
@@ -81,6 +82,8 @@
#define BATT_THERM_NUM_COEFFS 3
+#define MAX_CC_STEPS 20
+
/* Debug flag definitions */
enum fg_debug_flag {
FG_IRQ = BIT(0), /* Show interrupts */
@@ -192,6 +195,18 @@
int val);
};
+struct fg_dma_address {
+ /* Starting word address of the partition */
+ u16 partition_start;
+ /* Last word address of the partition */
+ u16 partition_end;
+ /*
+ * Byte offset in the FG_DMA peripheral that maps to the partition_start
+ * in SRAM
+ */
+ u16 spmi_addr_base;
+};
+
enum fg_alg_flag_id {
ALG_FLAG_SOC_LT_OTG_MIN = 0,
ALG_FLAG_SOC_LT_RECHARGE,
@@ -228,6 +243,11 @@
NUM_ESR_TIMERS,
};
+enum ttf_mode {
+ TTF_MODE_NORMAL = 0,
+ TTF_MODE_QNOVO,
+};
+
/* DT parameters for FG device */
struct fg_dt_props {
bool force_load_profile;
@@ -265,6 +285,7 @@
int slope_limit_temp;
int esr_pulse_thresh_ma;
int esr_meas_curr_ma;
+ int bmd_en_delay_ms;
int jeita_thresholds[NUM_JEITA_LEVELS];
int ki_coeff_soc[KI_COEFF_SOC_LEVELS];
int ki_coeff_med_dischg[KI_COEFF_SOC_LEVELS];
@@ -309,16 +330,31 @@
};
struct fg_circ_buf {
- int arr[20];
+ int arr[10];
int size;
int head;
};
+struct fg_cc_step_data {
+ int arr[MAX_CC_STEPS];
+ int sel;
+};
+
struct fg_pt {
s32 x;
s32 y;
};
+struct ttf {
+ struct fg_circ_buf ibatt;
+ struct fg_circ_buf vbatt;
+ struct fg_cc_step_data cc_step;
+ struct mutex lock;
+ int mode;
+ int last_ttf;
+ s64 last_ms;
+};
+
static const struct fg_pt fg_ln_table[] = {
{ 1000, 0 },
{ 2000, 693 },
@@ -358,14 +394,15 @@
struct power_supply *usb_psy;
struct power_supply *dc_psy;
struct power_supply *parallel_psy;
+ struct power_supply *pc_port_psy;
struct iio_channel *batt_id_chan;
struct iio_channel *die_temp_chan;
- struct fg_memif *sram;
struct fg_irq_info *irqs;
struct votable *awake_votable;
struct votable *delta_bsoc_irq_en_votable;
struct votable *batt_miss_irq_en_votable;
struct fg_sram_param *sp;
+ struct fg_dma_address *addr_map;
struct fg_alg_flag *alg_flags;
int *debug_mask;
char batt_profile[PROFILE_LEN];
@@ -374,9 +411,9 @@
struct fg_cyc_ctr_data cyc_ctr;
struct notifier_block nb;
struct fg_cap_learning cl;
+ struct ttf ttf;
struct mutex bus_lock;
struct mutex sram_rw_lock;
- struct mutex batt_avg_lock;
struct mutex charge_full_lock;
u32 batt_soc_base;
u32 batt_info_base;
@@ -389,6 +426,7 @@
int prev_charge_status;
int charge_done;
int charge_type;
+ int online_status;
int last_soc;
int last_batt_temp;
int health;
@@ -409,15 +447,14 @@
bool esr_flt_cold_temp_en;
bool slope_limit_en;
bool use_ima_single_mode;
+ bool use_dma;
struct completion soc_update;
struct completion soc_ready;
+ struct completion mem_grant;
struct delayed_work profile_load_work;
struct work_struct status_change_work;
- struct work_struct cycle_count_work;
- struct delayed_work batt_avg_work;
+ struct delayed_work ttf_work;
struct delayed_work sram_dump_work;
- struct fg_circ_buf ibatt_circ_buf;
- struct fg_circ_buf vbatt_circ_buf;
};
/* Debugfs data structures are below */
@@ -459,10 +496,15 @@
u8 offset, u8 *val, int len);
extern int fg_interleaved_mem_write(struct fg_chip *chip, u16 address,
u8 offset, u8 *val, int len, bool atomic_access);
+extern int fg_direct_mem_read(struct fg_chip *chip, u16 address,
+ u8 offset, u8 *val, int len);
+extern int fg_direct_mem_write(struct fg_chip *chip, u16 address,
+ u8 offset, u8 *val, int len, bool atomic_access);
extern int fg_read(struct fg_chip *chip, int addr, u8 *val, int len);
extern int fg_write(struct fg_chip *chip, int addr, u8 *val, int len);
extern int fg_masked_write(struct fg_chip *chip, int addr, u8 mask, u8 val);
extern int fg_ima_init(struct fg_chip *chip);
+extern int fg_dma_init(struct fg_chip *chip);
extern int fg_clear_ima_errors_if_any(struct fg_chip *chip, bool check_hw_sts);
extern int fg_clear_dma_errors_if_any(struct fg_chip *chip);
extern int fg_debugfs_create(struct fg_chip *chip);
@@ -475,6 +517,7 @@
extern void fg_circ_buf_add(struct fg_circ_buf *buf, int val);
extern void fg_circ_buf_clr(struct fg_circ_buf *buf);
extern int fg_circ_buf_avg(struct fg_circ_buf *buf, int *avg);
+extern int fg_circ_buf_median(struct fg_circ_buf *buf, int *median);
extern int fg_lerp(const struct fg_pt *pts, size_t tablesize, s32 input,
s32 *output);
#endif
diff --git a/drivers/power/supply/qcom/fg-memif.c b/drivers/power/supply/qcom/fg-memif.c
index 8a949bf..0abc9df 100644
--- a/drivers/power/supply/qcom/fg-memif.c
+++ b/drivers/power/supply/qcom/fg-memif.c
@@ -746,6 +746,257 @@
return rc;
}
+#define MEM_GRANT_WAIT_MS 200
+static int fg_direct_mem_request(struct fg_chip *chip, bool request)
+{
+ int rc, ret;
+ u8 val, mask;
+ bool tried_again = false;
+
+ if (request)
+ reinit_completion(&chip->mem_grant);
+
+ mask = MEM_ACCESS_REQ_BIT | IACS_SLCT_BIT;
+ val = request ? MEM_ACCESS_REQ_BIT : 0;
+ rc = fg_masked_write(chip, MEM_IF_MEM_INTF_CFG(chip), mask, val);
+ if (rc < 0) {
+ pr_err("failed to configure mem_if_mem_intf_cfg rc=%d\n", rc);
+ return rc;
+ }
+
+ mask = MEM_ARB_LO_LATENCY_EN_BIT | MEM_ARB_REQ_BIT;
+ val = request ? mask : 0;
+ rc = fg_masked_write(chip, MEM_IF_MEM_ARB_CFG(chip), mask, val);
+ if (rc < 0) {
+ pr_err("failed to configure mem_if_mem_arb_cfg rc:%d\n", rc);
+ return rc;
+ }
+
+ if (request)
+ pr_debug("requesting access\n");
+ else
+ pr_debug("releasing access\n");
+
+ if (!request)
+ return 0;
+
+wait:
+ ret = wait_for_completion_interruptible_timeout(
+ &chip->mem_grant, msecs_to_jiffies(MEM_GRANT_WAIT_MS));
+ /* If we were interrupted wait again one more time. */
+ if (ret <= 0) {
+ if ((ret == -ERESTARTSYS || ret == 0) && !tried_again) {
+ pr_debug("trying again, ret=%d\n", ret);
+ tried_again = true;
+ goto wait;
+ } else {
+ pr_err("wait for mem_grant timed out ret=%d\n",
+ ret);
+ }
+ }
+
+ if (ret <= 0) {
+ val = 0;
+ mask = MEM_ACCESS_REQ_BIT | IACS_SLCT_BIT;
+ rc = fg_masked_write(chip, MEM_IF_MEM_INTF_CFG(chip), mask,
+ val);
+ if (rc < 0) {
+ pr_err("failed to configure mem_if_mem_intf_cfg rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ mask = MEM_ARB_LO_LATENCY_EN_BIT | MEM_ARB_REQ_BIT;
+ rc = fg_masked_write(chip, MEM_IF_MEM_ARB_CFG(chip), mask,
+ val);
+ if (rc < 0) {
+ pr_err("failed to configure mem_if_mem_arb_cfg rc:%d\n",
+ rc);
+ return rc;
+ }
+
+ return -ETIMEDOUT;
+ }
+
+ return rc;
+}
+
+static int fg_get_dma_address(struct fg_chip *chip, u16 sram_addr, u8 offset,
+ u16 *addr)
+{
+ int i;
+ u16 start_sram_addr, end_sram_addr;
+
+ for (i = 0; i < NUM_PARTITIONS; i++) {
+ start_sram_addr = chip->addr_map[i].partition_start;
+ end_sram_addr = chip->addr_map[i].partition_end;
+ if (sram_addr >= start_sram_addr &&
+ sram_addr <= end_sram_addr) {
+ *addr = chip->addr_map[i].spmi_addr_base + offset +
+ (sram_addr - start_sram_addr) *
+ BYTES_PER_SRAM_WORD;
+ return 0;
+ }
+ }
+
+ pr_err("Couldn't find address for %d from address map\n", sram_addr);
+ return -ENXIO;
+}
+
+static int fg_get_partition_count(struct fg_chip *chip, u16 sram_addr, int len,
+ int *count)
+{
+ int i, num = 0;
+ u16 end_addr, last_addr = 0;
+
+ end_addr = sram_addr + len / BYTES_PER_SRAM_WORD;
+ if (!(len % BYTES_PER_SRAM_WORD))
+ end_addr -= 1;
+
+ if (sram_addr == end_addr) {
+ *count = 1;
+ return 0;
+ }
+
+ for (i = 0; i < NUM_PARTITIONS; i++) {
+ pr_debug("address: %d last_addr: %d\n", sram_addr, last_addr);
+ if (sram_addr >= chip->addr_map[i].partition_start
+ && sram_addr <= chip->addr_map[i].partition_end
+ && last_addr < end_addr) {
+ num++;
+ last_addr = chip->addr_map[i].partition_end;
+ sram_addr = chip->addr_map[i+1].partition_start;
+ }
+ }
+
+ if (num > 0) {
+ *count = num;
+ return 0;
+ }
+
+ pr_err("Couldn't find number of partitions for address %d\n",
+ sram_addr);
+ return -ENXIO;
+}
+
+static int fg_get_partition_avail_bytes(struct fg_chip *chip, u16 sram_addr,
+ int len, int *rem_len)
+{
+ int i, part_len = 0, temp;
+ u16 end_addr;
+
+ for (i = 0; i < NUM_PARTITIONS; i++) {
+ if (sram_addr >= chip->addr_map[i].partition_start
+ && sram_addr <= chip->addr_map[i].partition_end) {
+ part_len = (chip->addr_map[i].partition_end -
+ chip->addr_map[i].partition_start + 1);
+ part_len *= BYTES_PER_SRAM_WORD;
+ end_addr = chip->addr_map[i].partition_end;
+ break;
+ }
+ }
+
+ if (part_len <= 0) {
+ pr_err("Bad address? total_len=%d\n", part_len);
+ return -ENXIO;
+ }
+
+ temp = (end_addr - sram_addr + 1) * BYTES_PER_SRAM_WORD;
+ if (temp > part_len || !temp) {
+ pr_err("Bad length=%d\n", temp);
+ return -ENXIO;
+ }
+
+ *rem_len = temp;
+ pr_debug("address %d len %d rem_len %d\n", sram_addr, len, *rem_len);
+ return 0;
+}
+
+static int __fg_direct_mem_rw(struct fg_chip *chip, u16 sram_addr, u8 offset,
+ u8 *val, int len, bool access)
+{
+ int rc, ret, num_partitions, num_bytes = 0;
+ u16 addr;
+ u8 *ptr = val;
+ char *temp_str;
+
+ if (offset > 3) {
+ pr_err("offset too large %d\n", offset);
+ return -EINVAL;
+ }
+
+ rc = fg_get_partition_count(chip, sram_addr, len, &num_partitions);
+ if (rc < 0)
+ return rc;
+
+ pr_debug("number of partitions: %d\n", num_partitions);
+
+ rc = fg_direct_mem_request(chip, true);
+ if (rc < 0) {
+ pr_err("Error in requesting direct_mem access rc=%d\n", rc);
+ return rc;
+ }
+
+ while (num_partitions-- && len) {
+ rc = fg_get_dma_address(chip, sram_addr, offset, &addr);
+ if (rc < 0) {
+ pr_err("Incorrect address %d/offset %d\n", sram_addr,
+ offset);
+ break;
+ }
+
+ rc = fg_get_partition_avail_bytes(chip, sram_addr + offset, len,
+ &num_bytes);
+ if (rc < 0)
+ break;
+
+ if (num_bytes > len)
+ num_bytes = len;
+
+ pr_debug("reading from address: [%d %d] dma_address = %x\n",
+ sram_addr, offset, addr);
+
+ if (access == FG_READ) {
+ rc = fg_read(chip, addr, ptr, num_bytes);
+ temp_str = "read";
+ } else {
+ rc = fg_write(chip, addr, ptr, num_bytes);
+ temp_str = "write";
+ }
+
+ if (rc < 0) {
+ pr_err("Error in %sing address %d rc=%d\n", temp_str,
+ sram_addr, rc);
+ break;
+ }
+
+ ptr += num_bytes;
+ len -= num_bytes;
+ sram_addr += (num_bytes / BYTES_PER_SRAM_WORD);
+ offset = 0;
+ }
+
+ ret = fg_direct_mem_request(chip, false);
+ if (ret < 0) {
+ pr_err("Error in releasing direct_mem access rc=%d\n", rc);
+ return ret;
+ }
+
+ return rc;
+}
+
+int fg_direct_mem_read(struct fg_chip *chip, u16 sram_addr, u8 offset,
+ u8 *val, int len)
+{
+ return __fg_direct_mem_rw(chip, sram_addr, offset, val, len, FG_READ);
+}
+
+int fg_direct_mem_write(struct fg_chip *chip, u16 sram_addr, u8 offset,
+ u8 *val, int len, bool atomic_access)
+{
+ return __fg_direct_mem_rw(chip, sram_addr, offset, val, len, FG_WRITE);
+}
+
int fg_ima_init(struct fg_chip *chip)
{
int rc;
@@ -778,3 +1029,59 @@
return 0;
}
+
+/*
+ * This SRAM partition to DMA address partition mapping remains identical for
+ * PMICs that use GEN3 FG.
+ */
+static struct fg_dma_address fg_gen3_addr_map[NUM_PARTITIONS] = {
+ /* system partition */
+ {
+ .partition_start = 0,
+ .partition_end = 23,
+ .spmi_addr_base = FG_DMA0_BASE + SRAM_ADDR_OFFSET,
+ },
+ /* battery profile partition */
+ {
+ .partition_start = 24,
+ .partition_end = 79,
+ .spmi_addr_base = FG_DMA1_BASE + SRAM_ADDR_OFFSET,
+ },
+ /* scratch pad partition */
+ {
+ .partition_start = 80,
+ .partition_end = 125,
+ .spmi_addr_base = FG_DMA2_BASE + SRAM_ADDR_OFFSET,
+ },
+};
+int fg_dma_init(struct fg_chip *chip)
+{
+ int rc;
+
+ chip->addr_map = fg_gen3_addr_map;
+
+ /* Clear DMA errors if any before clearing IMA errors */
+ rc = fg_clear_dma_errors_if_any(chip);
+ if (rc < 0) {
+ pr_err("Error in checking DMA errors rc:%d\n", rc);
+ return rc;
+ }
+
+ /* Configure the DMA peripheral addressing to partition */
+ rc = fg_masked_write(chip, MEM_IF_DMA_CTL(chip), ADDR_KIND_BIT,
+ ADDR_KIND_BIT);
+ if (rc < 0) {
+ pr_err("failed to configure DMA_CTL rc:%d\n", rc);
+ return rc;
+ }
+
+ /* Release the DMA initially so that request can happen */
+ rc = fg_direct_mem_request(chip, false);
+ if (rc < 0) {
+ pr_err("Error in releasing direct_mem access rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ return 0;
+}
diff --git a/drivers/power/supply/qcom/fg-reg.h b/drivers/power/supply/qcom/fg-reg.h
index cd0b2fb..8ca4376 100644
--- a/drivers/power/supply/qcom/fg-reg.h
+++ b/drivers/power/supply/qcom/fg-reg.h
@@ -31,6 +31,7 @@
#define BATT_SOC_LOW_PWR_STS(chip) (chip->batt_soc_base + 0x56)
/* BATT_SOC_INT_RT_STS */
+#define SOC_READY_BIT BIT(1)
#define MSOC_EMPTY_BIT BIT(5)
/* BATT_SOC_EN_CTL */
@@ -266,6 +267,7 @@
/* FG_MEM_IF register and bit definitions */
#define MEM_IF_INT_RT_STS(chip) ((chip->mem_if_base) + 0x10)
+#define MEM_IF_MEM_ARB_CFG(chip) ((chip->mem_if_base) + 0x40)
#define MEM_IF_MEM_INTF_CFG(chip) ((chip->mem_if_base) + 0x50)
#define MEM_IF_IMA_CTL(chip) ((chip->mem_if_base) + 0x51)
#define MEM_IF_IMA_CFG(chip) ((chip->mem_if_base) + 0x52)
@@ -286,6 +288,11 @@
/* MEM_IF_INT_RT_STS */
#define MEM_XCP_BIT BIT(1)
+#define MEM_GNT_BIT BIT(2)
+
+/* MEM_IF_MEM_ARB_CFG */
+#define MEM_ARB_LO_LATENCY_EN_BIT BIT(1)
+#define MEM_ARB_REQ_BIT BIT(0)
/* MEM_IF_MEM_INTF_CFG */
#define MEM_ACCESS_REQ_BIT BIT(7)
@@ -325,5 +332,13 @@
#define DMA_READ_ERROR_BIT BIT(2)
/* MEM_IF_DMA_CTL */
+#define ADDR_KIND_BIT BIT(1)
#define DMA_CLEAR_LOG_BIT BIT(0)
+
+/* FG_DMAx */
+#define FG_DMA0_BASE 0x4800
+#define FG_DMA1_BASE 0x4900
+#define FG_DMA2_BASE 0x4A00
+#define FG_DMA3_BASE 0x4B00
+#define SRAM_ADDR_OFFSET 0x20
#endif
diff --git a/drivers/power/supply/qcom/fg-util.c b/drivers/power/supply/qcom/fg-util.c
index 38d9594..aed2062 100644
--- a/drivers/power/supply/qcom/fg-util.c
+++ b/drivers/power/supply/qcom/fg-util.c
@@ -10,6 +10,7 @@
* GNU General Public License for more details.
*/
+#include <linux/sort.h>
#include "fg-core.h"
void fg_circ_buf_add(struct fg_circ_buf *buf, int val)
@@ -21,7 +22,9 @@
void fg_circ_buf_clr(struct fg_circ_buf *buf)
{
- memset(buf, 0, sizeof(*buf));
+ buf->size = 0;
+ buf->head = 0;
+ memset(buf->arr, 0, sizeof(buf->arr));
}
int fg_circ_buf_avg(struct fg_circ_buf *buf, int *avg)
@@ -39,6 +42,39 @@
return 0;
}
+static int cmp_int(const void *a, const void *b)
+{
+ return *(int *)a - *(int *)b;
+}
+
+int fg_circ_buf_median(struct fg_circ_buf *buf, int *median)
+{
+ int *temp;
+
+ if (buf->size == 0)
+ return -ENODATA;
+
+ if (buf->size == 1) {
+ *median = buf->arr[0];
+ return 0;
+ }
+
+ temp = kmalloc_array(buf->size, sizeof(*temp), GFP_KERNEL);
+ if (!temp)
+ return -ENOMEM;
+
+ memcpy(temp, buf->arr, buf->size * sizeof(*temp));
+ sort(temp, buf->size, sizeof(*temp), cmp_int, NULL);
+
+ if (buf->size % 2)
+ *median = temp[buf->size / 2];
+ else
+ *median = (temp[buf->size / 2 - 1] + temp[buf->size / 2]) / 2;
+
+ kfree(temp);
+ return 0;
+}
+
int fg_lerp(const struct fg_pt *pts, size_t tablesize, s32 input, s32 *output)
{
int i;
@@ -255,8 +291,6 @@
reinit_completion(&chip->soc_update);
enable_irq(chip->irqs[SOC_UPDATE_IRQ].irq);
atomic_access = true;
- } else {
- flags = FG_IMA_DEFAULT;
}
wait:
/*
@@ -282,11 +316,17 @@
}
}
- rc = fg_interleaved_mem_write(chip, address, offset, val, len,
- atomic_access);
+ if (chip->use_dma)
+ rc = fg_direct_mem_write(chip, address, offset, val, len,
+ false);
+ else
+ rc = fg_interleaved_mem_write(chip, address, offset, val, len,
+ atomic_access);
+
if (rc < 0)
pr_err("Error in writing SRAM address 0x%x[%d], rc=%d\n",
address, offset, rc);
+
out:
if (atomic_access)
disable_irq_nosync(chip->irqs[SOC_UPDATE_IRQ].irq);
@@ -313,9 +353,14 @@
if (!(flags & FG_IMA_NO_WLOCK))
vote(chip->awake_votable, SRAM_READ, true, 0);
+
mutex_lock(&chip->sram_rw_lock);
- rc = fg_interleaved_mem_read(chip, address, offset, val, len);
+ if (chip->use_dma)
+ rc = fg_direct_mem_read(chip, address, offset, val, len);
+ else
+ rc = fg_interleaved_mem_read(chip, address, offset, val, len);
+
if (rc < 0)
pr_err("Error in reading SRAM address 0x%x[%d], rc=%d\n",
address, offset, rc);
diff --git a/drivers/power/supply/qcom/pmic-voter.c b/drivers/power/supply/qcom/pmic-voter.c
index 10a1c54..e0a5150 100644
--- a/drivers/power/supply/qcom/pmic-voter.c
+++ b/drivers/power/supply/qcom/pmic-voter.c
@@ -438,12 +438,14 @@
int rerun_election(struct votable *votable)
{
int rc = 0;
+ int effective_result;
lock_votable(votable);
+ effective_result = get_effective_result_locked(votable);
if (votable->callback)
rc = votable->callback(votable,
- votable->data,
- votable->effective_result,
+ votable->data,
+ effective_result,
get_client_str(votable, votable->effective_client_id));
unlock_votable(votable);
return rc;
@@ -519,11 +521,10 @@
lock_votable(votable);
- seq_printf(m, "Votable %s:\n", votable->name);
- seq_puts(m, "clients:\n");
for (i = 0; i < votable->num_clients; i++) {
if (votable->client_strs[i]) {
- seq_printf(m, "%-15s:\t\ten=%d\t\tv=%d\n",
+ seq_printf(m, "%s: %s:\t\t\ten=%d v=%d\n",
+ votable->name,
votable->client_strs[i],
votable->votes[i].enabled,
votable->votes[i].value);
@@ -542,11 +543,11 @@
break;
}
- seq_printf(m, "type: %s\n", type_str);
- seq_puts(m, "Effective:\n");
effective_client_str = get_effective_client_locked(votable);
- seq_printf(m, "%-15s:\t\tv=%d\n",
+ seq_printf(m, "%s: effective=%s type=%s v=%d\n",
+ votable->name,
effective_client_str ? effective_client_str : "none",
+ type_str,
get_effective_result_locked(votable));
unlock_votable(votable);
diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c
index e5a3a07..5b629e4 100644
--- a/drivers/power/supply/qcom/qpnp-fg-gen3.c
+++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c
@@ -75,6 +75,8 @@
#define ESR_TIMER_CHG_MAX_OFFSET 0
#define ESR_TIMER_CHG_INIT_WORD 18
#define ESR_TIMER_CHG_INIT_OFFSET 2
+#define ESR_EXTRACTION_ENABLE_WORD 19
+#define ESR_EXTRACTION_ENABLE_OFFSET 0
#define PROFILE_LOAD_WORD 24
#define PROFILE_LOAD_OFFSET 0
#define ESR_RSLOW_DISCHG_WORD 34
@@ -533,7 +535,7 @@
rc = fg_sram_read(chip, chip->sp[id].addr_word, chip->sp[id].addr_byte,
buf, chip->sp[id].len, FG_IMA_DEFAULT);
if (rc < 0) {
- pr_err("Error reading address 0x%04x[%d] rc=%d\n",
+ pr_err("Error reading address %d[%d] rc=%d\n",
chip->sp[id].addr_word, chip->sp[id].addr_byte, rc);
return rc;
}
@@ -892,8 +894,8 @@
goto out;
}
- /* Wait for 200ms before enabling BMD again */
- msleep(200);
+ /* Wait for BATT_ID to settle down before enabling BMD again */
+ msleep(chip->dt.bmd_en_delay_ms);
fg_dbg(chip, FG_STATUS, "batt_id: %d\n", batt_id);
chip->batt_id_ohms = batt_id;
@@ -1171,6 +1173,42 @@
return true;
}
+static bool usb_psy_initialized(struct fg_chip *chip)
+{
+ if (chip->usb_psy)
+ return true;
+
+ chip->usb_psy = power_supply_get_by_name("usb");
+ if (!chip->usb_psy)
+ return false;
+
+ return true;
+}
+
+static bool pc_port_psy_initialized(struct fg_chip *chip)
+{
+ if (chip->pc_port_psy)
+ return true;
+
+ chip->pc_port_psy = power_supply_get_by_name("pc_port");
+ if (!chip->pc_port_psy)
+ return false;
+
+ return true;
+}
+
+static bool dc_psy_initialized(struct fg_chip *chip)
+{
+ if (chip->dc_psy)
+ return true;
+
+ chip->dc_psy = power_supply_get_by_name("dc");
+ if (!chip->dc_psy)
+ return false;
+
+ return true;
+}
+
static bool is_parallel_charger_available(struct fg_chip *chip)
{
if (!chip->parallel_psy)
@@ -1611,7 +1649,7 @@
static int fg_charge_full_update(struct fg_chip *chip)
{
union power_supply_propval prop = {0, };
- int rc, msoc, bsoc, recharge_soc;
+ int rc, msoc, bsoc, recharge_soc, msoc_raw;
u8 full_soc[2] = {0xFF, 0xFF};
if (!chip->dt.hold_soc_while_full)
@@ -1647,6 +1685,7 @@
pr_err("Error in getting msoc, rc=%d\n", rc);
goto out;
}
+ msoc_raw = DIV_ROUND_CLOSEST(msoc * FULL_SOC_RAW, FULL_CAPACITY);
fg_dbg(chip, FG_STATUS, "msoc: %d bsoc: %x health: %d status: %d full: %d\n",
msoc, bsoc, chip->health, chip->charge_status,
@@ -1670,7 +1709,7 @@
fg_dbg(chip, FG_STATUS, "Terminated charging @ SOC%d\n",
msoc);
}
- } else if ((bsoc >> 8) <= recharge_soc && chip->charge_full) {
+ } else if (msoc_raw < recharge_soc && chip->charge_full) {
chip->delta_soc = FULL_CAPACITY - msoc;
/*
@@ -1700,8 +1739,8 @@
rc);
goto out;
}
- fg_dbg(chip, FG_STATUS, "bsoc: %d recharge_soc: %d delta_soc: %d\n",
- bsoc >> 8, recharge_soc, chip->delta_soc);
+ fg_dbg(chip, FG_STATUS, "msoc_raw = %d bsoc: %d recharge_soc: %d delta_soc: %d\n",
+ msoc_raw, bsoc >> 8, recharge_soc, chip->delta_soc);
} else {
goto out;
}
@@ -2130,102 +2169,67 @@
return 0;
}
-static void fg_batt_avg_update(struct fg_chip *chip)
+static void fg_ttf_update(struct fg_chip *chip)
{
- if (chip->charge_status == chip->prev_charge_status)
+ int rc;
+ int delay_ms;
+ union power_supply_propval prop = {0, };
+ int online = 0;
+
+ if (usb_psy_initialized(chip)) {
+ rc = power_supply_get_property(chip->usb_psy,
+ POWER_SUPPLY_PROP_ONLINE, &prop);
+ if (rc < 0) {
+ pr_err("Couldn't read usb ONLINE prop rc=%d\n", rc);
+ return;
+ }
+
+ online = online || prop.intval;
+ }
+
+ if (pc_port_psy_initialized(chip)) {
+ rc = power_supply_get_property(chip->pc_port_psy,
+ POWER_SUPPLY_PROP_ONLINE, &prop);
+ if (rc < 0) {
+ pr_err("Couldn't read pc_port ONLINE prop rc=%d\n", rc);
+ return;
+ }
+
+ online = online || prop.intval;
+ }
+
+ if (dc_psy_initialized(chip)) {
+ rc = power_supply_get_property(chip->dc_psy,
+ POWER_SUPPLY_PROP_ONLINE, &prop);
+ if (rc < 0) {
+ pr_err("Couldn't read dc ONLINE prop rc=%d\n", rc);
+ return;
+ }
+
+ online = online || prop.intval;
+ }
+
+
+ if (chip->online_status == online)
return;
- cancel_delayed_work_sync(&chip->batt_avg_work);
- fg_circ_buf_clr(&chip->ibatt_circ_buf);
- fg_circ_buf_clr(&chip->vbatt_circ_buf);
+ chip->online_status = online;
+ if (online)
+ /* wait 35 seconds for the input to settle */
+ delay_ms = 35000;
+ else
+ /* wait 5 seconds for current to settle during discharge */
+ delay_ms = 5000;
- if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING ||
- chip->charge_status == POWER_SUPPLY_STATUS_DISCHARGING)
- schedule_delayed_work(&chip->batt_avg_work,
- msecs_to_jiffies(2000));
-}
-
-static void status_change_work(struct work_struct *work)
-{
- struct fg_chip *chip = container_of(work,
- struct fg_chip, status_change_work);
- union power_supply_propval prop = {0, };
- int rc, batt_temp;
-
- if (!batt_psy_initialized(chip)) {
- fg_dbg(chip, FG_STATUS, "Charger not available?!\n");
- goto out;
- }
-
- rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_STATUS,
- &prop);
- if (rc < 0) {
- pr_err("Error in getting charging status, rc=%d\n", rc);
- goto out;
- }
-
- chip->prev_charge_status = chip->charge_status;
- chip->charge_status = prop.intval;
- rc = power_supply_get_property(chip->batt_psy,
- POWER_SUPPLY_PROP_CHARGE_TYPE, &prop);
- if (rc < 0) {
- pr_err("Error in getting charge type, rc=%d\n", rc);
- goto out;
- }
-
- chip->charge_type = prop.intval;
- rc = power_supply_get_property(chip->batt_psy,
- POWER_SUPPLY_PROP_CHARGE_DONE, &prop);
- if (rc < 0) {
- pr_err("Error in getting charge_done, rc=%d\n", rc);
- goto out;
- }
-
- chip->charge_done = prop.intval;
- if (chip->cyc_ctr.en)
- schedule_work(&chip->cycle_count_work);
-
- fg_cap_learning_update(chip);
-
- rc = fg_charge_full_update(chip);
- if (rc < 0)
- pr_err("Error in charge_full_update, rc=%d\n", rc);
-
- rc = fg_adjust_recharge_soc(chip);
- if (rc < 0)
- pr_err("Error in adjusting recharge_soc, rc=%d\n", rc);
-
- rc = fg_adjust_ki_coeff_dischg(chip);
- if (rc < 0)
- pr_err("Error in adjusting ki_coeff_dischg, rc=%d\n", rc);
-
- rc = fg_esr_fcc_config(chip);
- if (rc < 0)
- pr_err("Error in adjusting FCC for ESR, rc=%d\n", rc);
-
- rc = fg_esr_timer_config(chip, false);
- if (rc < 0)
- pr_err("Error in configuring ESR timer, rc=%d\n", rc);
-
- rc = fg_get_battery_temp(chip, &batt_temp);
- if (!rc) {
- rc = fg_slope_limit_config(chip, batt_temp);
- if (rc < 0)
- pr_err("Error in configuring slope limiter rc:%d\n",
- rc);
-
- rc = fg_adjust_ki_coeff_full_soc(chip, batt_temp);
- if (rc < 0)
- pr_err("Error in configuring ki_coeff_full_soc rc:%d\n",
- rc);
- }
-
- fg_batt_avg_update(chip);
-
-out:
- fg_dbg(chip, FG_POWER_SUPPLY, "charge_status:%d charge_type:%d charge_done:%d\n",
- chip->charge_status, chip->charge_type, chip->charge_done);
- pm_relax(chip->dev);
+ vote(chip->awake_votable, TTF_PRIMING, true, 0);
+ cancel_delayed_work_sync(&chip->ttf_work);
+ mutex_lock(&chip->ttf.lock);
+ fg_circ_buf_clr(&chip->ttf.ibatt);
+ fg_circ_buf_clr(&chip->ttf.vbatt);
+ chip->ttf.last_ttf = 0;
+ chip->ttf.last_ms = 0;
+ mutex_unlock(&chip->ttf.lock);
+ schedule_delayed_work(&chip->ttf_work, msecs_to_jiffies(delay_ms));
}
static void restore_cycle_counter(struct fg_chip *chip)
@@ -2233,6 +2237,9 @@
int rc = 0, i;
u8 data[2];
+ if (!chip->cyc_ctr.en)
+ return;
+
mutex_lock(&chip->cyc_ctr.lock);
for (i = 0; i < BUCKET_COUNT; i++) {
rc = fg_sram_read(chip, CYCLE_COUNT_WORD + (i / 2),
@@ -2286,20 +2293,25 @@
rc = fg_sram_write(chip, CYCLE_COUNT_WORD + (bucket / 2),
CYCLE_COUNT_OFFSET + (bucket % 2) * 2, data, 2,
FG_IMA_DEFAULT);
- if (rc < 0)
+ if (rc < 0) {
pr_err("failed to write BATT_CYCLE[%d] rc=%d\n",
bucket, rc);
- else
- chip->cyc_ctr.count[bucket] = cyc_count;
+ return rc;
+ }
+
+ chip->cyc_ctr.count[bucket] = cyc_count;
+ fg_dbg(chip, FG_STATUS, "Stored count %d in bucket %d\n", cyc_count,
+ bucket);
+
return rc;
}
-static void cycle_count_work(struct work_struct *work)
+static void fg_cycle_counter_update(struct fg_chip *chip)
{
int rc = 0, bucket, i, batt_soc;
- struct fg_chip *chip = container_of(work,
- struct fg_chip,
- cycle_count_work);
+
+ if (!chip->cyc_ctr.en)
+ return;
mutex_lock(&chip->cyc_ctr.lock);
rc = fg_get_sram_prop(chip, FG_SRAM_BATT_SOC, &batt_soc);
@@ -2311,45 +2323,30 @@
/* We need only the most significant byte here */
batt_soc = (u32)batt_soc >> 24;
- if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) {
- /* Find out which bucket the SOC falls in */
- bucket = batt_soc / BUCKET_SOC_PCT;
- pr_debug("batt_soc: %d bucket: %d\n", batt_soc, bucket);
+ /* Find out which bucket the SOC falls in */
+ bucket = batt_soc / BUCKET_SOC_PCT;
- /*
- * If we've started counting for the previous bucket,
- * then store the counter for that bucket if the
- * counter for current bucket is getting started.
- */
- if (bucket > 0 && chip->cyc_ctr.started[bucket - 1] &&
- !chip->cyc_ctr.started[bucket]) {
- rc = fg_inc_store_cycle_ctr(chip, bucket - 1);
- if (rc < 0) {
- pr_err("Error in storing cycle_ctr rc: %d\n",
- rc);
- goto out;
- } else {
- chip->cyc_ctr.started[bucket - 1] = false;
- chip->cyc_ctr.last_soc[bucket - 1] = 0;
- }
- }
+ if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) {
if (!chip->cyc_ctr.started[bucket]) {
chip->cyc_ctr.started[bucket] = true;
chip->cyc_ctr.last_soc[bucket] = batt_soc;
}
- } else {
+ } else if (chip->charge_done || !is_input_present(chip)) {
for (i = 0; i < BUCKET_COUNT; i++) {
if (chip->cyc_ctr.started[i] &&
- batt_soc > chip->cyc_ctr.last_soc[i]) {
+ batt_soc > chip->cyc_ctr.last_soc[i] + 2) {
rc = fg_inc_store_cycle_ctr(chip, i);
if (rc < 0)
pr_err("Error in storing cycle_ctr rc: %d\n",
rc);
chip->cyc_ctr.last_soc[i] = 0;
+ chip->cyc_ctr.started[i] = false;
}
- chip->cyc_ctr.started[i] = false;
}
}
+
+ fg_dbg(chip, FG_STATUS, "batt_soc: %d bucket: %d chg_status: %d\n",
+ batt_soc, bucket, chip->charge_status);
out:
mutex_unlock(&chip->cyc_ctr.lock);
}
@@ -2370,6 +2367,83 @@
return count;
}
+static void status_change_work(struct work_struct *work)
+{
+ struct fg_chip *chip = container_of(work,
+ struct fg_chip, status_change_work);
+ union power_supply_propval prop = {0, };
+ int rc, batt_temp;
+
+ if (!batt_psy_initialized(chip)) {
+ fg_dbg(chip, FG_STATUS, "Charger not available?!\n");
+ goto out;
+ }
+
+ rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_STATUS,
+ &prop);
+ if (rc < 0) {
+ pr_err("Error in getting charging status, rc=%d\n", rc);
+ goto out;
+ }
+
+ chip->prev_charge_status = chip->charge_status;
+ chip->charge_status = prop.intval;
+ rc = power_supply_get_property(chip->batt_psy,
+ POWER_SUPPLY_PROP_CHARGE_TYPE, &prop);
+ if (rc < 0) {
+ pr_err("Error in getting charge type, rc=%d\n", rc);
+ goto out;
+ }
+
+ chip->charge_type = prop.intval;
+ rc = power_supply_get_property(chip->batt_psy,
+ POWER_SUPPLY_PROP_CHARGE_DONE, &prop);
+ if (rc < 0) {
+ pr_err("Error in getting charge_done, rc=%d\n", rc);
+ goto out;
+ }
+
+ chip->charge_done = prop.intval;
+ fg_cycle_counter_update(chip);
+ fg_cap_learning_update(chip);
+
+ rc = fg_charge_full_update(chip);
+ if (rc < 0)
+ pr_err("Error in charge_full_update, rc=%d\n", rc);
+
+ rc = fg_adjust_recharge_soc(chip);
+ if (rc < 0)
+ pr_err("Error in adjusting recharge_soc, rc=%d\n", rc);
+
+ rc = fg_adjust_ki_coeff_dischg(chip);
+ if (rc < 0)
+ pr_err("Error in adjusting ki_coeff_dischg, rc=%d\n", rc);
+
+ rc = fg_esr_fcc_config(chip);
+ if (rc < 0)
+ pr_err("Error in adjusting FCC for ESR, rc=%d\n", rc);
+
+ rc = fg_get_battery_temp(chip, &batt_temp);
+ if (!rc) {
+ rc = fg_slope_limit_config(chip, batt_temp);
+ if (rc < 0)
+ pr_err("Error in configuring slope limiter rc:%d\n",
+ rc);
+
+ rc = fg_adjust_ki_coeff_full_soc(chip, batt_temp);
+ if (rc < 0)
+ pr_err("Error in configuring ki_coeff_full_soc rc:%d\n",
+ rc);
+ }
+
+ fg_ttf_update(chip);
+
+out:
+ fg_dbg(chip, FG_POWER_SUPPLY, "charge_status:%d charge_type:%d charge_done:%d\n",
+ chip->charge_status, chip->charge_type, chip->charge_done);
+ pm_relax(chip->dev);
+}
+
static int fg_bp_params_config(struct fg_chip *chip)
{
int rc = 0;
@@ -2730,45 +2804,19 @@
module_param_cb(restart, &fg_restart_ops, &fg_restart, 0644);
-#define BATT_AVG_POLL_PERIOD_MS 10000
-static void batt_avg_work(struct work_struct *work)
-{
- struct fg_chip *chip = container_of(work, struct fg_chip,
- batt_avg_work.work);
- int rc, ibatt_now, vbatt_now;
-
- mutex_lock(&chip->batt_avg_lock);
- rc = fg_get_battery_current(chip, &ibatt_now);
- if (rc < 0) {
- pr_err("failed to get battery current, rc=%d\n", rc);
- goto reschedule;
- }
-
- rc = fg_get_battery_voltage(chip, &vbatt_now);
- if (rc < 0) {
- pr_err("failed to get battery voltage, rc=%d\n", rc);
- goto reschedule;
- }
-
- fg_circ_buf_add(&chip->ibatt_circ_buf, ibatt_now);
- fg_circ_buf_add(&chip->vbatt_circ_buf, vbatt_now);
-
-reschedule:
- mutex_unlock(&chip->batt_avg_lock);
- schedule_delayed_work(&chip->batt_avg_work,
- msecs_to_jiffies(BATT_AVG_POLL_PERIOD_MS));
-}
-
#define HOURS_TO_SECONDS 3600
#define OCV_SLOPE_UV 10869
#define MILLI_UNIT 1000
#define MICRO_UNIT 1000000
-static int fg_get_time_to_full(struct fg_chip *chip, int *val)
+#define NANO_UNIT 1000000000
+static int fg_get_time_to_full_locked(struct fg_chip *chip, int *val)
{
- int rc, ibatt_avg, vbatt_avg, rbatt, msoc, ocv_cc2cv, full_soc,
- act_cap_uah;
- s32 i_cc2cv, soc_cc2cv, ln_val, centi_tau_scale;
- s64 t_predicted_cc = 0, t_predicted_cv = 0;
+ int rc, ibatt_avg, vbatt_avg, rbatt, msoc, full_soc, act_cap_mah,
+ i_cc2cv = 0, soc_cc2cv, tau, divisor, iterm, ttf_mode,
+ i, soc_per_step, msoc_this_step, msoc_next_step,
+ ibatt_this_step, t_predicted_this_step, ttf_slope,
+ t_predicted_cv, t_predicted = 0;
+ s64 delta_ms;
if (chip->bp.float_volt_uv <= 0) {
pr_err("battery profile is not loaded\n");
@@ -2787,48 +2835,53 @@
}
fg_dbg(chip, FG_TTF, "msoc=%d\n", msoc);
+ /* the battery is considered full if the SOC is 100% */
if (msoc >= 100) {
*val = 0;
return 0;
}
- mutex_lock(&chip->batt_avg_lock);
- rc = fg_circ_buf_avg(&chip->ibatt_circ_buf, &ibatt_avg);
- if (rc < 0) {
- /* try to get instantaneous current */
- rc = fg_get_battery_current(chip, &ibatt_avg);
- if (rc < 0) {
- mutex_unlock(&chip->batt_avg_lock);
- pr_err("failed to get battery current, rc=%d\n", rc);
- return rc;
- }
+ if (is_qnovo_en(chip))
+ ttf_mode = TTF_MODE_QNOVO;
+ else
+ ttf_mode = TTF_MODE_NORMAL;
+
+ /* when switching TTF algorithms the TTF needs to be reset */
+ if (chip->ttf.mode != ttf_mode) {
+ fg_circ_buf_clr(&chip->ttf.ibatt);
+ fg_circ_buf_clr(&chip->ttf.vbatt);
+ chip->ttf.last_ttf = 0;
+ chip->ttf.last_ms = 0;
+ chip->ttf.mode = ttf_mode;
}
- rc = fg_circ_buf_avg(&chip->vbatt_circ_buf, &vbatt_avg);
- if (rc < 0) {
- /* try to get instantaneous voltage */
- rc = fg_get_battery_voltage(chip, &vbatt_avg);
- if (rc < 0) {
- mutex_unlock(&chip->batt_avg_lock);
- pr_err("failed to get battery voltage, rc=%d\n", rc);
- return rc;
- }
+ /* at least 10 samples are required to produce a stable IBATT */
+ if (chip->ttf.ibatt.size < 10) {
+ *val = -1;
+ return 0;
}
- mutex_unlock(&chip->batt_avg_lock);
- fg_dbg(chip, FG_TTF, "vbatt_avg=%d\n", vbatt_avg);
+ rc = fg_circ_buf_median(&chip->ttf.ibatt, &ibatt_avg);
+ if (rc < 0) {
+ pr_err("failed to get IBATT AVG rc=%d\n", rc);
+ return rc;
+ }
- /* clamp ibatt_avg to -150mA */
- if (ibatt_avg > -150000)
- ibatt_avg = -150000;
+ rc = fg_circ_buf_median(&chip->ttf.vbatt, &vbatt_avg);
+ if (rc < 0) {
+ pr_err("failed to get VBATT AVG rc=%d\n", rc);
+ return rc;
+ }
+
+ ibatt_avg = -ibatt_avg / MILLI_UNIT;
+ vbatt_avg /= MILLI_UNIT;
+
+ /* clamp ibatt_avg to iterm */
+ if (ibatt_avg < abs(chip->dt.sys_term_curr_ma))
+ ibatt_avg = abs(chip->dt.sys_term_curr_ma);
+
fg_dbg(chip, FG_TTF, "ibatt_avg=%d\n", ibatt_avg);
-
- /* reverse polarity to be consistent with unsigned current settings */
- ibatt_avg = abs(ibatt_avg);
-
- /* estimated battery current at the CC to CV transition */
- i_cc2cv = div_s64((s64)ibatt_avg * vbatt_avg, chip->bp.float_volt_uv);
- fg_dbg(chip, FG_TTF, "i_cc2cv=%d\n", i_cc2cv);
+ fg_dbg(chip, FG_TTF, "vbatt_avg=%d\n", vbatt_avg);
rc = fg_get_battery_resistance(chip, &rbatt);
if (rc < 0) {
@@ -2836,19 +2889,14 @@
return rc;
}
- /* clamp rbatt to 50mOhms */
- if (rbatt < 50000)
- rbatt = 50000;
-
+ rbatt /= MILLI_UNIT;
fg_dbg(chip, FG_TTF, "rbatt=%d\n", rbatt);
- rc = fg_get_sram_prop(chip, FG_SRAM_ACT_BATT_CAP, &act_cap_uah);
+ rc = fg_get_sram_prop(chip, FG_SRAM_ACT_BATT_CAP, &act_cap_mah);
if (rc < 0) {
pr_err("failed to get ACT_BATT_CAP rc=%d\n", rc);
return rc;
}
- act_cap_uah *= MILLI_UNIT;
- fg_dbg(chip, FG_TTF, "actual_capacity_uah=%d\n", act_cap_uah);
rc = fg_get_sram_prop(chip, FG_SRAM_FULL_SOC, &full_soc);
if (rc < 0) {
@@ -2857,69 +2905,148 @@
}
full_soc = DIV_ROUND_CLOSEST(((u16)full_soc >> 8) * FULL_CAPACITY,
FULL_SOC_RAW);
- fg_dbg(chip, FG_TTF, "full_soc=%d\n", full_soc);
+ act_cap_mah = full_soc * act_cap_mah / 100;
+ fg_dbg(chip, FG_TTF, "act_cap_mah=%d\n", act_cap_mah);
+
+ /* estimated battery current at the CC to CV transition */
+ switch (chip->ttf.mode) {
+ case TTF_MODE_NORMAL:
+ i_cc2cv = ibatt_avg * vbatt_avg /
+ max(MILLI_UNIT, chip->bp.float_volt_uv / MILLI_UNIT);
+ break;
+ case TTF_MODE_QNOVO:
+ i_cc2cv = min(
+ chip->ttf.cc_step.arr[MAX_CC_STEPS - 1] / MILLI_UNIT,
+ ibatt_avg * vbatt_avg /
+ max(MILLI_UNIT, chip->bp.float_volt_uv / MILLI_UNIT));
+ break;
+ default:
+ pr_err("TTF mode %d is not supported\n", chip->ttf.mode);
+ break;
+ }
+ fg_dbg(chip, FG_TTF, "i_cc2cv=%d\n", i_cc2cv);
/* if we are already in CV state then we can skip estimating CC */
if (chip->charge_type == POWER_SUPPLY_CHARGE_TYPE_TAPER)
- goto skip_cc_estimate;
+ goto cv_estimate;
- /* if the charger is current limited then use power approximation */
- if (ibatt_avg > chip->bp.fastchg_curr_ma * MILLI_UNIT - 50000)
- ocv_cc2cv = div_s64((s64)rbatt * ibatt_avg, MICRO_UNIT);
- else
- ocv_cc2cv = div_s64((s64)rbatt * i_cc2cv, MICRO_UNIT);
- ocv_cc2cv = chip->bp.float_volt_uv - ocv_cc2cv;
- fg_dbg(chip, FG_TTF, "ocv_cc2cv=%d\n", ocv_cc2cv);
-
- soc_cc2cv = div_s64(chip->bp.float_volt_uv - ocv_cc2cv, OCV_SLOPE_UV);
/* estimated SOC at the CC to CV transition */
+ soc_cc2cv = DIV_ROUND_CLOSEST(rbatt * i_cc2cv, OCV_SLOPE_UV);
soc_cc2cv = 100 - soc_cc2cv;
fg_dbg(chip, FG_TTF, "soc_cc2cv=%d\n", soc_cc2cv);
- /* the esimated SOC may be lower than the current SOC */
- if (soc_cc2cv - msoc <= 0)
- goto skip_cc_estimate;
+ switch (chip->ttf.mode) {
+ case TTF_MODE_NORMAL:
+ if (soc_cc2cv - msoc <= 0)
+ goto cv_estimate;
- t_predicted_cc = div_s64((s64)full_soc * act_cap_uah, 100);
- t_predicted_cc = div_s64(t_predicted_cc * (soc_cc2cv - msoc), 100);
- t_predicted_cc *= HOURS_TO_SECONDS;
- t_predicted_cc = div_s64(t_predicted_cc, (ibatt_avg + i_cc2cv) / 2);
+ divisor = max(100, (ibatt_avg + i_cc2cv) / 2 * 100);
+ t_predicted = div_s64((s64)act_cap_mah * (soc_cc2cv - msoc) *
+ HOURS_TO_SECONDS, divisor);
+ break;
+ case TTF_MODE_QNOVO:
+ soc_per_step = 100 / MAX_CC_STEPS;
+ for (i = msoc / soc_per_step; i < MAX_CC_STEPS - 1; ++i) {
+ msoc_next_step = (i + 1) * soc_per_step;
+ if (i == msoc / soc_per_step)
+ msoc_this_step = msoc;
+ else
+ msoc_this_step = i * soc_per_step;
-skip_cc_estimate:
- fg_dbg(chip, FG_TTF, "t_predicted_cc=%lld\n", t_predicted_cc);
+ /* scale ibatt by 85% to account for discharge pulses */
+ ibatt_this_step = min(
+ chip->ttf.cc_step.arr[i] / MILLI_UNIT,
+ ibatt_avg) * 85 / 100;
+ divisor = max(100, ibatt_this_step * 100);
+ t_predicted_this_step = div_s64((s64)act_cap_mah *
+ (msoc_next_step - msoc_this_step) *
+ HOURS_TO_SECONDS, divisor);
+ t_predicted += t_predicted_this_step;
+ fg_dbg(chip, FG_TTF, "[%d, %d] ma=%d t=%d\n",
+ msoc_this_step, msoc_next_step,
+ ibatt_this_step, t_predicted_this_step);
+ }
+ break;
+ default:
+ pr_err("TTF mode %d is not supported\n", chip->ttf.mode);
+ break;
+ }
- /* CV estimate starts here */
- if (chip->charge_type >= POWER_SUPPLY_CHARGE_TYPE_TAPER)
- ln_val = ibatt_avg / (abs(chip->dt.sys_term_curr_ma) + 200);
+cv_estimate:
+ fg_dbg(chip, FG_TTF, "t_predicted_cc=%d\n", t_predicted);
+
+ iterm = max(100, abs(chip->dt.sys_term_curr_ma) + 200);
+ fg_dbg(chip, FG_TTF, "iterm=%d\n", iterm);
+
+ if (chip->charge_type == POWER_SUPPLY_CHARGE_TYPE_TAPER)
+ tau = max(MILLI_UNIT, ibatt_avg * MILLI_UNIT / iterm);
else
- ln_val = i_cc2cv / (abs(chip->dt.sys_term_curr_ma) + 200);
+ tau = max(MILLI_UNIT, i_cc2cv * MILLI_UNIT / iterm);
- if (msoc < 95)
- centi_tau_scale = 100;
- else
- centi_tau_scale = 20 * (100 - msoc);
+ rc = fg_lerp(fg_ln_table, ARRAY_SIZE(fg_ln_table), tau, &tau);
+ if (rc < 0) {
+ pr_err("failed to interpolate tau rc=%d\n", rc);
+ return rc;
+ }
- fg_dbg(chip, FG_TTF, "ln_in=%d\n", ln_val);
- rc = fg_lerp(fg_ln_table, ARRAY_SIZE(fg_ln_table), ln_val, &ln_val);
- fg_dbg(chip, FG_TTF, "ln_out=%d\n", ln_val);
- t_predicted_cv = div_s64((s64)act_cap_uah * rbatt, MICRO_UNIT);
- t_predicted_cv = div_s64(t_predicted_cv * centi_tau_scale, 100);
- t_predicted_cv = div_s64(t_predicted_cv * ln_val, MILLI_UNIT);
- t_predicted_cv = div_s64(t_predicted_cv * HOURS_TO_SECONDS, MICRO_UNIT);
- fg_dbg(chip, FG_TTF, "t_predicted_cv=%lld\n", t_predicted_cv);
- *val = t_predicted_cc + t_predicted_cv;
+ /* tau is scaled linearly from 95% to 100% SOC */
+ if (msoc >= 95)
+ tau = tau * 2 * (100 - msoc) / 10;
+
+ fg_dbg(chip, FG_TTF, "tau=%d\n", tau);
+ t_predicted_cv = div_s64((s64)act_cap_mah * rbatt * tau *
+ HOURS_TO_SECONDS, NANO_UNIT);
+ fg_dbg(chip, FG_TTF, "t_predicted_cv=%d\n", t_predicted_cv);
+ t_predicted += t_predicted_cv;
+
+ fg_dbg(chip, FG_TTF, "t_predicted_prefilter=%d\n", t_predicted);
+ if (chip->ttf.last_ms != 0) {
+ delta_ms = ktime_ms_delta(ktime_get_boottime(),
+ ms_to_ktime(chip->ttf.last_ms));
+ if (delta_ms > 10000) {
+ ttf_slope = div64_s64(
+ (s64)(t_predicted - chip->ttf.last_ttf) *
+ MICRO_UNIT, delta_ms);
+ if (ttf_slope > -100)
+ ttf_slope = -100;
+ else if (ttf_slope < -2000)
+ ttf_slope = -2000;
+
+ t_predicted = div_s64(
+ (s64)ttf_slope * delta_ms, MICRO_UNIT) +
+ chip->ttf.last_ttf;
+ fg_dbg(chip, FG_TTF, "ttf_slope=%d\n", ttf_slope);
+ } else {
+ t_predicted = chip->ttf.last_ttf;
+ }
+ }
+
+ /* clamp the ttf to 0 */
+ if (t_predicted < 0)
+ t_predicted = 0;
+
+ fg_dbg(chip, FG_TTF, "t_predicted_postfilter=%d\n", t_predicted);
+ *val = t_predicted;
return 0;
}
+static int fg_get_time_to_full(struct fg_chip *chip, int *val)
+{
+ int rc;
+
+ mutex_lock(&chip->ttf.lock);
+ rc = fg_get_time_to_full_locked(chip, val);
+ mutex_unlock(&chip->ttf.lock);
+ return rc;
+}
+
#define CENTI_ICORRECT_C0 105
#define CENTI_ICORRECT_C1 20
static int fg_get_time_to_empty(struct fg_chip *chip, int *val)
{
- int rc, ibatt_avg, msoc, act_cap_uah;
- s32 divisor;
- s64 t_predicted;
+ int rc, ibatt_avg, msoc, full_soc, act_cap_mah, divisor;
- rc = fg_circ_buf_avg(&chip->ibatt_circ_buf, &ibatt_avg);
+ rc = fg_circ_buf_median(&chip->ttf.ibatt, &ibatt_avg);
if (rc < 0) {
/* try to get instantaneous current */
rc = fg_get_battery_current(chip, &ibatt_avg);
@@ -2929,16 +3056,10 @@
}
}
- /* clamp ibatt_avg to 150mA */
- if (ibatt_avg < 150000)
- ibatt_avg = 150000;
-
- rc = fg_get_sram_prop(chip, FG_SRAM_ACT_BATT_CAP, &act_cap_uah);
- if (rc < 0) {
- pr_err("Error in getting ACT_BATT_CAP, rc=%d\n", rc);
- return rc;
- }
- act_cap_uah *= MILLI_UNIT;
+ ibatt_avg /= MILLI_UNIT;
+ /* clamp ibatt_avg to 100mA */
+ if (ibatt_avg < 100)
+ ibatt_avg = 100;
rc = fg_get_prop_capacity(chip, &msoc);
if (rc < 0) {
@@ -2946,14 +3067,25 @@
return rc;
}
- t_predicted = div_s64((s64)msoc * act_cap_uah, 100);
- t_predicted *= HOURS_TO_SECONDS;
- divisor = CENTI_ICORRECT_C0 * 100 + CENTI_ICORRECT_C1 * msoc;
- divisor = div_s64((s64)divisor * ibatt_avg, 10000);
- if (divisor > 0)
- t_predicted = div_s64(t_predicted, divisor);
+ rc = fg_get_sram_prop(chip, FG_SRAM_ACT_BATT_CAP, &act_cap_mah);
+ if (rc < 0) {
+ pr_err("Error in getting ACT_BATT_CAP, rc=%d\n", rc);
+ return rc;
+ }
- *val = t_predicted;
+ rc = fg_get_sram_prop(chip, FG_SRAM_FULL_SOC, &full_soc);
+ if (rc < 0) {
+ pr_err("failed to get full soc rc=%d\n", rc);
+ return rc;
+ }
+ full_soc = DIV_ROUND_CLOSEST(((u16)full_soc >> 8) * FULL_CAPACITY,
+ FULL_SOC_RAW);
+ act_cap_mah = full_soc * act_cap_mah / 100;
+
+ divisor = CENTI_ICORRECT_C0 * 100 + CENTI_ICORRECT_C1 * msoc;
+ divisor = ibatt_avg * divisor / 100;
+ divisor = max(100, divisor);
+ *val = act_cap_mah * msoc * HOURS_TO_SECONDS / divisor;
return 0;
}
@@ -3032,6 +3164,150 @@
return 0;
}
+static int fg_force_esr_meas(struct fg_chip *chip)
+{
+ int rc;
+ int esr_uohms;
+
+ /* force esr extraction enable */
+ rc = fg_sram_masked_write(chip, ESR_EXTRACTION_ENABLE_WORD,
+ ESR_EXTRACTION_ENABLE_OFFSET, BIT(0), BIT(0),
+ FG_IMA_DEFAULT);
+ if (rc < 0) {
+ pr_err("failed to enable esr extn rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = fg_masked_write(chip, BATT_INFO_QNOVO_CFG(chip),
+ LD_REG_CTRL_BIT, 0);
+ if (rc < 0) {
+ pr_err("Error in configuring qnovo_cfg rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = fg_masked_write(chip, BATT_INFO_TM_MISC1(chip),
+ ESR_REQ_CTL_BIT | ESR_REQ_CTL_EN_BIT,
+ ESR_REQ_CTL_BIT | ESR_REQ_CTL_EN_BIT);
+ if (rc < 0) {
+ pr_err("Error in configuring force ESR rc=%d\n", rc);
+ return rc;
+ }
+
+ /* wait 1.5 seconds for hw to measure ESR */
+ msleep(1500);
+ rc = fg_masked_write(chip, BATT_INFO_TM_MISC1(chip),
+ ESR_REQ_CTL_BIT | ESR_REQ_CTL_EN_BIT,
+ 0);
+ if (rc < 0) {
+ pr_err("Error in restoring force ESR rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = fg_masked_write(chip, BATT_INFO_QNOVO_CFG(chip),
+ LD_REG_CTRL_BIT, LD_REG_CTRL_BIT);
+ if (rc < 0) {
+ pr_err("Error in restoring qnovo_cfg rc=%d\n", rc);
+ return rc;
+ }
+
+ /* force esr extraction disable */
+ rc = fg_sram_masked_write(chip, ESR_EXTRACTION_ENABLE_WORD,
+ ESR_EXTRACTION_ENABLE_OFFSET, BIT(0), 0,
+ FG_IMA_DEFAULT);
+ if (rc < 0) {
+ pr_err("failed to disable esr extn rc=%d\n", rc);
+ return rc;
+ }
+
+ fg_get_battery_resistance(chip, &esr_uohms);
+ fg_dbg(chip, FG_STATUS, "ESR uohms = %d\n", esr_uohms);
+
+ return rc;
+}
+
+static int fg_prepare_for_qnovo(struct fg_chip *chip, int qnovo_enable)
+{
+ int rc;
+
+ /* force esr extraction disable when qnovo enables */
+ rc = fg_sram_masked_write(chip, ESR_EXTRACTION_ENABLE_WORD,
+ ESR_EXTRACTION_ENABLE_OFFSET,
+ BIT(0), qnovo_enable ? 0 : BIT(0),
+ FG_IMA_DEFAULT);
+ if (rc < 0)
+ pr_err("Error in configuring esr extraction rc=%d\n", rc);
+
+ rc = fg_masked_write(chip, BATT_INFO_QNOVO_CFG(chip),
+ LD_REG_CTRL_BIT,
+ qnovo_enable ? LD_REG_CTRL_BIT : 0);
+ if (rc < 0) {
+ pr_err("Error in configuring qnovo_cfg rc=%d\n", rc);
+ return rc;
+ }
+ fg_dbg(chip, FG_STATUS, "Prepared for Qnovo\n");
+ return 0;
+}
+
+static void ttf_work(struct work_struct *work)
+{
+ struct fg_chip *chip = container_of(work, struct fg_chip,
+ ttf_work.work);
+ int rc, ibatt_now, vbatt_now, ttf;
+ ktime_t ktime_now;
+
+ mutex_lock(&chip->ttf.lock);
+ if (chip->charge_status != POWER_SUPPLY_STATUS_CHARGING &&
+ chip->charge_status != POWER_SUPPLY_STATUS_DISCHARGING)
+ goto end_work;
+
+ rc = fg_get_battery_current(chip, &ibatt_now);
+ if (rc < 0) {
+ pr_err("failed to get battery current, rc=%d\n", rc);
+ goto end_work;
+ }
+
+ rc = fg_get_battery_voltage(chip, &vbatt_now);
+ if (rc < 0) {
+ pr_err("failed to get battery voltage, rc=%d\n", rc);
+ goto end_work;
+ }
+
+ fg_circ_buf_add(&chip->ttf.ibatt, ibatt_now);
+ fg_circ_buf_add(&chip->ttf.vbatt, vbatt_now);
+
+ if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) {
+ rc = fg_get_time_to_full_locked(chip, &ttf);
+ if (rc < 0) {
+ pr_err("failed to get ttf, rc=%d\n", rc);
+ goto end_work;
+ }
+
+ /* keep the wake lock and prime the IBATT and VBATT buffers */
+ if (ttf < 0) {
+ /* delay for one FG cycle */
+ schedule_delayed_work(&chip->ttf_work,
+ msecs_to_jiffies(1500));
+ mutex_unlock(&chip->ttf.lock);
+ return;
+ }
+
+ /* update the TTF reference point every minute */
+ ktime_now = ktime_get_boottime();
+ if (ktime_ms_delta(ktime_now,
+ ms_to_ktime(chip->ttf.last_ms)) > 60000 ||
+ chip->ttf.last_ms == 0) {
+ chip->ttf.last_ttf = ttf;
+ chip->ttf.last_ms = ktime_to_ms(ktime_now);
+ }
+ }
+
+ /* recurse every 10 seconds */
+ schedule_delayed_work(&chip->ttf_work, msecs_to_jiffies(10000));
+end_work:
+ vote(chip->awake_votable, TTF_PRIMING, false, 0);
+ mutex_unlock(&chip->ttf.lock);
+}
+
/* PSY CALLBACKS STAY HERE */
static int fg_psy_get_property(struct power_supply *psy,
@@ -3108,6 +3384,20 @@
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
rc = fg_get_sram_prop(chip, FG_SRAM_VBATT_FULL, &pval->intval);
break;
+ case POWER_SUPPLY_PROP_CC_STEP:
+ if ((chip->ttf.cc_step.sel >= 0) &&
+ (chip->ttf.cc_step.sel < MAX_CC_STEPS)) {
+ pval->intval =
+ chip->ttf.cc_step.arr[chip->ttf.cc_step.sel];
+ } else {
+ pr_err("cc_step_sel is out of bounds [0, %d]\n",
+ chip->ttf.cc_step.sel);
+ return -EINVAL;
+ }
+ break;
+ case POWER_SUPPLY_PROP_CC_STEP_SEL:
+ pval->intval = chip->ttf.cc_step.sel;
+ break;
default:
pr_err("unsupported property %d\n", psp);
rc = -EINVAL;
@@ -3140,6 +3430,32 @@
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
rc = fg_set_constant_chg_voltage(chip, pval->intval);
break;
+ case POWER_SUPPLY_PROP_RESISTANCE:
+ rc = fg_force_esr_meas(chip);
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_QNOVO_ENABLE:
+ rc = fg_prepare_for_qnovo(chip, pval->intval);
+ break;
+ case POWER_SUPPLY_PROP_CC_STEP:
+ if ((chip->ttf.cc_step.sel >= 0) &&
+ (chip->ttf.cc_step.sel < MAX_CC_STEPS)) {
+ chip->ttf.cc_step.arr[chip->ttf.cc_step.sel] =
+ pval->intval;
+ } else {
+ pr_err("cc_step_sel is out of bounds [0, %d]\n",
+ chip->ttf.cc_step.sel);
+ return -EINVAL;
+ }
+ break;
+ case POWER_SUPPLY_PROP_CC_STEP_SEL:
+ if ((pval->intval >= 0) && (pval->intval < MAX_CC_STEPS)) {
+ chip->ttf.cc_step.sel = pval->intval;
+ } else {
+ pr_err("cc_step_sel is out of bounds [0, %d]\n",
+ pval->intval);
+ return -EINVAL;
+ }
+ break;
default:
break;
}
@@ -3153,6 +3469,8 @@
switch (psp) {
case POWER_SUPPLY_PROP_CYCLE_COUNT_ID:
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+ case POWER_SUPPLY_PROP_CC_STEP:
+ case POWER_SUPPLY_PROP_CC_STEP_SEL:
return 1;
default:
break;
@@ -3213,6 +3531,8 @@
POWER_SUPPLY_PROP_SOC_REPORTING_READY,
POWER_SUPPLY_PROP_DEBUG_BATTERY,
POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
+ POWER_SUPPLY_PROP_CC_STEP,
+ POWER_SUPPLY_PROP_CC_STEP_SEL,
};
static const struct power_supply_desc fg_psy_desc = {
@@ -3423,8 +3743,7 @@
return rc;
}
- if (chip->cyc_ctr.en)
- restore_cycle_counter(chip);
+ restore_cycle_counter(chip);
if (chip->dt.jeita_hyst_temp >= 0) {
val = chip->dt.jeita_hyst_temp << JEITA_TEMP_HYST_SHIFT;
@@ -3503,6 +3822,9 @@
static int fg_memif_init(struct fg_chip *chip)
{
+ if (chip->use_dma)
+ return fg_dma_init(chip);
+
return fg_ima_init(chip);
}
@@ -3542,6 +3864,26 @@
/* INTERRUPT HANDLERS STAY HERE */
+static irqreturn_t fg_dma_grant_irq_handler(int irq, void *data)
+{
+ struct fg_chip *chip = data;
+ u8 status;
+ int rc;
+
+ rc = fg_read(chip, MEM_IF_INT_RT_STS(chip), &status, 1);
+ if (rc < 0) {
+ pr_err("failed to read addr=0x%04x, rc=%d\n",
+ MEM_IF_INT_RT_STS(chip), rc);
+ return IRQ_HANDLED;
+ }
+
+ fg_dbg(chip, FG_IRQ, "irq %d triggered, status:%d\n", irq, status);
+ if (status & MEM_GNT_BIT)
+ complete_all(&chip->mem_grant);
+
+ return IRQ_HANDLED;
+}
+
static irqreturn_t fg_mem_xcp_irq_handler(int irq, void *data)
{
struct fg_chip *chip = data;
@@ -3698,8 +4040,7 @@
int rc;
fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
- if (chip->cyc_ctr.en)
- schedule_work(&chip->cycle_count_work);
+ fg_cycle_counter_update(chip);
if (chip->cl.active)
fg_cap_learning_update(chip);
@@ -3822,7 +4163,8 @@
/* MEM_IF irqs */
[DMA_GRANT_IRQ] = {
.name = "dma-grant",
- .handler = fg_dummy_irq_handler,
+ .handler = fg_dma_grant_irq_handler,
+ .wakeable = true,
},
[MEM_XCP_IRQ] = {
.name = "mem-xcp",
@@ -4011,6 +4353,7 @@
#define DEFAULT_ESR_CLAMP_MOHMS 20
#define DEFAULT_ESR_PULSE_THRESH_MA 110
#define DEFAULT_ESR_MEAS_CURR_MA 120
+#define DEFAULT_BMD_EN_DELAY_MS 200
static int fg_parse_dt(struct fg_chip *chip)
{
struct device_node *child, *revid_node, *node = chip->dev->of_node;
@@ -4046,6 +4389,7 @@
switch (chip->pmic_rev_id->pmic_subtype) {
case PMI8998_SUBTYPE:
+ chip->use_dma = true;
if (chip->pmic_rev_id->rev4 < PMI8998_V2P0_REV4) {
chip->sp = pmi8998_v1_sram_params;
chip->alg_flags = pmi8998_v1_alg_flags;
@@ -4356,6 +4700,13 @@
chip->dt.esr_meas_curr_ma = temp;
}
+ chip->dt.bmd_en_delay_ms = DEFAULT_BMD_EN_DELAY_MS;
+ rc = of_property_read_u32(node, "qcom,fg-bmd-en-delay-ms", &temp);
+ if (!rc) {
+ if (temp > DEFAULT_BMD_EN_DELAY_MS)
+ chip->dt.bmd_en_delay_ms = temp;
+ }
+
return 0;
}
@@ -4394,6 +4745,7 @@
chip->charge_status = -EINVAL;
chip->prev_charge_status = -EINVAL;
chip->ki_coeff_full_soc = -EINVAL;
+ chip->online_status = -EINVAL;
chip->regmap = dev_get_regmap(chip->dev->parent, NULL);
if (!chip->regmap) {
dev_err(chip->dev, "Parent regmap is unavailable\n");
@@ -4462,14 +4814,14 @@
mutex_init(&chip->sram_rw_lock);
mutex_init(&chip->cyc_ctr.lock);
mutex_init(&chip->cl.lock);
- mutex_init(&chip->batt_avg_lock);
+ mutex_init(&chip->ttf.lock);
mutex_init(&chip->charge_full_lock);
init_completion(&chip->soc_update);
init_completion(&chip->soc_ready);
+ init_completion(&chip->mem_grant);
INIT_DELAYED_WORK(&chip->profile_load_work, profile_load_work);
INIT_WORK(&chip->status_change_work, status_change_work);
- INIT_WORK(&chip->cycle_count_work, cycle_count_work);
- INIT_DELAYED_WORK(&chip->batt_avg_work, batt_avg_work);
+ INIT_DELAYED_WORK(&chip->ttf_work, ttf_work);
INIT_DELAYED_WORK(&chip->sram_dump_work, sram_dump_work);
rc = fg_memif_init(chip);
@@ -4479,6 +4831,25 @@
goto exit;
}
+ platform_set_drvdata(pdev, chip);
+
+ rc = fg_register_interrupts(chip);
+ if (rc < 0) {
+ dev_err(chip->dev, "Error in registering interrupts, rc:%d\n",
+ rc);
+ goto exit;
+ }
+
+ /* Keep SOC_UPDATE irq disabled until we require it */
+ if (fg_irqs[SOC_UPDATE_IRQ].irq)
+ disable_irq_nosync(fg_irqs[SOC_UPDATE_IRQ].irq);
+
+ /* Keep BSOC_DELTA_IRQ disabled until we require it */
+ vote(chip->delta_bsoc_irq_en_votable, DELTA_BSOC_IRQ_VOTER, false, 0);
+
+ /* Keep BATT_MISSING_IRQ disabled until we require it */
+ vote(chip->batt_miss_irq_en_votable, BATT_MISS_IRQ_VOTER, false, 0);
+
rc = fg_hw_init(chip);
if (rc < 0) {
dev_err(chip->dev, "Error in initializing FG hardware, rc:%d\n",
@@ -4486,8 +4857,6 @@
goto exit;
}
- platform_set_drvdata(pdev, chip);
-
/* Register the power supply */
fg_psy_cfg.drv_data = chip;
fg_psy_cfg.of_node = NULL;
@@ -4508,23 +4877,6 @@
goto exit;
}
- rc = fg_register_interrupts(chip);
- if (rc < 0) {
- dev_err(chip->dev, "Error in registering interrupts, rc:%d\n",
- rc);
- goto exit;
- }
-
- /* Keep SOC_UPDATE_IRQ disabled until we require it */
- if (fg_irqs[SOC_UPDATE_IRQ].irq)
- disable_irq_nosync(fg_irqs[SOC_UPDATE_IRQ].irq);
-
- /* Keep BSOC_DELTA_IRQ disabled until we require it */
- vote(chip->delta_bsoc_irq_en_votable, DELTA_BSOC_IRQ_VOTER, false, 0);
-
- /* Keep BATT_MISSING_IRQ disabled until we require it */
- vote(chip->batt_miss_irq_en_votable, BATT_MISS_IRQ_VOTER, false, 0);
-
rc = fg_debugfs_create(chip);
if (rc < 0) {
dev_err(chip->dev, "Error in creating debugfs entries, rc:%d\n",
@@ -4566,7 +4918,7 @@
if (rc < 0)
pr_err("Error in configuring ESR timer, rc=%d\n", rc);
- cancel_delayed_work_sync(&chip->batt_avg_work);
+ cancel_delayed_work_sync(&chip->ttf_work);
if (fg_sram_dump)
cancel_delayed_work_sync(&chip->sram_dump_work);
return 0;
@@ -4581,9 +4933,7 @@
if (rc < 0)
pr_err("Error in configuring ESR timer, rc=%d\n", rc);
- fg_circ_buf_clr(&chip->ibatt_circ_buf);
- fg_circ_buf_clr(&chip->vbatt_circ_buf);
- schedule_delayed_work(&chip->batt_avg_work, 0);
+ schedule_delayed_work(&chip->ttf_work, 0);
if (fg_sram_dump)
schedule_delayed_work(&chip->sram_dump_work,
msecs_to_jiffies(fg_sram_dump_period_ms));
diff --git a/drivers/power/supply/qcom/qpnp-qnovo.c b/drivers/power/supply/qcom/qpnp-qnovo.c
index eb97eb0..cf90f90 100644
--- a/drivers/power/supply/qcom/qpnp-qnovo.c
+++ b/drivers/power/supply/qcom/qpnp-qnovo.c
@@ -20,6 +20,7 @@
#include <linux/of_irq.h>
#include <linux/qpnp/qpnp-revid.h>
#include <linux/pmic-voter.h>
+#include <linux/delay.h>
#define QNOVO_REVISION1 0x00
#define QNOVO_REVISION2 0x01
@@ -114,6 +115,17 @@
#define OK_TO_QNOVO_VOTER "ok_to_qnovo_voter"
#define QNOVO_VOTER "qnovo_voter"
+#define FG_AVAILABLE_VOTER "FG_AVAILABLE_VOTER"
+#define QNOVO_OVERALL_VOTER "QNOVO_OVERALL_VOTER"
+#define QNI_PT_VOTER "QNI_PT_VOTER"
+#define ESR_VOTER "ESR_VOTER"
+
+#define HW_OK_TO_QNOVO_VOTER "HW_OK_TO_QNOVO_VOTER"
+#define CHG_READY_VOTER "CHG_READY_VOTER"
+#define USB_READY_VOTER "USB_READY_VOTER"
+#define DC_READY_VOTER "DC_READY_VOTER"
+
+#define PT_RESTART_VOTER "PT_RESTART_VOTER"
struct qnovo_dt_props {
bool external_rsense;
@@ -127,6 +139,10 @@
struct qnovo_dt_props dt;
struct device *dev;
struct votable *disable_votable;
+ struct votable *pt_dis_votable;
+ struct votable *not_ok_to_qnovo_votable;
+ struct votable *chg_ready_votable;
+ struct votable *awake_votable;
struct class qnovo_class;
struct pmic_revid_data *pmic_rev_id;
u32 wa_flags;
@@ -138,10 +154,18 @@
s64 v_gain_mega;
struct notifier_block nb;
struct power_supply *batt_psy;
+ struct power_supply *bms_psy;
+ struct power_supply *usb_psy;
+ struct power_supply *dc_psy;
struct work_struct status_change_work;
int fv_uV_request;
int fcc_uA_request;
- bool ok_to_qnovo;
+ int usb_present;
+ int dc_present;
+ struct delayed_work usb_debounce_work;
+ struct delayed_work dc_debounce_work;
+
+ struct delayed_work ptrain_restart_work;
};
static int debug_mask;
@@ -229,6 +253,39 @@
return true;
}
+static bool is_fg_available(struct qnovo *chip)
+{
+ if (!chip->bms_psy)
+ chip->bms_psy = power_supply_get_by_name("bms");
+
+ if (!chip->bms_psy)
+ return false;
+
+ return true;
+}
+
+static bool is_usb_available(struct qnovo *chip)
+{
+ if (!chip->usb_psy)
+ chip->usb_psy = power_supply_get_by_name("usb");
+
+ if (!chip->usb_psy)
+ return false;
+
+ return true;
+}
+
+static bool is_dc_available(struct qnovo *chip)
+{
+ if (!chip->dc_psy)
+ chip->dc_psy = power_supply_get_by_name("dc");
+
+ if (!chip->dc_psy)
+ return false;
+
+ return true;
+}
+
static int qnovo_batt_psy_update(struct qnovo *chip, bool disable)
{
union power_supply_propval pval = {0};
@@ -281,10 +338,86 @@
return -EINVAL;
}
+ /*
+ * fg must be available for enable FG_AVAILABLE_VOTER
+ * won't enable it otherwise
+ */
+
+ if (is_fg_available(chip))
+ power_supply_set_property(chip->bms_psy,
+ POWER_SUPPLY_PROP_CHARGE_QNOVO_ENABLE,
+ &pval);
+
+ vote(chip->pt_dis_votable, QNOVO_OVERALL_VOTER, disable, 0);
rc = qnovo_batt_psy_update(chip, disable);
return rc;
}
+static int pt_dis_votable_cb(struct votable *votable, void *data, int disable,
+ const char *client)
+{
+ struct qnovo *chip = data;
+ int rc;
+
+ if (disable) {
+ cancel_delayed_work_sync(&chip->ptrain_restart_work);
+ vote(chip->awake_votable, PT_RESTART_VOTER, false, 0);
+ }
+
+ rc = qnovo_masked_write(chip, QNOVO_PTRAIN_EN, QNOVO_PTRAIN_EN_BIT,
+ (bool)disable ? 0 : QNOVO_PTRAIN_EN_BIT);
+ if (rc < 0) {
+ dev_err(chip->dev, "Couldn't %s pulse train rc=%d\n",
+ (bool)disable ? "disable" : "enable", rc);
+ return rc;
+ }
+
+ if (!disable) {
+ vote(chip->awake_votable, PT_RESTART_VOTER, true, 0);
+ schedule_delayed_work(&chip->ptrain_restart_work,
+ msecs_to_jiffies(20));
+ }
+
+ return 0;
+}
+
+static int not_ok_to_qnovo_cb(struct votable *votable, void *data,
+ int not_ok_to_qnovo,
+ const char *client)
+{
+ struct qnovo *chip = data;
+
+ vote(chip->disable_votable, OK_TO_QNOVO_VOTER, not_ok_to_qnovo, 0);
+ if (not_ok_to_qnovo)
+ vote(chip->disable_votable, USER_VOTER, true, 0);
+
+ kobject_uevent(&chip->dev->kobj, KOBJ_CHANGE);
+ return 0;
+}
+
+static int chg_ready_cb(struct votable *votable, void *data, int ready,
+ const char *client)
+{
+ struct qnovo *chip = data;
+
+ vote(chip->not_ok_to_qnovo_votable, CHG_READY_VOTER, !ready, 0);
+
+ return 0;
+}
+
+static int awake_cb(struct votable *votable, void *data, int awake,
+ const char *client)
+{
+ struct qnovo *chip = data;
+
+ if (awake)
+ pm_stay_awake(chip->dev);
+ else
+ pm_relax(chip->dev);
+
+ return 0;
+}
+
static int qnovo_parse_dt(struct qnovo *chip)
{
struct device_node *node = chip->dev->of_node;
@@ -626,8 +759,9 @@
char *buf)
{
struct qnovo *chip = container_of(c, struct qnovo, qnovo_class);
+ int val = get_effective_result(chip->not_ok_to_qnovo_votable);
- return snprintf(buf, PAGE_SIZE, "%d\n", chip->ok_to_qnovo);
+ return snprintf(buf, PAGE_SIZE, "%d\n", !val);
}
static ssize_t qnovo_enable_show(struct class *c, struct class_attribute *attr,
@@ -656,21 +790,10 @@
static ssize_t pt_enable_show(struct class *c, struct class_attribute *attr,
char *ubuf)
{
- int i = attr - qnovo_attributes;
struct qnovo *chip = container_of(c, struct qnovo, qnovo_class);
- u8 buf[2] = {0, 0};
- u16 regval;
- int rc;
+ int val = get_effective_result(chip->pt_dis_votable);
- rc = qnovo_read(chip, params[i].start_addr, buf, params[i].num_regs);
- if (rc < 0) {
- pr_err("Couldn't read %s rc = %d\n", params[i].name, rc);
- return -EINVAL;
- }
- regval = buf[1] << 8 | buf[0];
-
- return snprintf(ubuf, PAGE_SIZE, "%d\n",
- (int)(regval & QNOVO_PTRAIN_EN_BIT));
+ return snprintf(ubuf, PAGE_SIZE, "%d\n", !val);
}
static ssize_t pt_enable_store(struct class *c, struct class_attribute *attr,
@@ -678,21 +801,12 @@
{
struct qnovo *chip = container_of(c, struct qnovo, qnovo_class);
unsigned long val;
- int rc = 0;
-
- if (get_effective_result(chip->disable_votable))
- return -EINVAL;
if (kstrtoul(ubuf, 0, &val))
return -EINVAL;
- rc = qnovo_masked_write(chip, QNOVO_PTRAIN_EN, QNOVO_PTRAIN_EN_BIT,
- (bool)val ? QNOVO_PTRAIN_EN_BIT : 0);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't %s pulse train rc=%d\n",
- (bool)val ? "enable" : "disable", rc);
- return rc;
- }
+ /* val being 0, userspace wishes to disable pt so vote true */
+ vote(chip->pt_dis_votable, QNI_PT_VOTER, val ? false : true, 0);
return count;
}
@@ -1116,41 +1230,146 @@
{
u8 val = 0;
int rc;
- bool ok_to_qnovo;
- bool changed = false;
+ bool hw_ok_to_qnovo;
rc = qnovo_read(chip, QNOVO_ERROR_STS2, &val, 1);
if (rc < 0) {
pr_err("Couldn't read error sts rc = %d\n", rc);
- ok_to_qnovo = false;
+ hw_ok_to_qnovo = false;
} else {
/*
* For CV mode keep qnovo enabled, userspace is expected to
* disable it after few runs
*/
- ok_to_qnovo = (val == ERR_CV_MODE || val == 0) ? true : false;
+ hw_ok_to_qnovo = (val == ERR_CV_MODE || val == 0) ?
+ true : false;
}
- if (chip->ok_to_qnovo ^ ok_to_qnovo) {
-
- vote(chip->disable_votable, OK_TO_QNOVO_VOTER, !ok_to_qnovo, 0);
- if (!ok_to_qnovo)
- vote(chip->disable_votable, USER_VOTER, true, 0);
-
- chip->ok_to_qnovo = ok_to_qnovo;
- changed = true;
- }
-
- return changed;
+ vote(chip->not_ok_to_qnovo_votable, HW_OK_TO_QNOVO_VOTER,
+ !hw_ok_to_qnovo, 0);
+ return 0;
}
+static void usb_debounce_work(struct work_struct *work)
+{
+ struct qnovo *chip = container_of(work,
+ struct qnovo, usb_debounce_work.work);
+
+ vote(chip->chg_ready_votable, USB_READY_VOTER, true, 0);
+ vote(chip->awake_votable, USB_READY_VOTER, false, 0);
+}
+
+static void dc_debounce_work(struct work_struct *work)
+{
+ struct qnovo *chip = container_of(work,
+ struct qnovo, dc_debounce_work.work);
+
+ vote(chip->chg_ready_votable, DC_READY_VOTER, true, 0);
+ vote(chip->awake_votable, DC_READY_VOTER, false, 0);
+}
+
+#define DEBOUNCE_MS 15000 /* 15 seconds */
static void status_change_work(struct work_struct *work)
{
struct qnovo *chip = container_of(work,
struct qnovo, status_change_work);
+ union power_supply_propval pval;
+ bool usb_present = false, dc_present = false;
+ int rc;
- if (qnovo_update_status(chip))
- kobject_uevent(&chip->dev->kobj, KOBJ_CHANGE);
+ if (is_fg_available(chip))
+ vote(chip->disable_votable, FG_AVAILABLE_VOTER, false, 0);
+
+ if (is_usb_available(chip)) {
+ rc = power_supply_get_property(chip->usb_psy,
+ POWER_SUPPLY_PROP_PRESENT, &pval);
+ usb_present = (rc < 0) ? 0 : pval.intval;
+ }
+
+ if (chip->usb_present && !usb_present) {
+ /* removal */
+ chip->usb_present = 0;
+ cancel_delayed_work_sync(&chip->usb_debounce_work);
+ vote(chip->awake_votable, USB_READY_VOTER, false, 0);
+ vote(chip->chg_ready_votable, USB_READY_VOTER, false, 0);
+ } else if (!chip->usb_present && usb_present) {
+ /* insertion */
+ chip->usb_present = 1;
+ vote(chip->awake_votable, USB_READY_VOTER, true, 0);
+ schedule_delayed_work(&chip->usb_debounce_work,
+ msecs_to_jiffies(DEBOUNCE_MS));
+ }
+
+ if (is_dc_available(chip)) {
+ rc = power_supply_get_property(chip->dc_psy,
+ POWER_SUPPLY_PROP_PRESENT,
+ &pval);
+ dc_present = (rc < 0) ? 0 : pval.intval;
+ }
+
+ if (usb_present)
+ dc_present = 0;
+
+ if (chip->dc_present && !dc_present) {
+ /* removal */
+ chip->dc_present = 0;
+ cancel_delayed_work_sync(&chip->dc_debounce_work);
+ vote(chip->awake_votable, DC_READY_VOTER, false, 0);
+ vote(chip->chg_ready_votable, DC_READY_VOTER, false, 0);
+ } else if (!chip->dc_present && dc_present) {
+ /* insertion */
+ chip->dc_present = 1;
+ vote(chip->awake_votable, DC_READY_VOTER, true, 0);
+ schedule_delayed_work(&chip->dc_debounce_work,
+ msecs_to_jiffies(DEBOUNCE_MS));
+ }
+
+ qnovo_update_status(chip);
+}
+
+static void ptrain_restart_work(struct work_struct *work)
+{
+ struct qnovo *chip = container_of(work,
+ struct qnovo, ptrain_restart_work.work);
+ u8 pt_t1, pt_t2;
+ int rc;
+
+ rc = qnovo_read(chip, QNOVO_PTTIME_STS, &pt_t1, 1);
+ if (rc < 0) {
+ dev_err(chip->dev, "Couldn't read QNOVO_PTTIME_STS rc = %d\n",
+ rc);
+ goto clean_up;
+ }
+
+ /* pttime increments every 2 seconds */
+ msleep(2100);
+
+ rc = qnovo_read(chip, QNOVO_PTTIME_STS, &pt_t2, 1);
+ if (rc < 0) {
+ dev_err(chip->dev, "Couldn't read QNOVO_PTTIME_STS rc = %d\n",
+ rc);
+ goto clean_up;
+ }
+
+ if (pt_t1 != pt_t2)
+ goto clean_up;
+
+ /* Toggle pt enable to restart pulse train */
+ rc = qnovo_masked_write(chip, QNOVO_PTRAIN_EN, QNOVO_PTRAIN_EN_BIT, 0);
+ if (rc < 0) {
+ dev_err(chip->dev, "Couldn't disable pulse train rc=%d\n", rc);
+ goto clean_up;
+ }
+ msleep(1000);
+ rc = qnovo_masked_write(chip, QNOVO_PTRAIN_EN, QNOVO_PTRAIN_EN_BIT,
+ QNOVO_PTRAIN_EN_BIT);
+ if (rc < 0) {
+ dev_err(chip->dev, "Couldn't enable pulse train rc=%d\n", rc);
+ goto clean_up;
+ }
+
+clean_up:
+ vote(chip->awake_votable, PT_RESTART_VOTER, false, 0);
}
static int qnovo_notifier_call(struct notifier_block *nb,
@@ -1162,7 +1381,10 @@
if (ev != PSY_EVENT_PROP_CHANGED)
return NOTIFY_OK;
- if (strcmp(psy->desc->name, "battery") == 0)
+ if (strcmp(psy->desc->name, "battery") == 0
+ || strcmp(psy->desc->name, "bms") == 0
+ || strcmp(psy->desc->name, "usb") == 0
+ || strcmp(psy->desc->name, "dc") == 0)
schedule_work(&chip->status_change_work);
return NOTIFY_OK;
@@ -1171,7 +1393,23 @@
static irqreturn_t handle_ptrain_done(int irq, void *data)
{
struct qnovo *chip = data;
+ union power_supply_propval pval = {0};
+ /*
+ * hw resets pt_en bit once ptrain_done triggers.
+ * vote on behalf of QNI to disable it such that
+ * once QNI enables it, the votable state changes
+ * and the callback that sets it is indeed invoked
+ */
+ vote(chip->pt_dis_votable, QNI_PT_VOTER, true, 0);
+
+ vote(chip->pt_dis_votable, ESR_VOTER, true, 0);
+ if (is_fg_available(chip))
+ power_supply_set_property(chip->bms_psy,
+ POWER_SUPPLY_PROP_RESISTANCE,
+ &pval);
+
+ vote(chip->pt_dis_votable, ESR_VOTER, false, 0);
qnovo_update_status(chip);
kobject_uevent(&chip->dev->kobj, KOBJ_CHANGE);
return IRQ_HANDLED;
@@ -1186,6 +1424,11 @@
u8 val;
vote(chip->disable_votable, USER_VOTER, true, 0);
+ vote(chip->disable_votable, FG_AVAILABLE_VOTER, true, 0);
+
+ vote(chip->pt_dis_votable, QNI_PT_VOTER, true, 0);
+ vote(chip->pt_dis_votable, QNOVO_OVERALL_VOTER, true, 0);
+ vote(chip->pt_dis_votable, ESR_VOTER, false, 0);
val = 0;
rc = qnovo_write(chip, QNOVO_STRM_CTRL, &val, 1);
@@ -1349,12 +1592,45 @@
goto cleanup;
}
+ chip->pt_dis_votable = create_votable("QNOVO_PT_DIS", VOTE_SET_ANY,
+ pt_dis_votable_cb, chip);
+ if (IS_ERR(chip->pt_dis_votable)) {
+ rc = PTR_ERR(chip->pt_dis_votable);
+ goto destroy_disable_votable;
+ }
+
+ chip->not_ok_to_qnovo_votable = create_votable("QNOVO_NOT_OK",
+ VOTE_SET_ANY,
+ not_ok_to_qnovo_cb, chip);
+ if (IS_ERR(chip->not_ok_to_qnovo_votable)) {
+ rc = PTR_ERR(chip->not_ok_to_qnovo_votable);
+ goto destroy_pt_dis_votable;
+ }
+
+ chip->chg_ready_votable = create_votable("QNOVO_CHG_READY",
+ VOTE_SET_ANY,
+ chg_ready_cb, chip);
+ if (IS_ERR(chip->chg_ready_votable)) {
+ rc = PTR_ERR(chip->chg_ready_votable);
+ goto destroy_not_ok_to_qnovo_votable;
+ }
+
+ chip->awake_votable = create_votable("QNOVO_AWAKE", VOTE_SET_ANY,
+ awake_cb, chip);
+ if (IS_ERR(chip->awake_votable)) {
+ rc = PTR_ERR(chip->awake_votable);
+ goto destroy_chg_ready_votable;
+ }
+
INIT_WORK(&chip->status_change_work, status_change_work);
+ INIT_DELAYED_WORK(&chip->dc_debounce_work, dc_debounce_work);
+ INIT_DELAYED_WORK(&chip->usb_debounce_work, usb_debounce_work);
+ INIT_DELAYED_WORK(&chip->ptrain_restart_work, ptrain_restart_work);
rc = qnovo_hw_init(chip);
if (rc < 0) {
pr_err("Couldn't initialize hardware rc=%d\n", rc);
- goto destroy_votable;
+ goto destroy_awake_votable;
}
rc = qnovo_register_notifier(chip);
@@ -1390,7 +1666,15 @@
unreg_notifier:
power_supply_unreg_notifier(&chip->nb);
-destroy_votable:
+destroy_awake_votable:
+ destroy_votable(chip->awake_votable);
+destroy_chg_ready_votable:
+ destroy_votable(chip->chg_ready_votable);
+destroy_not_ok_to_qnovo_votable:
+ destroy_votable(chip->not_ok_to_qnovo_votable);
+destroy_pt_dis_votable:
+ destroy_votable(chip->pt_dis_votable);
+destroy_disable_votable:
destroy_votable(chip->disable_votable);
cleanup:
platform_set_drvdata(pdev, NULL);
@@ -1403,6 +1687,9 @@
class_unregister(&chip->qnovo_class);
power_supply_unreg_notifier(&chip->nb);
+ destroy_votable(chip->chg_ready_votable);
+ destroy_votable(chip->not_ok_to_qnovo_votable);
+ destroy_votable(chip->pt_dis_votable);
destroy_votable(chip->disable_votable);
platform_set_drvdata(pdev, NULL);
return 0;
diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c
index e94873c..faca084 100644
--- a/drivers/power/supply/qcom/qpnp-smb2.c
+++ b/drivers/power/supply/qcom/qpnp-smb2.c
@@ -19,6 +19,7 @@
#include <linux/power_supply.h>
#include <linux/of.h>
#include <linux/of_irq.h>
+#include <linux/log2.h>
#include <linux/qpnp/qpnp-revid.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/of_regulator.h>
@@ -122,87 +123,6 @@
.max_u = 1575000,
.step_u = 25000,
},
- .step_soc_threshold[0] = {
- .name = "step charge soc threshold 1",
- .reg = STEP_CHG_SOC_OR_BATT_V_TH1_REG,
- .min_u = 0,
- .max_u = 100,
- .step_u = 1,
- },
- .step_soc_threshold[1] = {
- .name = "step charge soc threshold 2",
- .reg = STEP_CHG_SOC_OR_BATT_V_TH2_REG,
- .min_u = 0,
- .max_u = 100,
- .step_u = 1,
- },
- .step_soc_threshold[2] = {
- .name = "step charge soc threshold 3",
- .reg = STEP_CHG_SOC_OR_BATT_V_TH3_REG,
- .min_u = 0,
- .max_u = 100,
- .step_u = 1,
- },
- .step_soc_threshold[3] = {
- .name = "step charge soc threshold 4",
- .reg = STEP_CHG_SOC_OR_BATT_V_TH4_REG,
- .min_u = 0,
- .max_u = 100,
- .step_u = 1,
- },
- .step_soc = {
- .name = "step charge soc",
- .reg = STEP_CHG_SOC_VBATT_V_REG,
- .min_u = 0,
- .max_u = 100,
- .step_u = 1,
- .set_proc = smblib_mapping_soc_from_field_value,
- },
- .step_cc_delta[0] = {
- .name = "step charge current delta 1",
- .reg = STEP_CHG_CURRENT_DELTA1_REG,
- .min_u = 100000,
- .max_u = 3200000,
- .step_u = 100000,
- .get_proc = smblib_mapping_cc_delta_to_field_value,
- .set_proc = smblib_mapping_cc_delta_from_field_value,
- },
- .step_cc_delta[1] = {
- .name = "step charge current delta 2",
- .reg = STEP_CHG_CURRENT_DELTA2_REG,
- .min_u = 100000,
- .max_u = 3200000,
- .step_u = 100000,
- .get_proc = smblib_mapping_cc_delta_to_field_value,
- .set_proc = smblib_mapping_cc_delta_from_field_value,
- },
- .step_cc_delta[2] = {
- .name = "step charge current delta 3",
- .reg = STEP_CHG_CURRENT_DELTA3_REG,
- .min_u = 100000,
- .max_u = 3200000,
- .step_u = 100000,
- .get_proc = smblib_mapping_cc_delta_to_field_value,
- .set_proc = smblib_mapping_cc_delta_from_field_value,
- },
- .step_cc_delta[3] = {
- .name = "step charge current delta 4",
- .reg = STEP_CHG_CURRENT_DELTA4_REG,
- .min_u = 100000,
- .max_u = 3200000,
- .step_u = 100000,
- .get_proc = smblib_mapping_cc_delta_to_field_value,
- .set_proc = smblib_mapping_cc_delta_from_field_value,
- },
- .step_cc_delta[4] = {
- .name = "step charge current delta 5",
- .reg = STEP_CHG_CURRENT_DELTA5_REG,
- .min_u = 100000,
- .max_u = 3200000,
- .step_u = 100000,
- .get_proc = smblib_mapping_cc_delta_to_field_value,
- .set_proc = smblib_mapping_cc_delta_from_field_value,
- },
.freq_buck = {
.name = "buck switching frequency",
.reg = CFG_BUCKBOOST_FREQ_SELECT_BUCK_REG,
@@ -236,7 +156,6 @@
},
};
-#define STEP_CHARGING_MAX_STEPS 5
struct smb_dt_props {
int usb_icl_ua;
int dc_icl_ua;
@@ -244,14 +163,13 @@
int wipower_max_uw;
int min_freq_khz;
int max_freq_khz;
- u32 step_soc_threshold[STEP_CHARGING_MAX_STEPS - 1];
- s32 step_cc_delta[STEP_CHARGING_MAX_STEPS];
struct device_node *revid_dev_node;
int float_option;
int chg_inhibit_thr_mv;
bool no_battery;
bool hvdcp_disable;
bool auto_recharge_soc;
+ int wd_bark_time;
};
struct smb2 {
@@ -273,6 +191,11 @@
#define MICRO_1P5A 1500000
#define MICRO_P1A 100000
#define OTG_DEFAULT_DEGLITCH_TIME_MS 50
+#define MIN_WD_BARK_TIME 16
+#define DEFAULT_WD_BARK_TIME 64
+#define BITE_WDOG_TIMEOUT_8S 0x3
+#define BARK_WDOG_TIMEOUT_MASK GENMASK(3, 2)
+#define BARK_WDOG_TIMEOUT_SHIFT 2
static int smb2_parse_dt(struct smb2 *chip)
{
struct smb_charger *chg = &chip->chg;
@@ -284,27 +207,16 @@
return -EINVAL;
}
- chg->step_chg_enabled = true;
+ chg->step_chg_enabled = of_property_read_bool(node,
+ "qcom,step-charging-enable");
- if (of_property_count_u32_elems(node, "qcom,step-soc-thresholds")
- != STEP_CHARGING_MAX_STEPS - 1)
- chg->step_chg_enabled = false;
+ chg->sw_jeita_enabled = of_property_read_bool(node,
+ "qcom,sw-jeita-enable");
- rc = of_property_read_u32_array(node, "qcom,step-soc-thresholds",
- chip->dt.step_soc_threshold,
- STEP_CHARGING_MAX_STEPS - 1);
- if (rc < 0)
- chg->step_chg_enabled = false;
-
- if (of_property_count_u32_elems(node, "qcom,step-current-deltas")
- != STEP_CHARGING_MAX_STEPS)
- chg->step_chg_enabled = false;
-
- rc = of_property_read_u32_array(node, "qcom,step-current-deltas",
- chip->dt.step_cc_delta,
- STEP_CHARGING_MAX_STEPS);
- if (rc < 0)
- chg->step_chg_enabled = false;
+ rc = of_property_read_u32(node, "qcom,wd-bark-time-secs",
+ &chip->dt.wd_bark_time);
+ if (rc < 0 || chip->dt.wd_bark_time < MIN_WD_BARK_TIME)
+ chip->dt.wd_bark_time = DEFAULT_WD_BARK_TIME;
chip->dt.no_battery = of_property_read_bool(node,
"qcom,batteryless-platform");
@@ -988,7 +900,6 @@
POWER_SUPPLY_PROP_TEMP,
POWER_SUPPLY_PROP_TECHNOLOGY,
POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED,
- POWER_SUPPLY_PROP_STEP_CHARGING_STEP,
POWER_SUPPLY_PROP_CHARGE_DONE,
POWER_SUPPLY_PROP_PARALLEL_DISABLE,
POWER_SUPPLY_PROP_SET_SHIP_MODE,
@@ -1051,9 +962,6 @@
case POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED:
val->intval = chg->step_chg_enabled;
break;
- case POWER_SUPPLY_PROP_STEP_CHARGING_STEP:
- rc = smblib_get_prop_step_chg_step(chg, val);
- break;
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
rc = smblib_get_prop_batt_voltage_now(chg, val);
break;
@@ -1126,6 +1034,9 @@
struct smb_charger *chg = power_supply_get_drvdata(psy);
switch (prop) {
+ case POWER_SUPPLY_PROP_STATUS:
+ rc = smblib_set_prop_batt_status(chg, val);
+ break;
case POWER_SUPPLY_PROP_INPUT_SUSPEND:
rc = smblib_set_prop_input_suspend(chg, val);
break;
@@ -1167,6 +1078,9 @@
vote(chg->fcc_votable, BATT_PROFILE_VOTER, false, 0);
}
break;
+ case POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED:
+ chg->step_chg_enabled = !!val->intval;
+ break;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
chg->batt_profile_fcc_ua = val->intval;
vote(chg->fcc_votable, BATT_PROFILE_VOTER, true, val->intval);
@@ -1200,6 +1114,7 @@
enum power_supply_property psp)
{
switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
case POWER_SUPPLY_PROP_INPUT_SUSPEND:
case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL:
case POWER_SUPPLY_PROP_CAPACITY:
@@ -1207,6 +1122,7 @@
case POWER_SUPPLY_PROP_DP_DM:
case POWER_SUPPLY_PROP_RERUN_AICL:
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED:
+ case POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED:
return 1;
default:
break;
@@ -1334,73 +1250,6 @@
/***************************
* HARDWARE INITIALIZATION *
***************************/
-static int smb2_config_step_charging(struct smb2 *chip)
-{
- struct smb_charger *chg = &chip->chg;
- int rc = 0;
- int i;
-
- if (!chg->step_chg_enabled)
- return rc;
-
- for (i = 0; i < STEP_CHARGING_MAX_STEPS - 1; i++) {
- rc = smblib_set_charge_param(chg,
- &chg->param.step_soc_threshold[i],
- chip->dt.step_soc_threshold[i]);
- if (rc < 0) {
- pr_err("Couldn't configure soc thresholds rc = %d\n",
- rc);
- goto err_out;
- }
- }
-
- for (i = 0; i < STEP_CHARGING_MAX_STEPS; i++) {
- rc = smblib_set_charge_param(chg, &chg->param.step_cc_delta[i],
- chip->dt.step_cc_delta[i]);
- if (rc < 0) {
- pr_err("Couldn't configure cc delta rc = %d\n",
- rc);
- goto err_out;
- }
- }
-
- rc = smblib_write(chg, STEP_CHG_UPDATE_REQUEST_TIMEOUT_CFG_REG,
- STEP_CHG_UPDATE_REQUEST_TIMEOUT_40S);
- if (rc < 0) {
- dev_err(chg->dev,
- "Couldn't configure soc request timeout reg rc=%d\n",
- rc);
- goto err_out;
- }
-
- rc = smblib_write(chg, STEP_CHG_UPDATE_FAIL_TIMEOUT_CFG_REG,
- STEP_CHG_UPDATE_FAIL_TIMEOUT_120S);
- if (rc < 0) {
- dev_err(chg->dev,
- "Couldn't configure soc fail timeout reg rc=%d\n",
- rc);
- goto err_out;
- }
-
- /*
- * enable step charging, source soc, standard mode, go to final
- * state in case of failure.
- */
- rc = smblib_write(chg, CHGR_STEP_CHG_MODE_CFG_REG,
- STEP_CHARGING_ENABLE_BIT |
- STEP_CHARGING_SOURCE_SELECT_BIT |
- STEP_CHARGING_SOC_FAIL_OPTION_BIT);
- if (rc < 0) {
- dev_err(chg->dev, "Couldn't configure charger rc=%d\n", rc);
- goto err_out;
- }
-
- return 0;
-err_out:
- chg->step_chg_enabled = false;
- return rc;
-}
-
static int smb2_config_wipower_input_power(struct smb2 *chip, int uw)
{
int rc;
@@ -1576,7 +1425,7 @@
{
struct smb_charger *chg = &chip->chg;
int rc;
- u8 stat;
+ u8 stat, val;
if (chip->dt.no_battery)
chg->fake_capacity = 50;
@@ -1724,11 +1573,27 @@
return rc;
}
- /* configure step charging */
- rc = smb2_config_step_charging(chip);
- if (rc < 0) {
- dev_err(chg->dev, "Couldn't configure step charging rc=%d\n",
- rc);
+ val = (ilog2(chip->dt.wd_bark_time / 16) << BARK_WDOG_TIMEOUT_SHIFT) &
+ BARK_WDOG_TIMEOUT_MASK;
+ val |= BITE_WDOG_TIMEOUT_8S;
+ rc = smblib_masked_write(chg, SNARL_BARK_BITE_WD_CFG_REG,
+ BITE_WDOG_DISABLE_CHARGING_CFG_BIT |
+ BARK_WDOG_TIMEOUT_MASK | BITE_WDOG_TIMEOUT_MASK,
+ val);
+ if (rc) {
+ pr_err("Couldn't configue WD config rc=%d\n", rc);
+ return rc;
+ }
+
+ /* enable WD BARK and enable it on plugin */
+ rc = smblib_masked_write(chg, WD_CFG_REG,
+ WATCHDOG_TRIGGER_AFP_EN_BIT |
+ WDOG_TIMER_EN_ON_PLUGIN_BIT |
+ BARK_WDOG_INT_EN_BIT,
+ WDOG_TIMER_EN_ON_PLUGIN_BIT |
+ BARK_WDOG_INT_EN_BIT);
+ if (rc) {
+ pr_err("Couldn't configue WD config rc=%d\n", rc);
return rc;
}
@@ -1787,6 +1652,13 @@
return rc;
}
+ rc = smblib_read(chg, USBIN_OPTIONS_2_CFG_REG, &chg->float_cfg);
+ if (rc < 0) {
+ dev_err(chg->dev, "Couldn't read float charger options rc=%d\n",
+ rc);
+ return rc;
+ }
+
switch (chip->dt.chg_inhibit_thr_mv) {
case 50:
rc = smblib_masked_write(chg, CHARGE_INHIBIT_THRESHOLD_CFG_REG,
@@ -1851,6 +1723,12 @@
struct smb_charger *chg = &chip->chg;
int rc;
+ /* In case the usb path is suspended, we would have missed disabling
+ * the icl change interrupt because the interrupt could have been
+ * not requested
+ */
+ rerun_election(chg->usb_icl_votable);
+
/* configure power role for dual-role */
rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
TYPEC_POWER_ROLE_CMD_MASK, 0);
@@ -1942,8 +1820,8 @@
smblib_handle_usb_source_change(0, &irq_data);
smblib_handle_chg_state_change(0, &irq_data);
smblib_handle_icl_change(0, &irq_data);
- smblib_handle_step_chg_state_change(0, &irq_data);
- smblib_handle_step_chg_soc_update_request(0, &irq_data);
+ smblib_handle_batt_temp_changed(0, &irq_data);
+ smblib_handle_wdog_bark(0, &irq_data);
return 0;
}
@@ -1965,18 +1843,15 @@
},
[STEP_CHG_STATE_CHANGE_IRQ] = {
.name = "step-chg-state-change",
- .handler = smblib_handle_step_chg_state_change,
- .wake = true,
+ .handler = NULL,
},
[STEP_CHG_SOC_UPDATE_FAIL_IRQ] = {
.name = "step-chg-soc-update-fail",
- .handler = smblib_handle_step_chg_soc_update_fail,
- .wake = true,
+ .handler = NULL,
},
[STEP_CHG_SOC_UPDATE_REQ_IRQ] = {
.name = "step-chg-soc-update-request",
- .handler = smblib_handle_step_chg_soc_update_request,
- .wake = true,
+ .handler = NULL,
},
/* OTG IRQs */
[OTG_FAIL_IRQ] = {
@@ -1999,6 +1874,7 @@
[BATT_TEMP_IRQ] = {
.name = "bat-temp",
.handler = smblib_handle_batt_temp_changed,
+ .wake = true,
},
[BATT_OCP_IRQ] = {
.name = "bat-ocp",
@@ -2094,7 +1970,8 @@
},
[WDOG_BARK_IRQ] = {
.name = "wdog-bark",
- .handler = NULL,
+ .handler = smblib_handle_wdog_bark,
+ .wake = true,
},
[AICL_FAIL_IRQ] = {
.name = "aicl-fail",
@@ -2200,6 +2077,8 @@
return rc;
}
}
+ if (chg->irq_info[USBIN_ICL_CHANGE_IRQ].irq)
+ chg->usb_icl_change_irq_enabled = true;
return rc;
}
@@ -2332,18 +2211,18 @@
return rc;
}
- rc = smblib_init(chg);
- if (rc < 0) {
- pr_err("Smblib_init failed rc=%d\n", rc);
- goto cleanup;
- }
-
rc = smb2_parse_dt(chip);
if (rc < 0) {
pr_err("Couldn't parse device tree rc=%d\n", rc);
goto cleanup;
}
+ rc = smblib_init(chg);
+ if (rc < 0) {
+ pr_err("Smblib_init failed rc=%d\n", rc);
+ goto cleanup;
+ }
+
/* set driver data before resources request it */
platform_set_drvdata(pdev, chip);
diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c
index 3f26e5e..601f3e1 100644
--- a/drivers/power/supply/qcom/smb-lib.c
+++ b/drivers/power/supply/qcom/smb-lib.c
@@ -22,6 +22,7 @@
#include "smb-lib.h"
#include "smb-reg.h"
#include "battery.h"
+#include "step-chg-jeita.h"
#include "storm-watch.h"
#define smblib_err(chg, fmt, ...) \
@@ -101,35 +102,6 @@
return rc;
}
-static int smblib_get_step_cc_delta(struct smb_charger *chg, int *cc_delta_ua)
-{
- int rc, step_state;
- u8 stat;
-
- if (!chg->step_chg_enabled) {
- *cc_delta_ua = 0;
- return 0;
- }
-
- rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
- if (rc < 0) {
- smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
- rc);
- return rc;
- }
-
- step_state = (stat & STEP_CHARGING_STATUS_MASK) >>
- STEP_CHARGING_STATUS_SHIFT;
- rc = smblib_get_charge_param(chg, &chg->param.step_cc_delta[step_state],
- cc_delta_ua);
- if (rc < 0) {
- smblib_err(chg, "Couldn't get step cc delta rc=%d\n", rc);
- return rc;
- }
-
- return 0;
-}
-
static int smblib_get_jeita_cc_delta(struct smb_charger *chg, int *cc_delta_ua)
{
int rc, cc_minus_ua;
@@ -148,7 +120,7 @@
}
rc = smblib_get_charge_param(chg, &chg->param.jeita_cc_comp,
- &cc_minus_ua);
+ &cc_minus_ua);
if (rc < 0) {
smblib_err(chg, "Couldn't get jeita cc minus rc=%d\n", rc);
return rc;
@@ -401,31 +373,17 @@
return rc;
}
-static int step_charge_soc_update(struct smb_charger *chg, int capacity)
-{
- int rc = 0;
-
- rc = smblib_set_charge_param(chg, &chg->param.step_soc, capacity);
- if (rc < 0) {
- smblib_err(chg, "Error in updating soc, rc=%d\n", rc);
- return rc;
- }
-
- rc = smblib_write(chg, STEP_CHG_SOC_VBATT_V_UPDATE_REG,
- STEP_CHG_SOC_VBATT_V_UPDATE_BIT);
- if (rc < 0) {
- smblib_err(chg,
- "Couldn't set STEP_CHG_SOC_VBATT_V_UPDATE_REG rc=%d\n",
- rc);
- return rc;
- }
-
- return rc;
-}
-
int smblib_set_usb_suspend(struct smb_charger *chg, bool suspend)
{
int rc = 0;
+ int irq = chg->irq_info[USBIN_ICL_CHANGE_IRQ].irq;
+
+ if (suspend && irq) {
+ if (chg->usb_icl_change_irq_enabled) {
+ disable_irq_nosync(irq);
+ chg->usb_icl_change_irq_enabled = false;
+ }
+ }
rc = smblib_masked_write(chg, USBIN_CMD_IL_REG, USBIN_SUSPEND_BIT,
suspend ? USBIN_SUSPEND_BIT : 0);
@@ -433,6 +391,13 @@
smblib_err(chg, "Couldn't write %s to USBIN_SUSPEND_BIT rc=%d\n",
suspend ? "suspend" : "resume", rc);
+ if (!suspend && irq) {
+ if (!chg->usb_icl_change_irq_enabled) {
+ enable_irq(irq);
+ chg->usb_icl_change_irq_enabled = true;
+ }
+ }
+
return rc;
}
@@ -522,6 +487,45 @@
/********************
* HELPER FUNCTIONS *
********************/
+static int smblib_request_dpdm(struct smb_charger *chg, bool enable)
+{
+ int rc = 0;
+
+ /* fetch the DPDM regulator */
+ if (!chg->dpdm_reg && of_get_property(chg->dev->of_node,
+ "dpdm-supply", NULL)) {
+ chg->dpdm_reg = devm_regulator_get(chg->dev, "dpdm");
+ if (IS_ERR(chg->dpdm_reg)) {
+ rc = PTR_ERR(chg->dpdm_reg);
+ smblib_err(chg, "Couldn't get dpdm regulator rc=%d\n",
+ rc);
+ chg->dpdm_reg = NULL;
+ return rc;
+ }
+ }
+
+ if (enable) {
+ if (chg->dpdm_reg && !regulator_is_enabled(chg->dpdm_reg)) {
+ smblib_dbg(chg, PR_MISC, "enabling DPDM regulator\n");
+ rc = regulator_enable(chg->dpdm_reg);
+ if (rc < 0)
+ smblib_err(chg,
+ "Couldn't enable dpdm regulator rc=%d\n",
+ rc);
+ }
+ } else {
+ if (chg->dpdm_reg && regulator_is_enabled(chg->dpdm_reg)) {
+ smblib_dbg(chg, PR_MISC, "disabling DPDM regulator\n");
+ rc = regulator_disable(chg->dpdm_reg);
+ if (rc < 0)
+ smblib_err(chg,
+ "Couldn't disable dpdm regulator rc=%d\n",
+ rc);
+ }
+ }
+
+ return rc;
+}
static void smblib_rerun_apsd(struct smb_charger *chg)
{
@@ -548,10 +552,17 @@
const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
/* if PD is active, APSD is disabled so won't have a valid result */
- if (chg->pd_active)
+ if (chg->pd_active) {
chg->real_charger_type = POWER_SUPPLY_TYPE_USB_PD;
- else
+ } else {
+ /*
+ * Update real charger type only if its not FLOAT
+ * detected as as SDP
+ */
+ if (!(apsd_result->pst == POWER_SUPPLY_TYPE_USB_FLOAT &&
+ chg->real_charger_type == POWER_SUPPLY_TYPE_USB))
chg->real_charger_type = apsd_result->pst;
+ }
smblib_dbg(chg, PR_MISC, "APSD=%s PD=%d\n",
apsd_result->name, chg->pd_active);
@@ -634,13 +645,9 @@
cancel_delayed_work_sync(&chg->pl_enable_work);
- if (chg->dpdm_reg && regulator_is_enabled(chg->dpdm_reg)) {
- smblib_dbg(chg, PR_MISC, "disabling DPDM regulator\n");
- rc = regulator_disable(chg->dpdm_reg);
- if (rc < 0)
- smblib_err(chg, "Couldn't disable dpdm regulator rc=%d\n",
- rc);
- }
+ rc = smblib_request_dpdm(chg, false);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't to disable DPDM rc=%d\n", rc);
if (chg->wa_flags & BOOST_BACK_WA) {
data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data;
@@ -732,24 +739,9 @@
if (!val.intval)
return 0;
- /* fetch the DPDM regulator */
- if (!chg->dpdm_reg && of_get_property(chg->dev->of_node,
- "dpdm-supply", NULL)) {
- chg->dpdm_reg = devm_regulator_get(chg->dev, "dpdm");
- if (IS_ERR(chg->dpdm_reg)) {
- smblib_err(chg, "Couldn't get dpdm regulator rc=%ld\n",
- PTR_ERR(chg->dpdm_reg));
- chg->dpdm_reg = NULL;
- }
- }
-
- if (chg->dpdm_reg && !regulator_is_enabled(chg->dpdm_reg)) {
- smblib_dbg(chg, PR_MISC, "enabling DPDM regulator\n");
- rc = regulator_enable(chg->dpdm_reg);
- if (rc < 0)
- smblib_err(chg, "Couldn't enable dpdm regulator rc=%d\n",
- rc);
- }
+ rc = smblib_request_dpdm(chg, true);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc);
chg->uusb_apsd_rerun_done = true;
smblib_rerun_apsd(chg);
@@ -819,6 +811,7 @@
{
int rc;
u8 icl_options;
+ const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
/* power source is SDP */
switch (icl_ua) {
@@ -843,6 +836,21 @@
return -EINVAL;
}
+ if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB &&
+ apsd_result->pst == POWER_SUPPLY_TYPE_USB_FLOAT) {
+ /*
+ * change the float charger configuration to SDP, if this
+ * is the case of SDP being detected as FLOAT
+ */
+ rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
+ FORCE_FLOAT_SDP_CFG_BIT, FORCE_FLOAT_SDP_CFG_BIT);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't set float ICL options rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
+
rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
CFG_USB3P0_SEL_BIT | USB51_MODE_BIT, icl_options);
if (rc < 0) {
@@ -884,7 +892,6 @@
if (icl_ua < USBIN_25MA)
return smblib_set_usb_suspend(chg, true);
- disable_irq_nosync(chg->irq_info[USBIN_ICL_CHANGE_IRQ].irq);
if (icl_ua == INT_MAX)
goto override_suspend_config;
@@ -942,7 +949,6 @@
}
enable_icl_changed_interrupt:
- enable_irq(chg->irq_info[USBIN_ICL_CHANGE_IRQ].irq);
return rc;
}
@@ -1318,11 +1324,84 @@
#define MAX_RETRY 15
#define MIN_DELAY_US 2000
#define MAX_DELAY_US 9000
+static int otg_current[] = {250000, 500000, 1000000, 1500000};
+static int smblib_enable_otg_wa(struct smb_charger *chg)
+{
+ u8 stat;
+ int rc, i, retry_count = 0, min_delay = MIN_DELAY_US;
+
+ for (i = 0; i < ARRAY_SIZE(otg_current); i++) {
+ smblib_dbg(chg, PR_OTG, "enabling OTG with %duA\n",
+ otg_current[i]);
+ rc = smblib_set_charge_param(chg, &chg->param.otg_cl,
+ otg_current[i]);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't set otg limit rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = smblib_write(chg, CMD_OTG_REG, OTG_EN_BIT);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't enable OTG rc=%d\n", rc);
+ return rc;
+ }
+
+ retry_count = 0;
+ min_delay = MIN_DELAY_US;
+ do {
+ usleep_range(min_delay, min_delay + 100);
+ rc = smblib_read(chg, OTG_STATUS_REG, &stat);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't read OTG status rc=%d\n",
+ rc);
+ goto out;
+ }
+
+ if (stat & BOOST_SOFTSTART_DONE_BIT) {
+ rc = smblib_set_charge_param(chg,
+ &chg->param.otg_cl, chg->otg_cl_ua);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't set otg limit rc=%d\n",
+ rc);
+ goto out;
+ }
+ break;
+ }
+ /* increase the delay for following iterations */
+ if (retry_count > 5)
+ min_delay = MAX_DELAY_US;
+
+ } while (retry_count++ < MAX_RETRY);
+
+ if (retry_count >= MAX_RETRY) {
+ smblib_dbg(chg, PR_OTG, "OTG enable failed with %duA\n",
+ otg_current[i]);
+ rc = smblib_write(chg, CMD_OTG_REG, 0);
+ if (rc < 0) {
+ smblib_err(chg, "disable OTG rc=%d\n", rc);
+ goto out;
+ }
+ } else {
+ smblib_dbg(chg, PR_OTG, "OTG enabled\n");
+ return 0;
+ }
+ }
+
+ if (i == ARRAY_SIZE(otg_current)) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ return 0;
+out:
+ smblib_write(chg, CMD_OTG_REG, 0);
+ return rc;
+}
+
static int _smblib_vbus_regulator_enable(struct regulator_dev *rdev)
{
struct smb_charger *chg = rdev_get_drvdata(rdev);
- int rc, retry_count = 0, min_delay = MIN_DELAY_US;
- u8 stat;
+ int rc;
smblib_dbg(chg, PR_OTG, "halt 1 in 8 mode\n");
rc = smblib_masked_write(chg, OTG_ENG_OTG_CFG_REG,
@@ -1335,48 +1414,17 @@
}
smblib_dbg(chg, PR_OTG, "enabling OTG\n");
- rc = smblib_write(chg, CMD_OTG_REG, OTG_EN_BIT);
- if (rc < 0) {
- smblib_err(chg, "Couldn't enable OTG regulator rc=%d\n", rc);
- return rc;
- }
if (chg->wa_flags & OTG_WA) {
- /* check for softstart */
- do {
- usleep_range(min_delay, min_delay + 100);
- rc = smblib_read(chg, OTG_STATUS_REG, &stat);
- if (rc < 0) {
- smblib_err(chg,
- "Couldn't read OTG status rc=%d\n",
- rc);
- goto out;
- }
-
- if (stat & BOOST_SOFTSTART_DONE_BIT) {
- rc = smblib_set_charge_param(chg,
- &chg->param.otg_cl, chg->otg_cl_ua);
- if (rc < 0)
- smblib_err(chg,
- "Couldn't set otg limit\n");
- break;
- }
-
- /* increase the delay for following iterations */
- if (retry_count > 5)
- min_delay = MAX_DELAY_US;
- } while (retry_count++ < MAX_RETRY);
-
- if (retry_count >= MAX_RETRY) {
- smblib_dbg(chg, PR_OTG, "Boost Softstart not done\n");
- goto out;
- }
+ rc = smblib_enable_otg_wa(chg);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't enable OTG rc=%d\n", rc);
+ } else {
+ rc = smblib_write(chg, CMD_OTG_REG, OTG_EN_BIT);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't enable OTG rc=%d\n", rc);
}
- return 0;
-out:
- /* disable OTG if softstart failed */
- smblib_write(chg, CMD_OTG_REG, 0);
return rc;
}
@@ -1522,8 +1570,8 @@
union power_supply_propval *val)
{
union power_supply_propval pval = {0, };
- bool usb_online, dc_online;
- u8 stat;
+ bool usb_online, dc_online, qnovo_en;
+ u8 stat, pt_en_cmd;
int rc;
rc = smblib_get_prop_usb_online(chg, &pval);
@@ -1586,16 +1634,33 @@
if (val->intval != POWER_SUPPLY_STATUS_CHARGING)
return 0;
+ if (!usb_online && dc_online
+ && chg->fake_batt_status == POWER_SUPPLY_STATUS_FULL) {
+ val->intval = POWER_SUPPLY_STATUS_FULL;
+ return 0;
+ }
+
rc = smblib_read(chg, BATTERY_CHARGER_STATUS_7_REG, &stat);
if (rc < 0) {
smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
rc);
return rc;
- }
+ }
stat &= ENABLE_TRICKLE_BIT | ENABLE_PRE_CHARGING_BIT |
ENABLE_FAST_CHARGING_BIT | ENABLE_FULLON_MODE_BIT;
- if (!stat)
+
+ rc = smblib_read(chg, QNOVO_PT_ENABLE_CMD_REG, &pt_en_cmd);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't read QNOVO_PT_ENABLE_CMD_REG rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ qnovo_en = (bool)(pt_en_cmd & QNOVO_PT_ENABLE_CMD_BIT);
+
+ /* ignore stat7 when qnovo is enabled */
+ if (!qnovo_en && !stat)
val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
return 0;
@@ -1755,30 +1820,6 @@
return rc;
}
-int smblib_get_prop_step_chg_step(struct smb_charger *chg,
- union power_supply_propval *val)
-{
- int rc;
- u8 stat;
-
- if (!chg->step_chg_enabled) {
- val->intval = -1;
- return 0;
- }
-
- rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
- if (rc < 0) {
- smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
- rc);
- return rc;
- }
-
- val->intval = (stat & STEP_CHARGING_STATUS_MASK) >>
- STEP_CHARGING_STATUS_SHIFT;
-
- return rc;
-}
-
int smblib_get_prop_batt_charge_done(struct smb_charger *chg,
union power_supply_propval *val)
{
@@ -1852,6 +1893,20 @@
return 0;
}
+int smblib_set_prop_batt_status(struct smb_charger *chg,
+ const union power_supply_propval *val)
+{
+ /* Faking battery full */
+ if (val->intval == POWER_SUPPLY_STATUS_FULL)
+ chg->fake_batt_status = val->intval;
+ else
+ chg->fake_batt_status = -EINVAL;
+
+ power_supply_changed(chg->batt_psy);
+
+ return 0;
+}
+
int smblib_set_prop_system_temp_level(struct smb_charger *chg,
const union power_supply_propval *val)
{
@@ -2346,16 +2401,9 @@
int smblib_get_prop_input_voltage_settled(struct smb_charger *chg,
union power_supply_propval *val)
{
- const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
int rc, pulses;
- val->intval = MICRO_5V;
- if (apsd_result == NULL) {
- smblib_err(chg, "APSD result is NULL\n");
- return 0;
- }
-
- switch (apsd_result->pst) {
+ switch (chg->real_charger_type) {
case POWER_SUPPLY_TYPE_USB_HVDCP_3:
rc = smblib_get_pulse_cnt(chg, &pulses);
if (rc < 0) {
@@ -2365,6 +2413,9 @@
}
val->intval = MICRO_5V + HVDCP3_STEP_UV * pulses;
break;
+ case POWER_SUPPLY_TYPE_USB_PD:
+ val->intval = chg->voltage_min_uv;
+ break;
default:
val->intval = MICRO_5V;
break;
@@ -2427,6 +2478,31 @@
return 0;
}
+#define SDP_CURRENT_UA 500000
+#define CDP_CURRENT_UA 1500000
+#define DCP_CURRENT_UA 1500000
+#define HVDCP_CURRENT_UA 3000000
+#define TYPEC_DEFAULT_CURRENT_UA 900000
+#define TYPEC_MEDIUM_CURRENT_UA 1500000
+#define TYPEC_HIGH_CURRENT_UA 3000000
+static int get_rp_based_dcp_current(struct smb_charger *chg, int typec_mode)
+{
+ int rp_ua;
+
+ switch (typec_mode) {
+ case POWER_SUPPLY_TYPEC_SOURCE_HIGH:
+ rp_ua = TYPEC_HIGH_CURRENT_UA;
+ break;
+ case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM:
+ case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT:
+ /* fall through */
+ default:
+ rp_ua = DCP_CURRENT_UA;
+ }
+
+ return rp_ua;
+}
+
/*******************
* USB PSY SETTERS *
* *****************/
@@ -2444,14 +2520,54 @@
return rc;
}
+static int smblib_handle_usb_current(struct smb_charger *chg,
+ int usb_current)
+{
+ int rc = 0, rp_ua, typec_mode;
+
+ if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_FLOAT) {
+ if (usb_current == -ETIMEDOUT) {
+ /*
+ * Valid FLOAT charger, report the current based
+ * of Rp
+ */
+ typec_mode = smblib_get_prop_typec_mode(chg);
+ rp_ua = get_rp_based_dcp_current(chg, typec_mode);
+ rc = vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER,
+ true, rp_ua);
+ if (rc < 0)
+ return rc;
+ } else {
+ /*
+ * FLOAT charger detected as SDP by USB driver,
+ * charge with the requested current and update the
+ * real_charger_type
+ */
+ chg->real_charger_type = POWER_SUPPLY_TYPE_USB;
+ rc = vote(chg->usb_icl_votable, USB_PSY_VOTER,
+ true, usb_current);
+ if (rc < 0)
+ return rc;
+ rc = vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER,
+ false, 0);
+ if (rc < 0)
+ return rc;
+ }
+ } else {
+ rc = vote(chg->usb_icl_votable, USB_PSY_VOTER,
+ true, usb_current);
+ }
+
+ return rc;
+}
+
int smblib_set_prop_usb_current_max(struct smb_charger *chg,
const union power_supply_propval *val)
{
int rc = 0;
if (!chg->pd_active) {
- rc = vote(chg->usb_icl_votable, USB_PSY_VOTER,
- true, val->intval);
+ rc = smblib_handle_usb_current(chg, val->intval);
} else if (chg->system_suspend_supported) {
if (val->intval <= USBIN_25MA)
rc = vote(chg->usb_icl_votable,
@@ -2547,6 +2663,7 @@
}
chg->voltage_min_uv = min_uv;
+ power_supply_changed(chg->usb_main_psy);
return rc;
}
@@ -2834,46 +2951,72 @@
return rc;
}
+static int smblib_recover_from_soft_jeita(struct smb_charger *chg)
+{
+ u8 stat_1, stat_2;
+ int rc;
+
+ rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat_1);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ rc = smblib_read(chg, BATTERY_CHARGER_STATUS_2_REG, &stat_2);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ if ((chg->jeita_status && !(stat_2 & BAT_TEMP_STATUS_SOFT_LIMIT_MASK) &&
+ ((stat_1 & BATTERY_CHARGER_STATUS_MASK) == TERMINATE_CHARGE))) {
+ /*
+ * We are moving from JEITA soft -> Normal and charging
+ * is terminated
+ */
+ rc = smblib_write(chg, CHARGING_ENABLE_CMD_REG, 0);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't disable charging rc=%d\n",
+ rc);
+ return rc;
+ }
+ rc = smblib_write(chg, CHARGING_ENABLE_CMD_REG,
+ CHARGING_ENABLE_CMD_BIT);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't enable charging rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
+
+ chg->jeita_status = stat_2 & BAT_TEMP_STATUS_SOFT_LIMIT_MASK;
+
+ return 0;
+}
+
/************************
* USB MAIN PSY GETTERS *
************************/
int smblib_get_prop_fcc_delta(struct smb_charger *chg,
- union power_supply_propval *val)
+ union power_supply_propval *val)
{
- int rc, jeita_cc_delta_ua, step_cc_delta_ua, hw_cc_delta_ua = 0;
-
- rc = smblib_get_step_cc_delta(chg, &step_cc_delta_ua);
- if (rc < 0) {
- smblib_err(chg, "Couldn't get step cc delta rc=%d\n", rc);
- step_cc_delta_ua = 0;
- } else {
- hw_cc_delta_ua = step_cc_delta_ua;
- }
+ int rc, jeita_cc_delta_ua = 0;
rc = smblib_get_jeita_cc_delta(chg, &jeita_cc_delta_ua);
if (rc < 0) {
smblib_err(chg, "Couldn't get jeita cc delta rc=%d\n", rc);
jeita_cc_delta_ua = 0;
- } else if (jeita_cc_delta_ua < 0) {
- /* HW will take the min between JEITA and step charge */
- hw_cc_delta_ua = min(hw_cc_delta_ua, jeita_cc_delta_ua);
}
- val->intval = hw_cc_delta_ua;
+ val->intval = jeita_cc_delta_ua;
return 0;
}
/************************
* USB MAIN PSY SETTERS *
************************/
-
-#define SDP_CURRENT_UA 500000
-#define CDP_CURRENT_UA 1500000
-#define DCP_CURRENT_UA 1500000
-#define HVDCP_CURRENT_UA 3000000
-#define TYPEC_DEFAULT_CURRENT_UA 900000
-#define TYPEC_MEDIUM_CURRENT_UA 1500000
-#define TYPEC_HIGH_CURRENT_UA 3000000
int smblib_get_charge_current(struct smb_charger *chg,
int *total_current_ua)
{
@@ -3040,61 +3183,18 @@
return IRQ_HANDLED;
}
-irqreturn_t smblib_handle_step_chg_state_change(int irq, void *data)
-{
- struct smb_irq_data *irq_data = data;
- struct smb_charger *chg = irq_data->parent_data;
-
- smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
-
- if (chg->step_chg_enabled)
- rerun_election(chg->fcc_votable);
-
- return IRQ_HANDLED;
-}
-
-irqreturn_t smblib_handle_step_chg_soc_update_fail(int irq, void *data)
-{
- struct smb_irq_data *irq_data = data;
- struct smb_charger *chg = irq_data->parent_data;
-
- smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
-
- if (chg->step_chg_enabled)
- rerun_election(chg->fcc_votable);
-
- return IRQ_HANDLED;
-}
-
-#define STEP_SOC_REQ_MS 3000
-irqreturn_t smblib_handle_step_chg_soc_update_request(int irq, void *data)
-{
- struct smb_irq_data *irq_data = data;
- struct smb_charger *chg = irq_data->parent_data;
- int rc;
- union power_supply_propval pval = {0, };
-
- smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
-
- if (!chg->bms_psy) {
- schedule_delayed_work(&chg->step_soc_req_work,
- msecs_to_jiffies(STEP_SOC_REQ_MS));
- return IRQ_HANDLED;
- }
-
- rc = smblib_get_prop_batt_capacity(chg, &pval);
- if (rc < 0)
- smblib_err(chg, "Couldn't get batt capacity rc=%d\n", rc);
- else
- step_charge_soc_update(chg, pval.intval);
-
- return IRQ_HANDLED;
-}
-
irqreturn_t smblib_handle_batt_temp_changed(int irq, void *data)
{
struct smb_irq_data *irq_data = data;
struct smb_charger *chg = irq_data->parent_data;
+ int rc;
+
+ rc = smblib_recover_from_soft_jeita(chg);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't recover chg from soft jeita rc=%d\n",
+ rc);
+ return IRQ_HANDLED;
+ }
rerun_election(chg->fcc_votable);
power_supply_changed(chg->batt_psy);
@@ -3207,25 +3307,10 @@
smblib_set_opt_freq_buck(chg, vbus_rising ? chg->chg_freq.freq_5V :
chg->chg_freq.freq_removal);
- /* fetch the DPDM regulator */
- if (!chg->dpdm_reg && of_get_property(chg->dev->of_node,
- "dpdm-supply", NULL)) {
- chg->dpdm_reg = devm_regulator_get(chg->dev, "dpdm");
- if (IS_ERR(chg->dpdm_reg)) {
- smblib_err(chg, "Couldn't get dpdm regulator rc=%ld\n",
- PTR_ERR(chg->dpdm_reg));
- chg->dpdm_reg = NULL;
- }
- }
-
if (vbus_rising) {
- if (chg->dpdm_reg && !regulator_is_enabled(chg->dpdm_reg)) {
- smblib_dbg(chg, PR_MISC, "enabling DPDM regulator\n");
- rc = regulator_enable(chg->dpdm_reg);
- if (rc < 0)
- smblib_err(chg, "Couldn't enable dpdm regulator rc=%d\n",
- rc);
- }
+ rc = smblib_request_dpdm(chg, true);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc);
/* Schedule work to enable parallel charger */
vote(chg->awake_votable, PL_DELAY_VOTER, true, 0);
@@ -3245,13 +3330,9 @@
}
}
- if (chg->dpdm_reg && regulator_is_enabled(chg->dpdm_reg)) {
- smblib_dbg(chg, PR_MISC, "disabling DPDM regulator\n");
- rc = regulator_disable(chg->dpdm_reg);
- if (rc < 0)
- smblib_err(chg, "Couldn't disable dpdm regulator rc=%d\n",
- rc);
- }
+ rc = smblib_request_dpdm(chg, false);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc);
}
if (chg->micro_usb_mode)
@@ -3472,24 +3553,6 @@
rising ? "rising" : "falling");
}
-static int get_rp_based_dcp_current(struct smb_charger *chg, int typec_mode)
-{
- int rp_ua;
-
- switch (typec_mode) {
- case POWER_SUPPLY_TYPEC_SOURCE_HIGH:
- rp_ua = TYPEC_HIGH_CURRENT_UA;
- break;
- case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM:
- case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT:
- /* fall through */
- default:
- rp_ua = DCP_CURRENT_UA;
- }
-
- return rp_ua;
-}
-
static void smblib_force_legacy_icl(struct smb_charger *chg, int pst)
{
int typec_mode;
@@ -3515,11 +3578,17 @@
vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 1500000);
break;
case POWER_SUPPLY_TYPE_USB_DCP:
- case POWER_SUPPLY_TYPE_USB_FLOAT:
typec_mode = smblib_get_prop_typec_mode(chg);
rp_ua = get_rp_based_dcp_current(chg, typec_mode);
vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, rp_ua);
break;
+ case POWER_SUPPLY_TYPE_USB_FLOAT:
+ /*
+ * limit ICL to 100mA, the USB driver will enumerate to check
+ * if this is a SDP and appropriately set the current
+ */
+ vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 100000);
+ break;
case POWER_SUPPLY_TYPE_USB_HVDCP:
case POWER_SUPPLY_TYPE_USB_HVDCP_3:
vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 3000000);
@@ -3655,13 +3724,9 @@
chg->cc2_detach_wa_active = false;
- if (chg->dpdm_reg && regulator_is_enabled(chg->dpdm_reg)) {
- smblib_dbg(chg, PR_MISC, "disabling DPDM regulator\n");
- rc = regulator_disable(chg->dpdm_reg);
- if (rc < 0)
- smblib_err(chg, "Couldn't disable dpdm regulator rc=%d\n",
- rc);
- }
+ rc = smblib_request_dpdm(chg, false);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc);
if (chg->wa_flags & BOOST_BACK_WA) {
data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data;
@@ -3720,6 +3785,13 @@
chg->pd_hard_reset = 0;
chg->typec_legacy_valid = false;
+ /* write back the default FLOAT charger configuration */
+ rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
+ (u8)FLOAT_OPTIONS_MASK, chg->float_cfg);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't write float charger options rc=%d\n",
+ rc);
+
/* reset back to 120mS tCC debounce */
rc = smblib_masked_write(chg, MISC_CFG_REG, TCC_DEBOUNCE_20MS_BIT, 0);
if (rc < 0)
@@ -3799,10 +3871,14 @@
smblib_err(chg, "Couldn't disable APSD_START_ON_CC rc=%d\n",
rc);
- if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT)
+ if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT) {
typec_sink_insertion(chg);
- else
+ } else {
+ rc = smblib_request_dpdm(chg, true);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc);
typec_sink_removal(chg);
+ }
}
static void smblib_handle_rp_change(struct smb_charger *chg, int typec_mode)
@@ -3815,6 +3891,24 @@
return;
/*
+ * if APSD indicates FLOAT and the USB stack had detected SDP,
+ * do not respond to Rp changes as we do not confirm that its
+ * a legacy cable
+ */
+ if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
+ return;
+ /*
+ * We want the ICL vote @ 100mA for a FLOAT charger
+ * until the detection by the USB stack is complete.
+ * Ignore the Rp changes unless there is a
+ * pre-existing valid vote.
+ */
+ if (apsd->pst == POWER_SUPPLY_TYPE_USB_FLOAT &&
+ get_client_vote(chg->usb_icl_votable,
+ LEGACY_UNKNOWN_VOTER) <= 100000)
+ return;
+
+ /*
* handle Rp change for DCP/FLOAT/OCP.
* Update the current only if the Rp is different from
* the last Rp value.
@@ -3852,7 +3946,8 @@
}
/* suspend usb if sink */
- if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT)
+ if ((chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT)
+ && chg->typec_present)
vote(chg->usb_icl_votable, OTG_VOTER, true, 0);
else
vote(chg->usb_icl_votable, OTG_VOTER, false, 0);
@@ -4011,10 +4106,15 @@
struct smb_charger *chg = irq_data->parent_data;
int rc;
+ smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
+
rc = smblib_write(chg, BARK_BITE_WDOG_PET_REG, BARK_BITE_WDOG_PET_BIT);
if (rc < 0)
smblib_err(chg, "Couldn't pet the dog rc=%d\n", rc);
+ if (chg->step_chg_enabled || chg->sw_jeita_enabled)
+ power_supply_changed(chg->batt_psy);
+
return IRQ_HANDLED;
}
@@ -4097,22 +4197,6 @@
power_supply_changed(chg->batt_psy);
}
-static void step_soc_req_work(struct work_struct *work)
-{
- struct smb_charger *chg = container_of(work, struct smb_charger,
- step_soc_req_work.work);
- union power_supply_propval pval = {0, };
- int rc;
-
- rc = smblib_get_prop_batt_capacity(chg, &pval);
- if (rc < 0) {
- smblib_err(chg, "Couldn't get batt capacity rc=%d\n", rc);
- return;
- }
-
- step_charge_soc_update(chg, pval.intval);
-}
-
static void clear_hdc_work(struct work_struct *work)
{
struct smb_charger *chg = container_of(work, struct smb_charger,
@@ -4645,7 +4729,6 @@
INIT_WORK(&chg->bms_update_work, bms_update_work);
INIT_WORK(&chg->rdstd_cc2_detach_work, rdstd_cc2_detach_work);
INIT_DELAYED_WORK(&chg->hvdcp_detect_work, smblib_hvdcp_detect_work);
- INIT_DELAYED_WORK(&chg->step_soc_req_work, step_soc_req_work);
INIT_DELAYED_WORK(&chg->clear_hdc_work, clear_hdc_work);
INIT_WORK(&chg->otg_oc_work, smblib_otg_oc_work);
INIT_WORK(&chg->vconn_oc_work, smblib_vconn_oc_work);
@@ -4657,6 +4740,7 @@
INIT_DELAYED_WORK(&chg->bb_removal_work, smblib_bb_removal_work);
chg->fake_capacity = -EINVAL;
chg->fake_input_current_limited = -EINVAL;
+ chg->fake_batt_status = -EINVAL;
switch (chg->mode) {
case PARALLEL_MASTER:
@@ -4667,6 +4751,14 @@
return rc;
}
+ rc = qcom_step_chg_init(chg->step_chg_enabled,
+ chg->sw_jeita_enabled);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't init qcom_step_chg_init rc=%d\n",
+ rc);
+ return rc;
+ }
+
rc = smblib_create_votables(chg);
if (rc < 0) {
smblib_err(chg, "Couldn't create votables rc=%d\n",
@@ -4701,7 +4793,6 @@
cancel_work_sync(&chg->bms_update_work);
cancel_work_sync(&chg->rdstd_cc2_detach_work);
cancel_delayed_work_sync(&chg->hvdcp_detect_work);
- cancel_delayed_work_sync(&chg->step_soc_req_work);
cancel_delayed_work_sync(&chg->clear_hdc_work);
cancel_work_sync(&chg->otg_oc_work);
cancel_work_sync(&chg->vconn_oc_work);
@@ -4713,6 +4804,7 @@
cancel_delayed_work_sync(&chg->bb_removal_work);
power_supply_unreg_notifier(&chg->nb);
smblib_destroy_votables(chg);
+ qcom_step_chg_deinit();
qcom_batt_deinit();
break;
case PARALLEL_SLAVE:
diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h
index c08d404..2746555 100644
--- a/drivers/power/supply/qcom/smb-lib.h
+++ b/drivers/power/supply/qcom/smb-lib.h
@@ -192,9 +192,6 @@
struct smb_chg_param dc_icl_div2_mid_hv;
struct smb_chg_param dc_icl_div2_hv;
struct smb_chg_param jeita_cc_comp;
- struct smb_chg_param step_soc_threshold[4];
- struct smb_chg_param step_soc;
- struct smb_chg_param step_cc_delta[5];
struct smb_chg_param freq_buck;
struct smb_chg_param freq_boost;
};
@@ -289,7 +286,6 @@
struct work_struct rdstd_cc2_detach_work;
struct delayed_work hvdcp_detect_work;
struct delayed_work ps_change_timeout_work;
- struct delayed_work step_soc_req_work;
struct delayed_work clear_hdc_work;
struct work_struct otg_oc_work;
struct work_struct vconn_oc_work;
@@ -311,7 +307,9 @@
int *thermal_mitigation;
int dcp_icl_ua;
int fake_capacity;
+ int fake_batt_status;
bool step_chg_enabled;
+ bool sw_jeita_enabled;
bool is_hdc;
bool chg_done;
bool micro_usb_mode;
@@ -330,6 +328,9 @@
int fake_input_current_limited;
bool pr_swap_in_progress;
int typec_mode;
+ int usb_icl_change_irq_enabled;
+ u32 jeita_status;
+ u8 float_cfg;
/* workaround flag */
u32 wa_flags;
@@ -384,9 +385,6 @@
irqreturn_t smblib_handle_debug(int irq, void *data);
irqreturn_t smblib_handle_otg_overcurrent(int irq, void *data);
irqreturn_t smblib_handle_chg_state_change(int irq, void *data);
-irqreturn_t smblib_handle_step_chg_state_change(int irq, void *data);
-irqreturn_t smblib_handle_step_chg_soc_update_fail(int irq, void *data);
-irqreturn_t smblib_handle_step_chg_soc_update_request(int irq, void *data);
irqreturn_t smblib_handle_batt_temp_changed(int irq, void *data);
irqreturn_t smblib_handle_batt_psy_changed(int irq, void *data);
irqreturn_t smblib_handle_usb_psy_changed(int irq, void *data);
@@ -426,13 +424,12 @@
union power_supply_propval *val);
int smblib_get_prop_batt_temp(struct smb_charger *chg,
union power_supply_propval *val);
-int smblib_get_prop_step_chg_step(struct smb_charger *chg,
- union power_supply_propval *val);
-
int smblib_set_prop_input_suspend(struct smb_charger *chg,
const union power_supply_propval *val);
int smblib_set_prop_batt_capacity(struct smb_charger *chg,
const union power_supply_propval *val);
+int smblib_set_prop_batt_status(struct smb_charger *chg,
+ const union power_supply_propval *val);
int smblib_set_prop_system_temp_level(struct smb_charger *chg,
const union power_supply_propval *val);
int smblib_set_prop_input_current_limited(struct smb_charger *chg,
@@ -508,7 +505,7 @@
void smblib_suspend_on_debug_battery(struct smb_charger *chg);
int smblib_rerun_apsd_if_required(struct smb_charger *chg);
int smblib_get_prop_fcc_delta(struct smb_charger *chg,
- union power_supply_propval *val);
+ union power_supply_propval *val);
int smblib_icl_override(struct smb_charger *chg, bool override);
int smblib_dp_dm(struct smb_charger *chg, int val);
int smblib_rerun_aicl(struct smb_charger *chg);
diff --git a/drivers/power/supply/qcom/smb138x-charger.c b/drivers/power/supply/qcom/smb138x-charger.c
index ca0a2c6..dd949e7 100644
--- a/drivers/power/supply/qcom/smb138x-charger.c
+++ b/drivers/power/supply/qcom/smb138x-charger.c
@@ -845,6 +845,13 @@
}
}
+ /* configure to a fixed 700khz freq to avoid tdie errors */
+ rc = smblib_set_charge_param(chg, &chg->param.freq_buck, 700);
+ if (rc < 0) {
+ pr_err("Couldn't configure 700Khz switch freq rc=%d\n", rc);
+ return rc;
+ }
+
/* enable watchdog bark and bite interrupts, and disable the watchdog */
rc = smblib_masked_write(chg, WD_CFG_REG, WDOG_TIMER_EN_BIT
| WDOG_TIMER_EN_ON_PLUGIN_BIT | BITE_WDOG_INT_EN_BIT
diff --git a/drivers/power/supply/qcom/step-chg-jeita.c b/drivers/power/supply/qcom/step-chg-jeita.c
new file mode 100644
index 0000000..053aac3
--- /dev/null
+++ b/drivers/power/supply/qcom/step-chg-jeita.c
@@ -0,0 +1,494 @@
+/* Copyright (c) 2017 The Linux Foundation. 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 and
+ * only 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.
+ */
+#define pr_fmt(fmt) "QCOM-STEPCHG: %s: " fmt, __func__
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/power_supply.h>
+#include <linux/slab.h>
+#include <linux/pmic-voter.h>
+#include "step-chg-jeita.h"
+
+#define MAX_STEP_CHG_ENTRIES 8
+#define STEP_CHG_VOTER "STEP_CHG_VOTER"
+#define JEITA_VOTER "JEITA_VOTER"
+
+#define is_between(left, right, value) \
+ (((left) >= (right) && (left) >= (value) \
+ && (value) >= (right)) \
+ || ((left) <= (right) && (left) <= (value) \
+ && (value) <= (right)))
+
+struct range_data {
+ u32 low_threshold;
+ u32 high_threshold;
+ u32 value;
+};
+
+struct step_chg_cfg {
+ u32 psy_prop;
+ char *prop_name;
+ int hysteresis;
+ struct range_data fcc_cfg[MAX_STEP_CHG_ENTRIES];
+};
+
+struct jeita_fcc_cfg {
+ u32 psy_prop;
+ char *prop_name;
+ int hysteresis;
+ struct range_data fcc_cfg[MAX_STEP_CHG_ENTRIES];
+};
+
+struct jeita_fv_cfg {
+ u32 psy_prop;
+ char *prop_name;
+ int hysteresis;
+ struct range_data fv_cfg[MAX_STEP_CHG_ENTRIES];
+};
+
+struct step_chg_info {
+ ktime_t step_last_update_time;
+ ktime_t jeita_last_update_time;
+ bool step_chg_enable;
+ bool sw_jeita_enable;
+ int jeita_fcc_index;
+ int jeita_fv_index;
+ int step_index;
+
+ struct votable *fcc_votable;
+ struct votable *fv_votable;
+ struct wakeup_source *step_chg_ws;
+ struct power_supply *batt_psy;
+ struct delayed_work status_change_work;
+ struct notifier_block nb;
+};
+
+static struct step_chg_info *the_chip;
+
+#define STEP_CHG_HYSTERISIS_DELAY_US 5000000 /* 5 secs */
+
+/*
+ * Step Charging Configuration
+ * Update the table based on the battery profile
+ * Supports VBATT and SOC based source
+ * range data must be in increasing ranges and shouldn't overlap
+ */
+static struct step_chg_cfg step_chg_config = {
+ .psy_prop = POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ .prop_name = "VBATT",
+ .hysteresis = 100000, /* 100mV */
+ .fcc_cfg = {
+ /* VBAT_LOW VBAT_HIGH FCC */
+ {3600000, 4000000, 3000000},
+ {4001000, 4200000, 2800000},
+ {4201000, 4400000, 2000000},
+ },
+ /*
+ * SOC STEP-CHG configuration example.
+ *
+ * .psy_prop = POWER_SUPPLY_PROP_CAPACITY,
+ * .prop_name = "SOC",
+ * .fcc_cfg = {
+ * //SOC_LOW SOC_HIGH FCC
+ * {20, 70, 3000000},
+ * {70, 90, 2750000},
+ * {90, 100, 2500000},
+ * },
+ */
+};
+
+/*
+ * Jeita Charging Configuration
+ * Update the table based on the battery profile
+ * Please ensure that the TEMP ranges are programmed in the hw so that
+ * an interrupt is issued and a consequent psy changed will cause us to
+ * react immediately.
+ * range data must be in increasing ranges and shouldn't overlap.
+ * Gaps are okay
+ */
+static struct jeita_fcc_cfg jeita_fcc_config = {
+ .psy_prop = POWER_SUPPLY_PROP_TEMP,
+ .prop_name = "BATT_TEMP",
+ .hysteresis = 10, /* 1degC hysteresis */
+ .fcc_cfg = {
+ /* TEMP_LOW TEMP_HIGH FCC */
+ {0, 100, 600000},
+ {101, 200, 2000000},
+ {201, 450, 3000000},
+ {451, 550, 600000},
+ },
+};
+
+static struct jeita_fv_cfg jeita_fv_config = {
+ .psy_prop = POWER_SUPPLY_PROP_TEMP,
+ .prop_name = "BATT_TEMP",
+ .hysteresis = 10, /* 1degC hysteresis */
+ .fv_cfg = {
+ /* TEMP_LOW TEMP_HIGH FCC */
+ {0, 100, 4200000},
+ {101, 450, 4400000},
+ {451, 550, 4200000},
+ },
+};
+
+static bool is_batt_available(struct step_chg_info *chip)
+{
+ if (!chip->batt_psy)
+ chip->batt_psy = power_supply_get_by_name("battery");
+
+ if (!chip->batt_psy)
+ return false;
+
+ return true;
+}
+
+static int get_val(struct range_data *range, int hysteresis, int current_index,
+ int threshold,
+ int *new_index, int *val)
+{
+ int i;
+
+ *new_index = -EINVAL;
+ /* first find the matching index without hysteresis */
+ for (i = 0; i < MAX_STEP_CHG_ENTRIES; i++)
+ if (is_between(range[i].low_threshold,
+ range[i].high_threshold, threshold)) {
+ *new_index = i;
+ *val = range[i].value;
+ }
+
+ /* if nothing was found, return -ENODATA */
+ if (*new_index == -EINVAL)
+ return -ENODATA;
+ /*
+ * If we don't have a current_index return this
+ * newfound value. There is no hysterisis from out of range
+ * to in range transition
+ */
+ if (current_index == -EINVAL)
+ return 0;
+
+ /*
+ * Check for hysteresis if it in the neighbourhood
+ * of our current index.
+ */
+ if (*new_index == current_index + 1) {
+ if (threshold < range[*new_index].low_threshold + hysteresis) {
+ /*
+ * Stay in the current index, threshold is not higher
+ * by hysteresis amount
+ */
+ *new_index = current_index;
+ *val = range[current_index].value;
+ }
+ } else if (*new_index == current_index - 1) {
+ if (threshold > range[*new_index].high_threshold - hysteresis) {
+ /*
+ * stay in the current index, threshold is not lower
+ * by hysteresis amount
+ */
+ *new_index = current_index;
+ *val = range[current_index].value;
+ }
+ }
+ return 0;
+}
+
+static int handle_step_chg_config(struct step_chg_info *chip)
+{
+ union power_supply_propval pval = {0, };
+ int rc = 0, fcc_ua = 0;
+ u64 elapsed_us;
+
+ elapsed_us = ktime_us_delta(ktime_get(), chip->step_last_update_time);
+ if (elapsed_us < STEP_CHG_HYSTERISIS_DELAY_US)
+ goto reschedule;
+
+ rc = power_supply_get_property(chip->batt_psy,
+ POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED, &pval);
+ if (rc < 0)
+ chip->step_chg_enable = 0;
+ else
+ chip->step_chg_enable = pval.intval;
+
+ if (!chip->step_chg_enable) {
+ if (chip->fcc_votable)
+ vote(chip->fcc_votable, STEP_CHG_VOTER, false, 0);
+ goto update_time;
+ }
+
+ rc = power_supply_get_property(chip->batt_psy,
+ step_chg_config.psy_prop, &pval);
+ if (rc < 0) {
+ pr_err("Couldn't read %s property rc=%d\n",
+ step_chg_config.prop_name, rc);
+ return rc;
+ }
+
+ rc = get_val(step_chg_config.fcc_cfg, step_chg_config.hysteresis,
+ chip->step_index,
+ pval.intval,
+ &chip->step_index,
+ &fcc_ua);
+ if (rc < 0) {
+ /* remove the vote if no step-based fcc is found */
+ if (chip->fcc_votable)
+ vote(chip->fcc_votable, STEP_CHG_VOTER, false, 0);
+ goto update_time;
+ }
+
+ if (!chip->fcc_votable)
+ chip->fcc_votable = find_votable("FCC");
+ if (!chip->fcc_votable)
+ return -EINVAL;
+
+ vote(chip->fcc_votable, STEP_CHG_VOTER, true, fcc_ua);
+
+ pr_debug("%s = %d Step-FCC = %duA\n",
+ step_chg_config.prop_name, pval.intval, fcc_ua);
+
+update_time:
+ chip->step_last_update_time = ktime_get();
+ return 0;
+
+reschedule:
+ /* reschedule 1000uS after the remaining time */
+ return (STEP_CHG_HYSTERISIS_DELAY_US - elapsed_us + 1000);
+}
+
+static int handle_jeita(struct step_chg_info *chip)
+{
+ union power_supply_propval pval = {0, };
+ int rc = 0, fcc_ua = 0, fv_uv = 0;
+ u64 elapsed_us;
+
+ if (!chip->sw_jeita_enable) {
+ if (chip->fcc_votable)
+ vote(chip->fcc_votable, JEITA_VOTER, false, 0);
+ if (chip->fv_votable)
+ vote(chip->fv_votable, JEITA_VOTER, false, 0);
+ return 0;
+ }
+
+ elapsed_us = ktime_us_delta(ktime_get(), chip->jeita_last_update_time);
+ if (elapsed_us < STEP_CHG_HYSTERISIS_DELAY_US)
+ goto reschedule;
+
+ rc = power_supply_get_property(chip->batt_psy,
+ jeita_fcc_config.psy_prop, &pval);
+ if (rc < 0) {
+ pr_err("Couldn't read %s property rc=%d\n",
+ step_chg_config.prop_name, rc);
+ return rc;
+ }
+
+ rc = get_val(jeita_fcc_config.fcc_cfg, jeita_fcc_config.hysteresis,
+ chip->jeita_fcc_index,
+ pval.intval,
+ &chip->jeita_fcc_index,
+ &fcc_ua);
+ if (rc < 0) {
+ /* remove the vote if no step-based fcc is found */
+ if (chip->fcc_votable)
+ vote(chip->fcc_votable, JEITA_VOTER, false, 0);
+ goto update_time;
+ }
+
+ if (!chip->fcc_votable)
+ chip->fcc_votable = find_votable("FCC");
+ if (!chip->fcc_votable)
+ /* changing FCC is a must */
+ return -EINVAL;
+
+ vote(chip->fcc_votable, JEITA_VOTER, true, fcc_ua);
+
+ rc = get_val(jeita_fv_config.fv_cfg, jeita_fv_config.hysteresis,
+ chip->jeita_fv_index,
+ pval.intval,
+ &chip->jeita_fv_index,
+ &fv_uv);
+ if (rc < 0) {
+ /* remove the vote if no step-based fcc is found */
+ if (chip->fv_votable)
+ vote(chip->fv_votable, JEITA_VOTER, false, 0);
+ goto update_time;
+ }
+
+ chip->fv_votable = find_votable("FV");
+ if (!chip->fv_votable)
+ goto update_time;
+
+ vote(chip->fv_votable, JEITA_VOTER, true, fv_uv);
+
+ pr_debug("%s = %d FCC = %duA FV = %duV\n",
+ step_chg_config.prop_name, pval.intval, fcc_ua, fv_uv);
+
+update_time:
+ chip->jeita_last_update_time = ktime_get();
+ return 0;
+
+reschedule:
+ /* reschedule 1000uS after the remaining time */
+ return (STEP_CHG_HYSTERISIS_DELAY_US - elapsed_us + 1000);
+}
+
+static void status_change_work(struct work_struct *work)
+{
+ struct step_chg_info *chip = container_of(work,
+ struct step_chg_info, status_change_work.work);
+ int rc = 0;
+ int reschedule_us;
+ int reschedule_jeita_work_us = 0;
+ int reschedule_step_work_us = 0;
+
+ if (!is_batt_available(chip))
+ return;
+
+ /* skip elapsed_us debounce for handling battery temperature */
+ rc = handle_jeita(chip);
+ if (rc > 0)
+ reschedule_jeita_work_us = rc;
+ else if (rc < 0)
+ pr_err("Couldn't handle sw jeita rc = %d\n", rc);
+
+ rc = handle_step_chg_config(chip);
+ if (rc > 0)
+ reschedule_step_work_us = rc;
+ if (rc < 0)
+ pr_err("Couldn't handle step rc = %d\n", rc);
+
+ reschedule_us = min(reschedule_jeita_work_us, reschedule_step_work_us);
+ if (reschedule_us == 0)
+ __pm_relax(chip->step_chg_ws);
+ else
+ schedule_delayed_work(&chip->status_change_work,
+ usecs_to_jiffies(reschedule_us));
+}
+
+static int step_chg_notifier_call(struct notifier_block *nb,
+ unsigned long ev, void *v)
+{
+ struct power_supply *psy = v;
+ struct step_chg_info *chip = container_of(nb, struct step_chg_info, nb);
+
+ if (ev != PSY_EVENT_PROP_CHANGED)
+ return NOTIFY_OK;
+
+ if ((strcmp(psy->desc->name, "battery") == 0)) {
+ __pm_stay_awake(chip->step_chg_ws);
+ schedule_delayed_work(&chip->status_change_work, 0);
+ }
+
+ return NOTIFY_OK;
+}
+
+static int step_chg_register_notifier(struct step_chg_info *chip)
+{
+ int rc;
+
+ chip->nb.notifier_call = step_chg_notifier_call;
+ rc = power_supply_reg_notifier(&chip->nb);
+ if (rc < 0) {
+ pr_err("Couldn't register psy notifier rc = %d\n", rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+int qcom_step_chg_init(bool step_chg_enable, bool sw_jeita_enable)
+{
+ int rc;
+ struct step_chg_info *chip;
+
+ if (the_chip) {
+ pr_err("Already initialized\n");
+ return -EINVAL;
+ }
+
+ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ chip->step_chg_ws = wakeup_source_register("qcom-step-chg");
+ if (!chip->step_chg_ws) {
+ rc = -EINVAL;
+ goto cleanup;
+ }
+
+ chip->step_chg_enable = step_chg_enable;
+ chip->sw_jeita_enable = sw_jeita_enable;
+
+ chip->step_index = -EINVAL;
+ chip->jeita_fcc_index = -EINVAL;
+ chip->jeita_fv_index = -EINVAL;
+
+ if (step_chg_enable && (!step_chg_config.psy_prop ||
+ !step_chg_config.prop_name)) {
+ /* fail if step-chg configuration is invalid */
+ pr_err("Step-chg configuration not defined - fail\n");
+ rc = -ENODATA;
+ goto release_wakeup_source;
+ }
+
+ if (sw_jeita_enable && (!jeita_fcc_config.psy_prop ||
+ !jeita_fcc_config.prop_name)) {
+ /* fail if step-chg configuration is invalid */
+ pr_err("Jeita TEMP configuration not defined - fail\n");
+ rc = -ENODATA;
+ goto release_wakeup_source;
+ }
+
+ if (sw_jeita_enable && (!jeita_fv_config.psy_prop ||
+ !jeita_fv_config.prop_name)) {
+ /* fail if step-chg configuration is invalid */
+ pr_err("Jeita TEMP configuration not defined - fail\n");
+ rc = -ENODATA;
+ goto release_wakeup_source;
+ }
+
+ INIT_DELAYED_WORK(&chip->status_change_work, status_change_work);
+
+ rc = step_chg_register_notifier(chip);
+ if (rc < 0) {
+ pr_err("Couldn't register psy notifier rc = %d\n", rc);
+ goto release_wakeup_source;
+ }
+
+ the_chip = chip;
+
+ if (step_chg_enable)
+ pr_info("Step charging enabled. Using %s source\n",
+ step_chg_config.prop_name);
+
+ return 0;
+
+release_wakeup_source:
+ wakeup_source_unregister(chip->step_chg_ws);
+cleanup:
+ kfree(chip);
+ return rc;
+}
+
+void qcom_step_chg_deinit(void)
+{
+ struct step_chg_info *chip = the_chip;
+
+ if (!chip)
+ return;
+
+ cancel_delayed_work_sync(&chip->status_change_work);
+ power_supply_unreg_notifier(&chip->nb);
+ wakeup_source_unregister(chip->step_chg_ws);
+ the_chip = NULL;
+ kfree(chip);
+}
diff --git a/drivers/power/supply/qcom/step-chg-jeita.h b/drivers/power/supply/qcom/step-chg-jeita.h
new file mode 100644
index 0000000..5bb2b99
--- /dev/null
+++ b/drivers/power/supply/qcom/step-chg-jeita.h
@@ -0,0 +1,17 @@
+/* Copyright (c) 2017 The Linux Foundation. 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 and
+ * only 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 __STEP_CHG_H__
+#define __STEP_CHG_H__
+int qcom_step_chg_init(bool step_chg_enable, bool sw_jeita_enable);
+void qcom_step_chg_deinit(void);
+#endif /* __STEP_CHG_H__ */
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 534a1d7..6afa0f5 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -1027,6 +1027,15 @@
LDO and switching regulators. They also provide voltage switches and
boost regulators.
+config REGULATOR_REFGEN
+ tristate "Qualcomm Technologies, Inc. REFGEN regulator driver"
+ depends on OF
+ help
+ This driver supports control of the REFGEN reference bias generator
+ block found on some Qualcomm Technologies Inc. SoCs. A REFGEN
+ it used by various PHY blocks found inside of the SoC. It supports
+ enable/disable control.
+
config REGULATOR_RPMH
tristate "Qualcomm Technologies, Inc. RPMh regulator driver"
depends on OF
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index bf30b8d..59dea6e 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -127,6 +127,7 @@
obj-$(CONFIG_REGULATOR_QPNP_LCDB) += qpnp-lcdb-regulator.o
obj-$(CONFIG_REGULATOR_QPNP_OLEDB) += qpnp-oledb-regulator.o
obj-$(CONFIG_REGULATOR_QPNP) += qpnp-regulator.o
+obj-$(CONFIG_REGULATOR_REFGEN) += refgen.o
obj-$(CONFIG_REGULATOR_RPMH) += rpmh-regulator.o
obj-$(CONFIG_REGULATOR_STUB) += stub-regulator.o
diff --git a/drivers/regulator/cpr3-regulator.c b/drivers/regulator/cpr3-regulator.c
index b1e6a3b..9510016 100644
--- a/drivers/regulator/cpr3-regulator.c
+++ b/drivers/regulator/cpr3-regulator.c
@@ -1316,6 +1316,27 @@
static int cprh_regulator_aging_adjust(struct cpr3_controller *ctrl);
/**
+ * cpr3_regulator_cprh_initialized() - checks if CPRh has already been
+ * initialized by the boot loader
+ * @ctrl: Pointer to the CPR3 controller
+ *
+ * Return: true if CPRh controller is already initialized else false
+ */
+static bool cpr3_regulator_cprh_initialized(struct cpr3_controller *ctrl)
+{
+ u32 reg;
+
+ if (ctrl->ctrl_type != CPR_CTRL_TYPE_CPRH)
+ return false;
+
+ ctrl->cpr_hw_version = readl_relaxed(ctrl->cpr_ctrl_base
+ + CPR3_REG_CPR_VERSION);
+ reg = readl_relaxed(ctrl->cpr_ctrl_base + CPRH_REG_CTL(ctrl));
+
+ return reg & CPRH_CTL_OSM_ENABLED;
+}
+
+/**
* cpr3_regulator_init_cprh() - performs hardware initialization at the
* controller and thread level required for CPRh operation.
* @ctrl: Pointer to the CPR3 controller
@@ -6459,6 +6480,11 @@
}
ctrl->cpr_ctrl_base = devm_ioremap(dev, res->start, resource_size(res));
+ if (cpr3_regulator_cprh_initialized(ctrl)) {
+ cpr3_err(ctrl, "CPRh controller already initialized by boot loader\n");
+ return -EPERM;
+ }
+
if (ctrl->aging_possible_mask) {
/*
* Aging possible register address is required if an aging
diff --git a/drivers/regulator/cprh-kbss-regulator.c b/drivers/regulator/cprh-kbss-regulator.c
index deb0ce5..c393940 100644
--- a/drivers/regulator/cprh-kbss-regulator.c
+++ b/drivers/regulator/cprh-kbss-regulator.c
@@ -38,12 +38,10 @@
#define SDM660_KBSS_FUSE_CORNERS 5
#define SDM845_KBSS_POWER_CLUSTER_FUSE_CORNERS 4
-#define SDM845_KBSS_PERFORMANCE_CLUSTER_FUSE_CORNERS 3
-/*
- * This must be set to the larger of SDM845_KBSS_POWER_CLUSTER_FUSE_CORNERS and
- * SDM845_KBSS_PERFORMANCE_CLUSTER_FUSE_CORNERS values.
- */
-#define SDM845_KBSS_MAX_FUSE_CORNERS 4
+#define SDM845_V1_KBSS_PERF_CLUSTER_FUSE_CORNERS 3
+#define SDM845_V2_KBSS_PERF_CLUSTER_FUSE_CORNERS 5
+/* This must be set to the largest of SDM845 FUSE_CORNERS values. */
+#define SDM845_KBSS_MAX_FUSE_CORNERS 5
/**
* struct cprh_kbss_fuses - KBSS specific fuse data
@@ -153,18 +151,38 @@
#define CPRH_KBSS_PERFORMANCE_CLUSTER_THREAD_ID 0
static const char * const
-cprh_sdm845_kbss_fuse_corner_name[2][SDM845_KBSS_MAX_FUSE_CORNERS] = {
+cprh_sdm845_v1_kbss_fuse_corner_name[2][SDM845_KBSS_MAX_FUSE_CORNERS] = {
[CPRH_KBSS_POWER_CLUSTER_ID] = {
"LowSVS",
"SVS_L1",
"NOM_L1",
"TURBO",
+ "",
},
[CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = {
"SVS",
"NOM",
"TURBO_L2",
"",
+ "",
+ },
+};
+
+static const char * const
+cprh_sdm845_v2_kbss_fuse_corner_name[2][SDM845_KBSS_MAX_FUSE_CORNERS] = {
+ [CPRH_KBSS_POWER_CLUSTER_ID] = {
+ "LowSVS",
+ "SVS_L1",
+ "NOM",
+ "TURBO",
+ "",
+ },
+ [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = {
+ "LowSVS",
+ "SVS",
+ "NOM_L1",
+ "TURBO_L2",
+ "BINNING",
},
};
@@ -334,7 +352,7 @@
* different fuse rows.
*/
static const struct cpr3_fuse_param
-sdm845_kbss_ro_sel_param[2][2][SDM845_KBSS_MAX_FUSE_CORNERS][3] = {
+sdm845_v1_kbss_ro_sel_param[2][2][SDM845_KBSS_MAX_FUSE_CORNERS][3] = {
[CPRH_KBSS_POWER_CLUSTER_ID] = {
[CPRH_KBSS_POWER_CLUSTER_THREAD_ID] = {
{{66, 52, 55}, {} },
@@ -359,7 +377,34 @@
};
static const struct cpr3_fuse_param
-sdm845_kbss_init_voltage_param[2][2][SDM845_KBSS_MAX_FUSE_CORNERS][3] = {
+sdm845_v2_kbss_ro_sel_param[2][2][SDM845_KBSS_MAX_FUSE_CORNERS][3] = {
+ [CPRH_KBSS_POWER_CLUSTER_ID] = {
+ [CPRH_KBSS_POWER_CLUSTER_THREAD_ID] = {
+ {{66, 52, 55}, {} },
+ {{66, 48, 51}, {} },
+ {{66, 44, 47}, {} },
+ {{66, 40, 43}, {} },
+ },
+ [CPRH_KBSS_L3_THREAD_ID] = {
+ {{66, 52, 55}, {} },
+ {{66, 48, 51}, {} },
+ {{66, 44, 47}, {} },
+ {{66, 40, 43}, {} },
+ },
+ },
+ [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = {
+ [CPRH_KBSS_PERFORMANCE_CLUSTER_THREAD_ID] = {
+ {{73, 5, 8}, {} },
+ {{70, 12, 15}, {} },
+ {{70, 8, 11}, {} },
+ {{70, 4, 7}, {} },
+ {{70, 0, 3}, {} },
+ },
+ },
+};
+
+static const struct cpr3_fuse_param
+sdm845_v1_kbss_init_voltage_param[2][2][SDM845_KBSS_MAX_FUSE_CORNERS][3] = {
[CPRH_KBSS_POWER_CLUSTER_ID] = {
[CPRH_KBSS_POWER_CLUSTER_THREAD_ID] = {
{{67, 10, 15}, {} },
@@ -384,7 +429,34 @@
};
static const struct cpr3_fuse_param
-sdm845_kbss_target_quot_param[2][2][SDM845_KBSS_MAX_FUSE_CORNERS][3] = {
+sdm845_v2_kbss_init_voltage_param[2][2][SDM845_KBSS_MAX_FUSE_CORNERS][3] = {
+ [CPRH_KBSS_POWER_CLUSTER_ID] = {
+ [CPRH_KBSS_POWER_CLUSTER_THREAD_ID] = {
+ {{67, 10, 15}, {} },
+ {{67, 4, 9}, {} },
+ {{66, 62, 63}, {67, 0, 3}, {} },
+ {{66, 56, 61}, {} },
+ },
+ [CPRH_KBSS_L3_THREAD_ID] = {
+ {{68, 50, 55}, {} },
+ {{68, 44, 49}, {} },
+ {{68, 38, 43}, {} },
+ {{68, 32, 37}, {} },
+ },
+ },
+ [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = {
+ [CPRH_KBSS_PERFORMANCE_CLUSTER_THREAD_ID] = {
+ {{72, 10, 15}, {} },
+ {{70, 34, 39}, {} },
+ {{70, 28, 33}, {} },
+ {{70, 22, 27}, {} },
+ {{70, 16, 21}, {} },
+ },
+ },
+};
+
+static const struct cpr3_fuse_param
+sdm845_v1_kbss_target_quot_param[2][2][SDM845_KBSS_MAX_FUSE_CORNERS][3] = {
[CPRH_KBSS_POWER_CLUSTER_ID] = {
[CPRH_KBSS_POWER_CLUSTER_THREAD_ID] = {
{{67, 52, 63}, {} },
@@ -409,7 +481,34 @@
};
static const struct cpr3_fuse_param
-sdm845_kbss_quot_offset_param[2][2][SDM845_KBSS_MAX_FUSE_CORNERS][2] = {
+sdm845_v2_kbss_target_quot_param[2][2][SDM845_KBSS_MAX_FUSE_CORNERS][3] = {
+ [CPRH_KBSS_POWER_CLUSTER_ID] = {
+ [CPRH_KBSS_POWER_CLUSTER_THREAD_ID] = {
+ {{67, 52, 63}, {} },
+ {{67, 40, 51}, {} },
+ {{67, 28, 39}, {} },
+ {{67, 16, 27}, {} },
+ },
+ [CPRH_KBSS_L3_THREAD_ID] = {
+ {{69, 28, 39}, {} },
+ {{69, 16, 27}, {} },
+ {{69, 4, 15}, {} },
+ {{68, 56, 63}, {69, 0, 3}, {} },
+ },
+ },
+ [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = {
+ [CPRH_KBSS_PERFORMANCE_CLUSTER_THREAD_ID] = {
+ {{72, 16, 27}, {} },
+ {{71, 12, 23}, {} },
+ {{71, 0, 11}, {} },
+ {{70, 52, 63}, {} },
+ {{70, 40, 51}, {} },
+ },
+ },
+};
+
+static const struct cpr3_fuse_param
+sdm845_v1_kbss_quot_offset_param[2][2][SDM845_KBSS_MAX_FUSE_CORNERS][2] = {
[CPRH_KBSS_POWER_CLUSTER_ID] = {
[CPRH_KBSS_POWER_CLUSTER_THREAD_ID] = {
{{} },
@@ -433,6 +532,33 @@
},
};
+static const struct cpr3_fuse_param
+sdm845_v2_kbss_quot_offset_param[2][2][SDM845_KBSS_MAX_FUSE_CORNERS][2] = {
+ [CPRH_KBSS_POWER_CLUSTER_ID] = {
+ [CPRH_KBSS_POWER_CLUSTER_THREAD_ID] = {
+ {{} },
+ {{68, 16, 23}, {} },
+ {{68, 8, 15}, {} },
+ {{68, 0, 7}, {} },
+ },
+ [CPRH_KBSS_L3_THREAD_ID] = {
+ {{} },
+ {{69, 56, 63}, {} },
+ {{69, 48, 55}, {} },
+ {{69, 40, 47}, {} },
+ },
+ },
+ [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = {
+ [CPRH_KBSS_PERFORMANCE_CLUSTER_THREAD_ID] = {
+ {{} },
+ {{72, 28, 35}, {} },
+ {{71, 40, 47}, {} },
+ {{71, 32, 39}, {} },
+ {{71, 24, 31}, {} },
+ },
+ },
+};
+
static const struct cpr3_fuse_param msm8998_cpr_fusing_rev_param[] = {
{39, 51, 53},
{},
@@ -443,11 +569,16 @@
{},
};
-static const struct cpr3_fuse_param sdm845_cpr_fusing_rev_param[] = {
+static const struct cpr3_fuse_param sdm845_v1_cpr_fusing_rev_param[] = {
{73, 3, 5},
{},
};
+static const struct cpr3_fuse_param sdm845_v2_cpr_fusing_rev_param[] = {
+ {75, 34, 36},
+ {},
+};
+
static const struct cpr3_fuse_param kbss_speed_bin_param[] = {
{38, 29, 31},
{},
@@ -490,7 +621,7 @@
};
static const struct cpr3_fuse_param
-sdm845_kbss_aging_init_quot_diff_param[2][2] = {
+sdm845_v1_kbss_aging_init_quot_diff_param[2][2] = {
[CPRH_KBSS_POWER_CLUSTER_ID] = {
{68, 21, 28},
{},
@@ -501,6 +632,18 @@
},
};
+static const struct cpr3_fuse_param
+sdm845_v2_kbss_aging_init_quot_diff_param[2][2] = {
+ [CPRH_KBSS_POWER_CLUSTER_ID] = {
+ {68, 24, 31},
+ {},
+ },
+ [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = {
+ {71, 48, 55},
+ {},
+ },
+};
+
/*
* Open loop voltage fuse reference voltages in microvolts for MSM8998 v1
*/
@@ -556,7 +699,7 @@
* Open loop voltage fuse reference voltages in microvolts for SDM845
*/
static const int
-sdm845_kbss_fuse_ref_volt[2][2][SDM845_KBSS_MAX_FUSE_CORNERS] = {
+sdm845_v1_kbss_fuse_ref_volt[2][2][SDM845_KBSS_MAX_FUSE_CORNERS] = {
[CPRH_KBSS_POWER_CLUSTER_ID] = {
[CPRH_KBSS_POWER_CLUSTER_THREAD_ID] = {
688000,
@@ -580,6 +723,33 @@
},
};
+static const int
+sdm845_v2_kbss_fuse_ref_volt[2][2][SDM845_KBSS_MAX_FUSE_CORNERS] = {
+ [CPRH_KBSS_POWER_CLUSTER_ID] = {
+ [CPRH_KBSS_POWER_CLUSTER_THREAD_ID] = {
+ 688000,
+ 812000,
+ 828000,
+ 952000,
+ },
+ [CPRH_KBSS_L3_THREAD_ID] = {
+ 688000,
+ 812000,
+ 828000,
+ 952000,
+ },
+ },
+ [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = {
+ [CPRH_KBSS_PERFORMANCE_CLUSTER_THREAD_ID] = {
+ 688000,
+ 812000,
+ 884000,
+ 1000000,
+ 1000000,
+ },
+ },
+};
+
#define CPRH_KBSS_FUSE_STEP_VOLT 10000
#define CPRH_SDM845_KBSS_FUSE_STEP_VOLT 8000
#define CPRH_KBSS_VOLTAGE_FUSE_SIZE 6
@@ -880,9 +1050,11 @@
struct cprh_kbss_fuses *fuse)
{
void __iomem *base = vreg->thread->ctrl->fuse_base;
+ bool is_v1 = (vreg->thread->ctrl->soc_revision == SDM845_V1_SOC_ID);
int i, cid, tid, rc;
- rc = cpr3_read_fuse_param(base, sdm845_cpr_fusing_rev_param,
+ rc = cpr3_read_fuse_param(base, is_v1 ? sdm845_v1_cpr_fusing_rev_param
+ : sdm845_v2_cpr_fusing_rev_param,
&fuse->cpr_fusing_rev);
if (rc) {
cpr3_err(vreg, "Unable to read CPR fusing revision fuse, rc=%d\n",
@@ -895,8 +1067,9 @@
cid = vreg->thread->ctrl->ctrl_id;
for (i = 0; i < vreg->fuse_corner_count; i++) {
- rc = cpr3_read_fuse_param(base,
- sdm845_kbss_init_voltage_param[cid][tid][i],
+ rc = cpr3_read_fuse_param(base, is_v1 ?
+ sdm845_v1_kbss_init_voltage_param[cid][tid][i] :
+ sdm845_v2_kbss_init_voltage_param[cid][tid][i],
&fuse->init_voltage[i]);
if (rc) {
cpr3_err(vreg, "Unable to read fuse-corner %d initial voltage fuse, rc=%d\n",
@@ -904,8 +1077,9 @@
return rc;
}
- rc = cpr3_read_fuse_param(base,
- sdm845_kbss_target_quot_param[cid][tid][i],
+ rc = cpr3_read_fuse_param(base, is_v1 ?
+ sdm845_v1_kbss_target_quot_param[cid][tid][i] :
+ sdm845_v2_kbss_target_quot_param[cid][tid][i],
&fuse->target_quot[i]);
if (rc) {
cpr3_err(vreg, "Unable to read fuse-corner %d target quotient fuse, rc=%d\n",
@@ -913,8 +1087,9 @@
return rc;
}
- rc = cpr3_read_fuse_param(base,
- sdm845_kbss_ro_sel_param[cid][tid][i],
+ rc = cpr3_read_fuse_param(base, is_v1 ?
+ sdm845_v1_kbss_ro_sel_param[cid][tid][i] :
+ sdm845_v2_kbss_ro_sel_param[cid][tid][i],
&fuse->ro_sel[i]);
if (rc) {
cpr3_err(vreg, "Unable to read fuse-corner %d RO select fuse, rc=%d\n",
@@ -922,8 +1097,9 @@
return rc;
}
- rc = cpr3_read_fuse_param(base,
- sdm845_kbss_quot_offset_param[cid][tid][i],
+ rc = cpr3_read_fuse_param(base, is_v1 ?
+ sdm845_v1_kbss_quot_offset_param[cid][tid][i] :
+ sdm845_v2_kbss_quot_offset_param[cid][tid][i],
&fuse->quot_offset[i]);
if (rc) {
cpr3_err(vreg, "Unable to read fuse-corner %d quotient offset fuse, rc=%d\n",
@@ -932,8 +1108,9 @@
}
}
- rc = cpr3_read_fuse_param(base,
- sdm845_kbss_aging_init_quot_diff_param[cid],
+ rc = cpr3_read_fuse_param(base, is_v1 ?
+ sdm845_v1_kbss_aging_init_quot_diff_param[cid] :
+ sdm845_v2_kbss_aging_init_quot_diff_param[cid],
&fuse->aging_init_quot_diff);
if (rc) {
cpr3_err(vreg, "Unable to read aging initial quotient difference fuse, rc=%d\n",
@@ -994,11 +1171,16 @@
fuse_corners = MSM8998_KBSS_FUSE_CORNERS;
break;
case SDM845_V1_SOC_ID:
+ fuse_corners = vreg->thread->ctrl->ctrl_id
+ == CPRH_KBSS_POWER_CLUSTER_ID
+ ? SDM845_KBSS_POWER_CLUSTER_FUSE_CORNERS
+ : SDM845_V1_KBSS_PERF_CLUSTER_FUSE_CORNERS;
+ break;
case SDM845_V2_SOC_ID:
fuse_corners = vreg->thread->ctrl->ctrl_id
== CPRH_KBSS_POWER_CLUSTER_ID
? SDM845_KBSS_POWER_CLUSTER_FUSE_CORNERS
- : SDM845_KBSS_PERFORMANCE_CLUSTER_FUSE_CORNERS;
+ : SDM845_V2_KBSS_PERF_CLUSTER_FUSE_CORNERS;
break;
default:
cpr3_err(vreg, "unsupported soc id = %d\n", soc_revision);
@@ -1156,10 +1338,14 @@
corner_name = cprh_msm8998_kbss_fuse_corner_name;
break;
case SDM845_V1_SOC_ID:
+ tid = cprh_kbss_get_thread_id(vreg->thread);
+ ref_volt = sdm845_v1_kbss_fuse_ref_volt[id][tid];
+ corner_name = cprh_sdm845_v1_kbss_fuse_corner_name[id];
+ break;
case SDM845_V2_SOC_ID:
tid = cprh_kbss_get_thread_id(vreg->thread);
- ref_volt = sdm845_kbss_fuse_ref_volt[id][tid];
- corner_name = cprh_sdm845_kbss_fuse_corner_name[id];
+ ref_volt = sdm845_v2_kbss_fuse_ref_volt[id][tid];
+ corner_name = cprh_sdm845_v2_kbss_fuse_corner_name[id];
break;
default:
cpr3_err(vreg, "unsupported soc id = %d\n", soc_revision);
@@ -1744,8 +1930,13 @@
CPRH_MSM8998_KBSS_FUSE_CORNER_TURBO_L1;
break;
case SDM845_V1_SOC_ID:
+ corner_name = cprh_sdm845_v1_kbss_fuse_corner_name[
+ vreg->thread->ctrl->ctrl_id];
+ lowest_fuse_corner = 0;
+ highest_fuse_corner = vreg->fuse_corner_count - 1;
+ break;
case SDM845_V2_SOC_ID:
- corner_name = cprh_sdm845_kbss_fuse_corner_name[
+ corner_name = cprh_sdm845_v2_kbss_fuse_corner_name[
vreg->thread->ctrl->ctrl_id];
lowest_fuse_corner = 0;
highest_fuse_corner = vreg->fuse_corner_count - 1;
diff --git a/drivers/regulator/refgen.c b/drivers/regulator/refgen.c
new file mode 100644
index 0000000..629fee0
--- /dev/null
+++ b/drivers/regulator/refgen.c
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. 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 and
+ * only 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/bitops.h>
+#include <linux/err.h>
+#include <linux/io.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/slab.h>
+#include <linux/types.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+
+#define REFGEN_REG_BIAS_EN 0x08
+#define REFGEN_BIAS_EN_MASK GENMASK(2, 0)
+#define REFGEN_BIAS_EN_ENABLE 0x7
+#define REFGEN_BIAS_EN_DISABLE 0x6
+
+#define REFGEN_REG_BG_CTRL 0x14
+#define REFGEN_BG_CTRL_MASK GENMASK(2, 0)
+#define REFGEN_BG_CTRL_ENABLE 0x6
+#define REFGEN_BG_CTRL_DISABLE 0x4
+
+struct refgen {
+ struct regulator_desc rdesc;
+ struct regulator_dev *rdev;
+ void __iomem *addr;
+};
+
+static int refgen_enable(struct regulator_dev *rdev)
+{
+ struct refgen *vreg = rdev_get_drvdata(rdev);
+
+ writel_relaxed(REFGEN_BG_CTRL_ENABLE, vreg->addr + REFGEN_REG_BG_CTRL);
+ writel_relaxed(REFGEN_BIAS_EN_ENABLE, vreg->addr + REFGEN_REG_BIAS_EN);
+
+ return 0;
+}
+
+static int refgen_disable(struct regulator_dev *rdev)
+{
+ struct refgen *vreg = rdev_get_drvdata(rdev);
+
+ writel_relaxed(REFGEN_BIAS_EN_DISABLE, vreg->addr + REFGEN_REG_BIAS_EN);
+ writel_relaxed(REFGEN_BG_CTRL_DISABLE, vreg->addr + REFGEN_REG_BG_CTRL);
+
+ return 0;
+}
+
+static int refgen_is_enabled(struct regulator_dev *rdev)
+{
+ struct refgen *vreg = rdev_get_drvdata(rdev);
+ u32 val;
+
+ val = readl_relaxed(vreg->addr + REFGEN_REG_BG_CTRL);
+ if ((val & REFGEN_BG_CTRL_MASK) != REFGEN_BG_CTRL_ENABLE)
+ return 0;
+
+ val = readl_relaxed(vreg->addr + REFGEN_REG_BIAS_EN);
+ if ((val & REFGEN_BIAS_EN_MASK) != REFGEN_BIAS_EN_ENABLE)
+ return 0;
+
+ return 1;
+}
+
+static struct regulator_ops refgen_ops = {
+ .enable = refgen_enable,
+ .disable = refgen_disable,
+ .is_enabled = refgen_is_enabled,
+};
+
+static int refgen_probe(struct platform_device *pdev)
+{
+ struct regulator_config config = {};
+ struct regulator_init_data *init_data = NULL;
+ struct device *dev = &pdev->dev;
+ struct regulator_desc *rdesc;
+ struct resource *res;
+ struct refgen *vreg;
+ int rc;
+
+ vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
+ if (!vreg)
+ return -ENOMEM;
+
+ if (!dev->of_node) {
+ dev_err(dev, "%s: device tree node missing\n", __func__);
+ return -ENODEV;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res || !res->start) {
+ dev_err(dev, "reg address is missing\n");
+ return -EINVAL;
+ }
+
+ vreg->addr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(vreg->addr)) {
+ rc = PTR_ERR(vreg->addr);
+ dev_err(dev, "ioremap failed, rc=%d\n", rc);
+ return rc;
+ }
+
+ init_data = of_get_regulator_init_data(dev, dev->of_node, &vreg->rdesc);
+ if (!init_data)
+ return -ENOMEM;
+
+ if (init_data->constraints.name == NULL) {
+ dev_err(dev, "%s: regulator-name not specified\n", __func__);
+ return -EINVAL;
+ }
+
+ if (of_get_property(dev->of_node, "parent-supply", NULL))
+ init_data->supply_regulator = "parent";
+
+ rdesc = &vreg->rdesc;
+
+ rdesc->name = "refgen";
+ rdesc->ops = &refgen_ops;
+ rdesc->id = pdev->id;
+ rdesc->owner = THIS_MODULE;
+ rdesc->type = REGULATOR_VOLTAGE;
+
+ config.dev = dev;
+ config.init_data = init_data;
+ config.driver_data = vreg;
+ config.of_node = dev->of_node;
+
+ vreg->rdev = devm_regulator_register(dev, rdesc, &config);
+ if (IS_ERR(vreg->rdev)) {
+ rc = PTR_ERR(vreg->rdev);
+ if (rc != -EPROBE_DEFER)
+ dev_err(dev, "%s: regulator register failed\n",
+ __func__);
+ return rc;
+ }
+
+ return 0;
+}
+
+static const struct of_device_id refgen_match_table[] = {
+ { .compatible = "qcom,refgen-regulator", },
+ {}
+};
+
+static struct platform_driver refgen_driver = {
+ .probe = refgen_probe,
+ .driver = {
+ .name = "qcom,refgen-regulator",
+ .owner = THIS_MODULE,
+ .of_match_table = refgen_match_table,
+ },
+};
+
+static int __init refgen_init(void)
+{
+ return platform_driver_register(&refgen_driver);
+}
+arch_initcall(refgen_init);
+
+static void __exit refgen_exit(void)
+{
+ platform_driver_unregister(&refgen_driver);
+}
+module_exit(refgen_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("refgen regulator driver");
diff --git a/drivers/regulator/rpmh-regulator.c b/drivers/regulator/rpmh-regulator.c
index 1ba8926..562b05a 100644
--- a/drivers/regulator/rpmh-regulator.c
+++ b/drivers/regulator/rpmh-regulator.c
@@ -433,6 +433,7 @@
bool sleep_set_differs = aggr_vreg->sleep_request_sent;
bool wait_for_ack = aggr_vreg->always_wait_for_ack
|| aggr_vreg->next_wait_for_ack;
+ bool resend_active = false;
int i, j, max_reg_index, rc;
enum rpmh_state state;
u32 sent_mask;
@@ -471,6 +472,12 @@
if ((req_active.reg[i] != req_sleep.reg[i])
&& (req_sleep.valid & BIT(i))) {
sleep_set_differs = true;
+ /*
+ * Resend full active set request so that
+ * all parameters are specified in the wake-only
+ * state request.
+ */
+ resend_active = !aggr_vreg->use_awake_state;
break;
}
}
@@ -523,7 +530,7 @@
if ((req_active.valid & BIT(i))
&& (!(aggr_vreg->aggr_req_active.valid & BIT(i))
|| aggr_vreg->aggr_req_active.reg[i]
- != req_active.reg[i])) {
+ != req_active.reg[i] || resend_active)) {
cmd[j].addr = aggr_vreg->addr + i * 4;
cmd[j].data = req_active.reg[i];
j++;
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index a06069b..1d57b34 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -384,11 +384,12 @@
= container_of(kref, struct scsi_target, reap_ref);
/*
- * if we get here and the target is still in the CREATED state that
+ * if we get here and the target is still in a CREATED state that
* means it was allocated but never made visible (because a scan
* turned up no LUNs), so don't call device_del() on it.
*/
- if (starget->state != STARGET_CREATED) {
+ if ((starget->state != STARGET_CREATED) &&
+ (starget->state != STARGET_CREATED_REMOVE)) {
transport_remove_device(&starget->dev);
device_del(&starget->dev);
}
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index e90a8e1..f14d95e 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -1371,11 +1371,15 @@
spin_lock_irqsave(shost->host_lock, flags);
list_for_each_entry(starget, &shost->__targets, siblings) {
if (starget->state == STARGET_DEL ||
- starget->state == STARGET_REMOVE)
+ starget->state == STARGET_REMOVE ||
+ starget->state == STARGET_CREATED_REMOVE)
continue;
if (starget->dev.parent == dev || &starget->dev == dev) {
kref_get(&starget->reap_ref);
- starget->state = STARGET_REMOVE;
+ if (starget->state == STARGET_CREATED)
+ starget->state = STARGET_CREATED_REMOVE;
+ else
+ starget->state = STARGET_REMOVE;
spin_unlock_irqrestore(shost->host_lock, flags);
__scsi_remove_target(starget);
scsi_target_reap(starget);
diff --git a/drivers/scsi/ufs/ufs-debugfs.c b/drivers/scsi/ufs/ufs-debugfs.c
index 5a578f1..557ca19 100644
--- a/drivers/scsi/ufs/ufs-debugfs.c
+++ b/drivers/scsi/ufs/ufs-debugfs.c
@@ -1469,6 +1469,11 @@
hba->debugfs_files.err_occurred = true;
}
+void ufsdbg_clr_err_state(struct ufs_hba *hba)
+{
+ hba->debugfs_files.err_occurred = false;
+}
+
DEFINE_SIMPLE_ATTRIBUTE(ufsdbg_err_state,
ufsdbg_read_err_state,
ufsdbg_clear_err_state,
diff --git a/drivers/scsi/ufs/ufs-debugfs.h b/drivers/scsi/ufs/ufs-debugfs.h
index 13848e8..8ae5eb4 100644
--- a/drivers/scsi/ufs/ufs-debugfs.h
+++ b/drivers/scsi/ufs/ufs-debugfs.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2017, The Linux Foundation. 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 and
@@ -38,6 +38,7 @@
void ufsdbg_pr_buf_to_std(struct ufs_hba *hba, int offset, int num_regs,
char *str, void *priv);
void ufsdbg_set_err_state(struct ufs_hba *hba);
+void ufsdbg_clr_err_state(struct ufs_hba *hba);
#else
static inline void ufsdbg_add_debugfs(struct ufs_hba *hba)
{
@@ -52,6 +53,9 @@
void ufsdbg_set_err_state(struct ufs_hba *hba)
{
}
+void ufsdbg_clr_err_state(struct ufs_hba *hba)
+{
+}
#endif
#ifdef CONFIG_UFS_FAULT_INJECTION
diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index f85a67d..0ae51b9 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -65,6 +65,9 @@
#define UFS_MAX_LUNS (SCSI_W_LUN_BASE + UFS_UPIU_MAX_UNIT_NUM_ID)
#define UFS_UPIU_WLUN_ID (1 << 7)
#define UFS_UPIU_MAX_GENERAL_LUN 8
+#define UFS_MAX_WLUS 4
+#define UFS_MAX_LUS (UFS_UPIU_MAX_GENERAL_LUN + UFS_MAX_WLUS)
+
#define QUERY_DESC_IDN_CONFIGURATION QUERY_DESC_IDN_CONFIGURAION
/* Well known logical unit id in LUN field of UPIU */
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 370e092..c132dbc 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -331,6 +331,26 @@
return ufs_pm_lvl_states[lvl].link_state;
}
+static inline void ufshcd_set_card_online(struct ufs_hba *hba)
+{
+ atomic_set(&hba->card_state, UFS_CARD_STATE_ONLINE);
+}
+
+static inline void ufshcd_set_card_offline(struct ufs_hba *hba)
+{
+ atomic_set(&hba->card_state, UFS_CARD_STATE_OFFLINE);
+}
+
+static inline bool ufshcd_is_card_online(struct ufs_hba *hba)
+{
+ return (atomic_read(&hba->card_state) == UFS_CARD_STATE_ONLINE);
+}
+
+static inline bool ufshcd_is_card_offline(struct ufs_hba *hba)
+{
+ return (atomic_read(&hba->card_state) == UFS_CARD_STATE_OFFLINE);
+}
+
static inline enum ufs_pm_level
ufs_get_desired_pm_lvl_for_dev_link_state(enum ufs_dev_pwr_mode dev_state,
enum uic_link_state link_state)
@@ -384,6 +404,7 @@
unsigned long *freq, u32 flags);
static int ufshcd_devfreq_get_dev_status(struct device *dev,
struct devfreq_dev_status *stat);
+static void __ufshcd_shutdown_clkscaling(struct ufs_hba *hba);
#if IS_ENABLED(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND)
static struct devfreq_simple_ondemand_data ufshcd_ondemand_data = {
@@ -1487,7 +1508,7 @@
hba->clk_gating.state = REQ_CLKS_ON;
trace_ufshcd_clk_gating(dev_name(hba->dev),
hba->clk_gating.state);
- queue_work(hba->clk_gating.ungating_workq,
+ queue_work(hba->clk_gating.clk_gating_workq,
&hba->clk_gating.ungate_work);
/*
* fall through to check if we should wait for this
@@ -1755,7 +1776,8 @@
struct ufs_hba *hba = container_of(timer, struct ufs_hba,
clk_gating.gate_hrtimer);
- schedule_work(&hba->clk_gating.gate_work);
+ queue_work(hba->clk_gating.clk_gating_workq,
+ &hba->clk_gating.gate_work);
return HRTIMER_NORESTART;
}
@@ -1763,7 +1785,7 @@
static void ufshcd_init_clk_gating(struct ufs_hba *hba)
{
struct ufs_clk_gating *gating = &hba->clk_gating;
- char wq_name[sizeof("ufs_clk_ungating_00")];
+ char wq_name[sizeof("ufs_clk_gating_00")];
hba->clk_gating.state = CLKS_ON;
@@ -1792,9 +1814,10 @@
hrtimer_init(&gating->gate_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
gating->gate_hrtimer.function = ufshcd_clkgate_hrtimer_handler;
- snprintf(wq_name, ARRAY_SIZE(wq_name), "ufs_clk_ungating_%d",
+ snprintf(wq_name, ARRAY_SIZE(wq_name), "ufs_clk_gating_%d",
hba->host->host_no);
- hba->clk_gating.ungating_workq = create_singlethread_workqueue(wq_name);
+ hba->clk_gating.clk_gating_workq =
+ create_singlethread_workqueue(wq_name);
gating->is_enabled = true;
@@ -1858,7 +1881,7 @@
device_remove_file(hba->dev, &hba->clk_gating.enable_attr);
ufshcd_cancel_gate_work(hba);
cancel_work_sync(&hba->clk_gating.ungate_work);
- destroy_workqueue(hba->clk_gating.ungating_workq);
+ destroy_workqueue(hba->clk_gating.clk_gating_workq);
}
static void ufshcd_set_auto_hibern8_timer(struct ufs_hba *hba, u32 delay)
@@ -2981,6 +3004,12 @@
has_read_lock = true;
}
+ /*
+ * err might be non-zero here but logic later in this function
+ * assumes that err is set to 0.
+ */
+ err = 0;
+
spin_lock_irqsave(hba->host->host_lock, flags);
/* if error handling is in progress, return host busy */
@@ -2989,6 +3018,12 @@
goto out_unlock;
}
+ if (hba->extcon && ufshcd_is_card_offline(hba)) {
+ set_host_byte(cmd, DID_BAD_TARGET);
+ cmd->scsi_done(cmd);
+ goto out_unlock;
+ }
+
switch (hba->ufshcd_state) {
case UFSHCD_STATE_OPERATIONAL:
break;
@@ -5150,6 +5185,14 @@
out:
if (ret)
dev_err(hba->dev, "link startup failed %d\n", ret);
+ /*
+ * For some external cards, link startup succeeds only after few link
+ * startup attempts and err_state may get set in this case.
+ * But as the link startup has finally succeded, we are clearing the
+ * error state.
+ */
+ else if (hba->extcon)
+ ufsdbg_clr_err_state(hba);
return ret;
}
@@ -5594,8 +5637,15 @@
__func__, (intr_status & UIC_HIBERNATE_ENTER) ?
"Enter" : "Exit",
intr_status, ufshcd_get_upmcrs(hba));
- __ufshcd_print_host_regs(hba, true);
- ufshcd_print_host_state(hba);
+ /*
+ * It is possible to see auto-h8 errors during card
+ * removal, so set this flag and let the error handler
+ * decide if this error is seen while card was present
+ * or due to card removal.
+ * If error is seen during card removal, we don't want
+ * to printout the debug messages.
+ */
+ hba->auto_h8_err = true;
schedule_work(&hba->eh_work);
retval = IRQ_HANDLED;
}
@@ -6195,6 +6245,32 @@
hba = container_of(work, struct ufs_hba, eh_work);
spin_lock_irqsave(hba->host->host_lock, flags);
+ if (hba->extcon) {
+ if (ufshcd_is_card_online(hba)) {
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+ /*
+ * TODO: need better way to ensure that this delay is
+ * more than extcon's debounce-ms
+ */
+ msleep(300);
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ }
+
+ /*
+ * ignore error if card was online and offline/removed now or
+ * card was already offline.
+ */
+ if (ufshcd_is_card_offline(hba)) {
+ hba->saved_err = 0;
+ hba->saved_uic_err = 0;
+ hba->saved_ce_err = 0;
+ hba->auto_h8_err = false;
+ hba->force_host_reset = false;
+ hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL;
+ goto out;
+ }
+ }
+
ufsdbg_set_err_state(hba);
if (hba->ufshcd_state == UFSHCD_STATE_RESET)
@@ -6239,7 +6315,8 @@
* Dump controller state before resetting. Transfer requests state
* will be dump as part of the request completion.
*/
- if (hba->saved_err & (INT_FATAL_ERRORS | UIC_ERROR)) {
+ if ((hba->saved_err & (INT_FATAL_ERRORS | UIC_ERROR)) ||
+ hba->auto_h8_err) {
dev_err(hba->dev, "%s: saved_err 0x%x saved_uic_err 0x%x",
__func__, hba->saved_err, hba->saved_uic_err);
if (!hba->silence_err_logs) {
@@ -6252,6 +6329,7 @@
ufshcd_print_cmd_log(hba);
spin_lock_irqsave(hba->host->host_lock, flags);
}
+ hba->auto_h8_err = false;
}
if ((hba->saved_err & INT_FATAL_ERRORS)
@@ -6490,7 +6568,10 @@
queue_eh_work = true;
}
- if (queue_eh_work) {
+ if (hba->extcon && ufshcd_is_card_offline(hba)) {
+ /* ignore UIC errors if card is offline */
+ retval |= IRQ_HANDLED;
+ } else if (queue_eh_work) {
/*
* update the transfer error masks to sticky bits, let's do this
* irrespective of current ufshcd_state.
@@ -7836,6 +7917,13 @@
if (ret) {
ufshcd_set_ufs_dev_poweroff(hba);
ufshcd_set_link_off(hba);
+ if (hba->extcon) {
+ if (!ufshcd_is_card_online(hba))
+ ufsdbg_clr_err_state(hba);
+ ufshcd_set_card_offline(hba);
+ }
+ } else if (hba->extcon) {
+ ufshcd_set_card_online(hba);
}
/*
@@ -7851,22 +7939,60 @@
return ret;
}
+static void ufshcd_remove_device(struct ufs_hba *hba)
+{
+ struct scsi_device *sdev;
+ struct scsi_device *sdev_cache[UFS_MAX_LUS];
+ int sdev_count = 0, i;
+ unsigned long flags;
+
+ ufshcd_hold_all(hba);
+ /* Reset the host controller */
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ hba->silence_err_logs = true;
+ ufshcd_hba_stop(hba, false);
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+ ufshcd_set_ufs_dev_poweroff(hba);
+ ufshcd_set_link_off(hba);
+ __ufshcd_shutdown_clkscaling(hba);
+
+ /* Complete requests that have door-bell cleared by h/w */
+ ufshcd_complete_requests(hba);
+
+ /* remove all scsi devices */
+ list_for_each_entry(sdev, &hba->host->__devices, siblings) {
+ if (sdev_count < UFS_MAX_LUS) {
+ sdev_cache[sdev_count] = sdev;
+ sdev_count++;
+ }
+ }
+
+ for (i = 0; i < sdev_count; i++)
+ scsi_remove_device(sdev_cache[i]);
+
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ hba->silence_err_logs = false;
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+ ufshcd_release_all(hba);
+}
+
static void ufshcd_card_detect_handler(struct work_struct *work)
{
struct ufs_hba *hba;
hba = container_of(work, struct ufs_hba, card_detect_work);
- if (hba->card_detect_event &&
- (hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL)) {
- dev_dbg(hba->dev, "%s: card detect notification received\n",
- __func__);
+
+ if (ufshcd_is_card_online(hba) && !hba->sdev_ufs_device) {
pm_runtime_get_sync(hba->dev);
ufshcd_detect_device(hba);
+ /* ufshcd_probe_hba() calls pm_runtime_put_sync() on exit */
+ } else if (ufshcd_is_card_offline(hba) && hba->sdev_ufs_device) {
+ pm_runtime_get_sync(hba->dev);
+ ufshcd_remove_device(hba);
pm_runtime_put_sync(hba->dev);
- } else {
- dev_dbg(hba->dev, "%s: card removed notification received\n",
- __func__);
- /* TODO: remove the scsi device instances */
+ ufsdbg_clr_err_state(hba);
}
}
@@ -7875,9 +8001,23 @@
{
struct ufs_hba *hba = container_of(nb, struct ufs_hba, card_detect_nb);
- hba->card_detect_event = event;
- schedule_work(&hba->card_detect_work);
+ if (event)
+ ufshcd_set_card_online(hba);
+ else
+ ufshcd_set_card_offline(hba);
+ if (ufshcd_is_card_offline(hba) && !hba->sdev_ufs_device)
+ goto out;
+
+ /*
+ * card insertion/removal are very infrequent events and having this
+ * message helps if there is some issue with card detection/removal.
+ */
+ dev_info(hba->dev, "%s: card %s notification rcvd\n",
+ __func__, ufshcd_is_card_online(hba) ? "inserted" : "removed");
+
+ schedule_work(&hba->card_detect_work);
+out:
return NOTIFY_DONE;
}
@@ -9156,7 +9296,9 @@
if (ret)
goto disable_vreg;
- if (ufshcd_is_link_off(hba))
+ if (hba->extcon &&
+ (ufshcd_is_card_offline(hba) ||
+ (ufshcd_is_card_online(hba) && !hba->sdev_ufs_device)))
goto skip_dev_ops;
if (ufshcd_is_link_hibern8(hba)) {
@@ -9515,7 +9657,7 @@
ufshcd_add_spm_lvl_sysfs_nodes(hba);
}
-static void ufshcd_shutdown_clkscaling(struct ufs_hba *hba)
+static void __ufshcd_shutdown_clkscaling(struct ufs_hba *hba)
{
bool suspend = false;
unsigned long flags;
@@ -9532,7 +9674,6 @@
* doesn't race with shutdown
*/
if (ufshcd_is_clkscaling_supported(hba)) {
- device_remove_file(hba->dev, &hba->clk_scaling.enable_attr);
cancel_work_sync(&hba->clk_scaling.suspend_work);
cancel_work_sync(&hba->clk_scaling.resume_work);
if (suspend)
@@ -9540,8 +9681,16 @@
}
/* Unregister so that devfreq_monitor can't race with shutdown */
- if (hba->devfreq)
+ if (hba->devfreq) {
devfreq_remove_device(hba->devfreq);
+ hba->devfreq = NULL;
+ }
+}
+
+static void ufshcd_shutdown_clkscaling(struct ufs_hba *hba)
+{
+ __ufshcd_shutdown_clkscaling(hba);
+ device_remove_file(hba->dev, &hba->clk_scaling.enable_attr);
}
/**
@@ -9876,6 +10025,9 @@
{
int ret = 0;
+ if (hba->extcon && ufshcd_is_card_offline(hba))
+ return 0;
+
/* let's not get into low power until clock scaling is completed */
hba->ufs_stats.clk_hold.ctx = CLK_SCALE_WORK;
ufshcd_hold_all(hba);
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 343f327..fc855db 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -446,7 +446,7 @@
struct device_attribute enable_attr;
bool is_enabled;
int active_reqs;
- struct workqueue_struct *ungating_workq;
+ struct workqueue_struct *clk_gating_workq;
};
/* Hibern8 state */
@@ -688,6 +688,13 @@
u32 seq_num;
};
+/* UFS card state - hotplug state */
+enum ufshcd_card_state {
+ UFS_CARD_STATE_UNKNOWN = 0,
+ UFS_CARD_STATE_ONLINE = 1,
+ UFS_CARD_STATE_OFFLINE = 2,
+};
+
/**
* struct ufs_hba - per adapter private structure
* @mmio_base: UFSHCI base register address
@@ -737,7 +744,7 @@
* @extcon: pointer to external connector device
* @card_detect_nb: card detector notifier registered with @extcon
* @card_detect_work: work to exectute the card detect function
- * @card_detect_event: card detect event, 0 = removed, 1 = inserted
+ * @card_state: card state event, enum ufshcd_card_state defines possible states
* @vreg_info: UFS device voltage regulator information
* @clk_list_head: UFS host controller clocks list node head
* @pwr_info: holds current power mode
@@ -875,6 +882,7 @@
u32 saved_ce_err;
bool silence_err_logs;
bool force_host_reset;
+ bool auto_h8_err;
/* Device management request data */
struct ufs_dev_cmd dev_cmd;
@@ -914,7 +922,7 @@
struct extcon_dev *extcon;
struct notifier_block card_detect_nb;
struct work_struct card_detect_work;
- unsigned long card_detect_event;
+ atomic_t card_state;
struct ufs_pa_layer_attr pwr_info;
struct ufs_pwr_mode_info max_pwr_info;
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 5be06ba..38eff96 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -752,3 +752,10 @@
to Alway On processor using QMP transport.
source "drivers/soc/qcom/memshare/Kconfig"
+
+config QSEE_IPC_IRQ_BRIDGE
+ tristate "QSEE IPC Interrupt Bridge"
+ help
+ This module enables bridging an Inter-Processor Communication(IPC)
+ interrupt from a remote subsystem directed towards Qualcomm
+ Technologies, Inc. Secure Execution Environment(QSEE).
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 9736cdc..2d7d62a 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -79,3 +79,4 @@
obj-$(CONFIG_QTI_RPM_STATS_LOG) += rpm_stats.o
obj-$(CONFIG_QCOM_SMCINVOKE) += smcinvoke.o
obj-$(CONFIG_QMP_DEBUGFS_CLIENT) += qmp-debugfs-client.o
+obj-$(CONFIG_QSEE_IPC_IRQ_BRIDGE) += qsee_ipc_irq_bridge.o
diff --git a/drivers/soc/qcom/early_random.c b/drivers/soc/qcom/early_random.c
index 06601dd..641f70e 100644
--- a/drivers/soc/qcom/early_random.c
+++ b/drivers/soc/qcom/early_random.c
@@ -38,6 +38,7 @@
int ret;
u32 resp;
struct scm_desc desc;
+ u64 bytes_received;
data.out_buf = (uint8_t *) virt_to_phys(random_buffer);
desc.args[0] = (unsigned long) data.out_buf;
@@ -46,18 +47,18 @@
dmac_flush_range(random_buffer, random_buffer + RANDOM_BUFFER_SIZE);
- if (!is_scm_armv8())
+ if (!is_scm_armv8()) {
ret = scm_call_noalloc(TZ_SVC_CRYPTO, PRNG_CMD_ID, &data,
sizeof(data), &resp, sizeof(resp),
common_scm_buf,
SCM_BUFFER_SIZE(common_scm_buf));
- else
+ bytes_received = resp;
+ } else {
ret = scm_call2(SCM_SIP_FNID(TZ_SVC_CRYPTO, PRNG_CMD_ID),
&desc);
-
+ bytes_received = desc.ret[0];
+ }
if (!ret) {
- u64 bytes_received = desc.ret[0];
-
if (bytes_received != SZ_512)
pr_warn("Did not receive the expected number of bytes from PRNG: %llu\n",
bytes_received);
diff --git a/drivers/soc/qcom/eud.c b/drivers/soc/qcom/eud.c
index 92dbd48..51c08c6 100644
--- a/drivers/soc/qcom/eud.c
+++ b/drivers/soc/qcom/eud.c
@@ -70,6 +70,7 @@
struct extcon_dev *extcon;
struct uart_port port;
struct work_struct eud_work;
+ struct power_supply *batt_psy;
};
static const unsigned int eud_extcon_cable[] = {
@@ -176,17 +177,33 @@
module_param_cb(enable, &eud_param_ops, &enable, 0644);
+static bool is_batt_available(struct eud_chip *chip)
+{
+ if (!chip->batt_psy)
+ chip->batt_psy = power_supply_get_by_name("battery");
+
+ if (!chip->batt_psy)
+ return false;
+
+ return true;
+}
+
static void eud_event_notifier(struct work_struct *eud_work)
{
struct eud_chip *chip = container_of(eud_work, struct eud_chip,
eud_work);
+ union power_supply_propval pval;
if (chip->int_status == EUD_INT_VBUS)
extcon_set_state_sync(chip->extcon, chip->extcon_id,
chip->usb_attach);
- else if (chip->int_status == EUD_INT_CHGR)
- extcon_set_state_sync(chip->extcon, chip->extcon_id,
- chip->chgr_enable);
+ else if (chip->int_status == EUD_INT_CHGR) {
+ if (is_batt_available(chip)) {
+ pval.intval = !chip->chgr_enable;
+ power_supply_set_property(chip->batt_psy,
+ POWER_SUPPLY_PROP_INPUT_SUSPEND, &pval);
+ }
+ }
}
static void usb_attach_detach(struct eud_chip *chip)
diff --git a/drivers/soc/qcom/glink.c b/drivers/soc/qcom/glink.c
index d31bf8d..1d605e3 100644
--- a/drivers/soc/qcom/glink.c
+++ b/drivers/soc/qcom/glink.c
@@ -30,7 +30,6 @@
#include "glink_private.h"
#include "glink_xprt_if.h"
-#define GLINK_CTX_CANARY 0x58544324 /* "$CTX" */
/* Number of internal IPC Logging log pages */
#define NUM_LOG_PAGES 10
#define GLINK_PM_QOS_HOLDOFF_MS 10
@@ -40,7 +39,6 @@
#define GLINK_KTHREAD_PRIO 1
-static rwlock_t magic_lock;
/**
* struct glink_qos_priority_bin - Packet Scheduler's priority bucket
* @max_rate_kBps: Maximum rate supported by the priority bucket.
@@ -232,6 +230,8 @@
* @req_rate_kBps: Current QoS request by the channel.
* @tx_intent_cnt: Intent count to transmit soon in future.
* @tx_cnt: Packets to be picked by tx scheduler.
+ * @rt_vote_on: Number of times RT vote on is called.
+ * @rt_vote_off: Number of times RT vote off is called.
*/
struct channel_ctx {
struct rwref_lock ch_state_lhb2;
@@ -312,7 +312,9 @@
unsigned long req_rate_kBps;
uint32_t tx_intent_cnt;
uint32_t tx_cnt;
- uint32_t magic_number;
+
+ uint32_t rt_vote_on;
+ uint32_t rt_vote_off;
};
static struct glink_core_if core_impl;
@@ -443,33 +445,15 @@
static int glink_get_ch_ctx(struct channel_ctx *ctx)
{
- unsigned long flags;
-
if (!ctx)
return -EINVAL;
- read_lock_irqsave(&magic_lock, flags);
- if (ctx->magic_number != GLINK_CTX_CANARY) {
- read_unlock_irqrestore(&magic_lock, flags);
- return -EINVAL;
- }
rwref_get(&ctx->ch_state_lhb2);
- read_unlock_irqrestore(&magic_lock, flags);
return 0;
}
-static int glink_put_ch_ctx(struct channel_ctx *ctx, bool update_magic)
+static void glink_put_ch_ctx(struct channel_ctx *ctx)
{
- unsigned long flags;
-
- if (!update_magic) {
- rwref_put(&ctx->ch_state_lhb2);
- return 0;
- }
- write_lock_irqsave(&magic_lock, flags);
- ctx->magic_number = 0;
rwref_put(&ctx->ch_state_lhb2);
- write_unlock_irqrestore(&magic_lock, flags);
- return 0;
}
/**
@@ -1931,13 +1915,13 @@
}
ctx->transport_ptr = xprt_ctx;
+ rwref_get(&ctx->ch_state_lhb2);
list_add_tail(&ctx->port_list_node, &xprt_ctx->channels);
GLINK_INFO_PERF_CH_XPRT(ctx, xprt_ctx,
"%s: local:GLINK_CHANNEL_CLOSED\n",
__func__);
}
- rwref_get(&ctx->ch_state_lhb2);
spin_unlock_irqrestore(&xprt_ctx->xprt_ctx_lock_lhb1, flags);
rwref_write_put(&xprt_ctx->xprt_state_lhb0);
mutex_lock(&xprt_ctx->xprt_dbgfs_lock_lhb4);
@@ -2419,6 +2403,25 @@
}
/**
+ * dummy_rx_rt_vote() - Dummy RX Realtime thread vote
+ * @if_ptr: The transport to transmit on.
+
+ */
+static int dummy_rx_rt_vote(struct glink_transport_if *if_ptr)
+{
+ return -EOPNOTSUPP;
+}
+
+/**
+ * dummy_rx_rt_unvote() - Dummy RX Realtime thread unvote
+ * @if_ptr: The transport to transmit on.
+ */
+static int dummy_rx_rt_unvote(struct glink_transport_if *if_ptr)
+{
+ return -EOPNOTSUPP;
+}
+
+/**
* notif_if_up_all_xprts() - Check and notify existing transport state if up
* @notif_info: Data structure containing transport information to be notified.
*
@@ -2600,7 +2603,6 @@
ctx->notify_tx_abort = cfg->notify_tx_abort;
ctx->notify_rx_tracer_pkt = cfg->notify_rx_tracer_pkt;
ctx->notify_remote_rx_intent = cfg->notify_remote_rx_intent;
- ctx->magic_number = GLINK_CTX_CANARY;
if (!ctx->notify_rx_intent_req)
ctx->notify_rx_intent_req = glink_dummy_notify_rx_intent_req;
@@ -2742,13 +2744,13 @@
GLINK_INFO_CH(ctx, "%s: Closing channel, ctx: %p\n", __func__, ctx);
if (ctx->local_open_state == GLINK_CHANNEL_CLOSED) {
- glink_put_ch_ctx(ctx, false);
+ glink_put_ch_ctx(ctx);
return 0;
}
if (ctx->local_open_state == GLINK_CHANNEL_CLOSING) {
/* close already pending */
- glink_put_ch_ctx(ctx, false);
+ glink_put_ch_ctx(ctx);
return -EBUSY;
}
@@ -2813,7 +2815,7 @@
rwref_put(&ctx->ch_state_lhb2);
rwref_read_put(&xprt_ctx->xprt_state_lhb0);
- glink_put_ch_ctx(ctx, true);
+ glink_put_ch_ctx(ctx);
return ret;
}
EXPORT_SYMBOL(glink_close);
@@ -3029,13 +3031,13 @@
xprt_schedule_tx(ctx->transport_ptr, ctx, tx_info);
rwref_read_put(&ctx->ch_state_lhb2);
- glink_put_ch_ctx(ctx, false);
+ glink_put_ch_ctx(ctx);
return ret;
glink_tx_common_err:
rwref_read_put(&ctx->ch_state_lhb2);
glink_tx_common_err_2:
- glink_put_ch_ctx(ctx, false);
+ glink_put_ch_ctx(ctx);
kfree(tx_info);
return ret;
}
@@ -3085,7 +3087,7 @@
/* Can only queue rx intents if channel is fully opened */
GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n",
__func__);
- glink_put_ch_ctx(ctx, false);
+ glink_put_ch_ctx(ctx);
return -EBUSY;
}
@@ -3094,14 +3096,14 @@
GLINK_ERR_CH(ctx,
"%s: Intent pointer allocation failed size[%zu]\n",
__func__, size);
- glink_put_ch_ctx(ctx, false);
+ glink_put_ch_ctx(ctx);
return -ENOMEM;
}
GLINK_DBG_CH(ctx, "%s: L[%u]:%zu\n", __func__, intent_ptr->id,
intent_ptr->intent_size);
if (ctx->transport_ptr->capabilities & GCAP_INTENTLESS) {
- glink_put_ch_ctx(ctx, false);
+ glink_put_ch_ctx(ctx);
return ret;
}
@@ -3111,7 +3113,7 @@
if (ret)
/* unable to transmit, dequeue intent */
ch_remove_local_rx_intent(ctx, intent_ptr->id);
- glink_put_ch_ctx(ctx, false);
+ glink_put_ch_ctx(ctx);
return ret;
}
EXPORT_SYMBOL(glink_queue_rx_intent);
@@ -3143,12 +3145,12 @@
if (size <= intent->intent_size) {
spin_unlock_irqrestore(
&ctx->local_rx_intent_lst_lock_lhc1, flags);
- glink_put_ch_ctx(ctx, false);
+ glink_put_ch_ctx(ctx);
return true;
}
}
spin_unlock_irqrestore(&ctx->local_rx_intent_lst_lock_lhc1, flags);
- glink_put_ch_ctx(ctx, false);
+ glink_put_ch_ctx(ctx);
return false;
}
EXPORT_SYMBOL(glink_rx_intent_exists);
@@ -3177,7 +3179,7 @@
if (IS_ERR_OR_NULL(liid_ptr)) {
/* invalid pointer */
GLINK_ERR_CH(ctx, "%s: Invalid pointer %p\n", __func__, ptr);
- glink_put_ch_ctx(ctx, false);
+ glink_put_ch_ctx(ctx);
return -EINVAL;
}
@@ -3203,7 +3205,7 @@
/* send rx done */
ctx->transport_ptr->ops->tx_cmd_local_rx_done(ctx->transport_ptr->ops,
ctx->lcid, id, reuse);
- glink_put_ch_ctx(ctx, false);
+ glink_put_ch_ctx(ctx);
return ret;
}
EXPORT_SYMBOL(glink_rx_done);
@@ -3257,7 +3259,7 @@
if (!ch_is_fully_opened(ctx)) {
GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n",
__func__);
- glink_put_ch_ctx(ctx, false);
+ glink_put_ch_ctx(ctx);
return -EBUSY;
}
@@ -3267,7 +3269,7 @@
ctx->lcid, ctx->lsigs);
GLINK_INFO_CH(ctx, "%s: Sent SIGNAL SET command\n", __func__);
- glink_put_ch_ctx(ctx, false);
+ glink_put_ch_ctx(ctx);
return ret;
}
EXPORT_SYMBOL(glink_sigs_set);
@@ -3293,12 +3295,12 @@
if (!ch_is_fully_opened(ctx)) {
GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n",
__func__);
- glink_put_ch_ctx(ctx, false);
+ glink_put_ch_ctx(ctx);
return -EBUSY;
}
*sigs = ctx->lsigs;
- glink_put_ch_ctx(ctx, false);
+ glink_put_ch_ctx(ctx);
return 0;
}
EXPORT_SYMBOL(glink_sigs_local_get);
@@ -3325,12 +3327,12 @@
if (!ch_is_fully_opened(ctx)) {
GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n",
__func__);
- glink_put_ch_ctx(ctx, false);
+ glink_put_ch_ctx(ctx);
return -EBUSY;
}
*sigs = ctx->rsigs;
- glink_put_ch_ctx(ctx, false);
+ glink_put_ch_ctx(ctx);
return 0;
}
EXPORT_SYMBOL(glink_sigs_remote_get);
@@ -3434,7 +3436,7 @@
if (!ch_is_fully_opened(ctx)) {
GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n",
__func__);
- glink_put_ch_ctx(ctx, false);
+ glink_put_ch_ctx(ctx);
return -EBUSY;
}
@@ -3444,7 +3446,7 @@
if (ret < 0)
GLINK_ERR_CH(ctx, "%s: QoS %lu:%zu cannot be met\n",
__func__, latency_us, pkt_size);
- glink_put_ch_ctx(ctx, false);
+ glink_put_ch_ctx(ctx);
return ret;
}
EXPORT_SYMBOL(glink_qos_latency);
@@ -3468,12 +3470,12 @@
if (!ch_is_fully_opened(ctx)) {
GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n",
__func__);
- glink_put_ch_ctx(ctx, false);
+ glink_put_ch_ctx(ctx);
return -EBUSY;
}
ret = glink_qos_reset_priority(ctx);
- glink_put_ch_ctx(ctx, false);
+ glink_put_ch_ctx(ctx);
return ret;
}
EXPORT_SYMBOL(glink_qos_cancel);
@@ -3500,7 +3502,7 @@
if (!ch_is_fully_opened(ctx)) {
GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n",
__func__);
- glink_put_ch_ctx(ctx, false);
+ glink_put_ch_ctx(ctx);
return -EBUSY;
}
@@ -3509,7 +3511,7 @@
ret = glink_qos_add_ch_tx_intent(ctx);
spin_unlock(&ctx->tx_lists_lock_lhc3);
spin_unlock_irqrestore(&ctx->transport_ptr->tx_ready_lock_lhb3, flags);
- glink_put_ch_ctx(ctx, false);
+ glink_put_ch_ctx(ctx);
return ret;
}
EXPORT_SYMBOL(glink_qos_start);
@@ -3537,11 +3539,11 @@
if (!ch_is_fully_opened(ctx)) {
GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n",
__func__);
- glink_put_ch_ctx(ctx, false);
+ glink_put_ch_ctx(ctx);
return (unsigned long)-EBUSY;
}
- glink_put_ch_ctx(ctx, false);
+ glink_put_ch_ctx(ctx);
return ctx->transport_ptr->ops->get_power_vote_ramp_time(
ctx->transport_ptr->ops,
glink_prio_to_power_state(ctx->transport_ptr,
@@ -3549,6 +3551,61 @@
}
EXPORT_SYMBOL(glink_qos_get_ramp_time);
+
+/**
+ * glink_start_rx_rt() - Vote for RT thread priority on RX.
+ * @handle: Channel handle for which transaction are occurring.
+ *
+ * Return: 0 on success, standard Linux error codes on failure
+ */
+int glink_start_rx_rt(void *handle)
+{
+ struct channel_ctx *ctx = (struct channel_ctx *)handle;
+ int ret;
+
+ ret = glink_get_ch_ctx(ctx);
+ if (ret)
+ return ret;
+ if (!ch_is_fully_opened(ctx)) {
+ GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n",
+ __func__);
+ glink_put_ch_ctx(ctx);
+ return -EBUSY;
+ }
+ ret = ctx->transport_ptr->ops->rx_rt_vote(ctx->transport_ptr->ops);
+ ctx->rt_vote_on++;
+ GLINK_INFO_CH(ctx, "%s: Voting RX Realtime Thread %d", __func__, ret);
+ glink_put_ch_ctx(ctx);
+ return ret;
+}
+
+/**
+ * glink_end_rx_rt() - Vote for RT thread priority on RX.
+ * @handle: Channel handle for which transaction are occurring.
+ *
+ * Return: 0 on success, standard Linux error codes on failure
+ */
+int glink_end_rx_rt(void *handle)
+{
+ struct channel_ctx *ctx = (struct channel_ctx *)handle;
+ int ret;
+
+ ret = glink_get_ch_ctx(ctx);
+ if (ret)
+ return ret;
+ if (!ch_is_fully_opened(ctx)) {
+ GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n",
+ __func__);
+ glink_put_ch_ctx(ctx);
+ return -EBUSY;
+ }
+ ret = ctx->transport_ptr->ops->rx_rt_unvote(ctx->transport_ptr->ops);
+ ctx->rt_vote_off++;
+ GLINK_INFO_CH(ctx, "%s: Unvoting RX Realtime Thread %d", __func__, ret);
+ glink_put_ch_ctx(ctx);
+ return ret;
+}
+
/**
* glink_rpm_rx_poll() - Poll and receive any available events
* @handle: Channel handle in which this operation is performed.
@@ -3631,10 +3688,10 @@
if (ret)
return ret;
if (!ctx->transport_ptr) {
- glink_put_ch_ctx(ctx, false);
+ glink_put_ch_ctx(ctx);
return -EOPNOTSUPP;
}
- glink_put_ch_ctx(ctx, false);
+ glink_put_ch_ctx(ctx);
return ctx->transport_ptr->ops->wait_link_down(ctx->transport_ptr->ops);
}
EXPORT_SYMBOL(glink_wait_link_down);
@@ -3956,6 +4013,10 @@
if_ptr->power_vote = dummy_power_vote;
if (!if_ptr->power_unvote)
if_ptr->power_unvote = dummy_power_unvote;
+ if (!if_ptr->rx_rt_vote)
+ if_ptr->rx_rt_vote = dummy_rx_rt_vote;
+ if (!if_ptr->rx_rt_unvote)
+ if_ptr->rx_rt_unvote = dummy_rx_rt_unvote;
xprt_ptr->capabilities = 0;
xprt_ptr->ops = if_ptr;
spin_lock_init(&xprt_ptr->xprt_ctx_lock_lhb1);
@@ -6175,7 +6236,6 @@
static int glink_init(void)
{
log_ctx = ipc_log_context_create(NUM_LOG_PAGES, "glink", 0);
- rwlock_init(&magic_lock);
if (!log_ctx)
GLINK_ERR("%s: unable to create log context\n", __func__);
glink_debugfs_init();
diff --git a/drivers/soc/qcom/glink_smem_native_xprt.c b/drivers/soc/qcom/glink_smem_native_xprt.c
index 94dffa5..384347d 100644
--- a/drivers/soc/qcom/glink_smem_native_xprt.c
+++ b/drivers/soc/qcom/glink_smem_native_xprt.c
@@ -182,6 +182,8 @@
* @deferred_cmds: List of deferred commands that need to be
* processed in process context.
* @deferred_cmds_cnt: Number of deferred commands in queue.
+ * @rt_vote_lock: Serialize access to RT rx votes
+ * @rt_votes: Vote count for RT rx thread priority
* @num_pw_states: Size of @ramp_time_us.
* @ramp_time_us: Array of ramp times in microseconds where array
* index position represents a power state.
@@ -221,6 +223,8 @@
spinlock_t rx_lock;
struct list_head deferred_cmds;
uint32_t deferred_cmds_cnt;
+ spinlock_t rt_vote_lock;
+ uint32_t rt_votes;
uint32_t num_pw_states;
unsigned long *ramp_time_us;
struct mailbox_config_info *mailbox;
@@ -2125,6 +2129,52 @@
}
/**
+ * rx_rt_vote() - Increment and RX thread RT vote
+ * @if_ptr: The transport interface on which power voting is requested.
+ *
+ * Return: 0 on Success, standard error otherwise.
+ */
+static int rx_rt_vote(struct glink_transport_if *if_ptr)
+{
+ struct edge_info *einfo;
+ struct sched_param param = { .sched_priority = 1 };
+ int ret = 0;
+ unsigned long flags;
+
+ einfo = container_of(if_ptr, struct edge_info, xprt_if);
+ spin_lock_irqsave(&einfo->rt_vote_lock, flags);
+ if (!einfo->rt_votes)
+ ret = sched_setscheduler_nocheck(einfo->task, SCHED_FIFO,
+ ¶m);
+ einfo->rt_votes++;
+ spin_unlock_irqrestore(&einfo->rt_vote_lock, flags);
+ return ret;
+}
+
+/**
+ * rx_rt_unvote() - Remove a RX thread RT vote
+ * @if_ptr: The transport interface on which power voting is requested.
+ *
+ * Return: 0 on Success, standard error otherwise.
+ */
+static int rx_rt_unvote(struct glink_transport_if *if_ptr)
+{
+ struct edge_info *einfo;
+ struct sched_param param = { .sched_priority = 0 };
+ int ret = 0;
+ unsigned long flags;
+
+ einfo = container_of(if_ptr, struct edge_info, xprt_if);
+ spin_lock_irqsave(&einfo->rt_vote_lock, flags);
+ einfo->rt_votes--;
+ if (!einfo->rt_votes)
+ ret = sched_setscheduler_nocheck(einfo->task, SCHED_NORMAL,
+ ¶m);
+ spin_unlock_irqrestore(&einfo->rt_vote_lock, flags);
+ return ret;
+}
+
+/**
* negotiate_features_v1() - determine what features of a version can be used
* @if_ptr: The transport for which features are negotiated for.
* @version: The version negotiated.
@@ -2169,6 +2219,8 @@
einfo->xprt_if.get_power_vote_ramp_time = get_power_vote_ramp_time;
einfo->xprt_if.power_vote = power_vote;
einfo->xprt_if.power_unvote = power_unvote;
+ einfo->xprt_if.rx_rt_vote = rx_rt_vote;
+ einfo->xprt_if.rx_rt_unvote = rx_rt_unvote;
}
/**
@@ -2341,6 +2393,8 @@
init_srcu_struct(&einfo->use_ref);
spin_lock_init(&einfo->rx_lock);
INIT_LIST_HEAD(&einfo->deferred_cmds);
+ spin_lock_init(&einfo->rt_vote_lock);
+ einfo->rt_votes = 0;
mutex_lock(&probe_lock);
if (edge_infos[einfo->remote_proc_id]) {
diff --git a/drivers/soc/qcom/glink_xprt_if.h b/drivers/soc/qcom/glink_xprt_if.h
index f4d5a3b..47c1580 100644
--- a/drivers/soc/qcom/glink_xprt_if.h
+++ b/drivers/soc/qcom/glink_xprt_if.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, The Linux Foundation. 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 and
@@ -141,6 +141,8 @@
struct glink_transport_if *if_ptr, uint32_t state);
int (*power_vote)(struct glink_transport_if *if_ptr, uint32_t state);
int (*power_unvote)(struct glink_transport_if *if_ptr);
+ int (*rx_rt_vote)(struct glink_transport_if *if_ptr);
+ int (*rx_rt_unvote)(struct glink_transport_if *if_ptr);
/*
* Keep data pointers at the end of the structure after all function
* pointer to allow for in-place initialization.
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index a0982bc..a2ab266 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -84,34 +84,58 @@
} while (0)
#define icnss_pr_err(_fmt, ...) do { \
- pr_err(_fmt, ##__VA_ARGS__); \
- icnss_ipc_log_string("ERR: " pr_fmt(_fmt), \
- ##__VA_ARGS__); \
+ printk("%s" pr_fmt(_fmt), KERN_ERR, ##__VA_ARGS__); \
+ icnss_ipc_log_string("%s" pr_fmt(_fmt), "", \
+ ##__VA_ARGS__); \
} while (0)
#define icnss_pr_warn(_fmt, ...) do { \
- pr_warn(_fmt, ##__VA_ARGS__); \
- icnss_ipc_log_string("WRN: " pr_fmt(_fmt), \
- ##__VA_ARGS__); \
+ printk("%s" pr_fmt(_fmt), KERN_WARNING, ##__VA_ARGS__); \
+ icnss_ipc_log_string("%s" pr_fmt(_fmt), "", \
+ ##__VA_ARGS__); \
} while (0)
#define icnss_pr_info(_fmt, ...) do { \
- pr_info(_fmt, ##__VA_ARGS__); \
- icnss_ipc_log_string("INF: " pr_fmt(_fmt), \
- ##__VA_ARGS__); \
+ printk("%s" pr_fmt(_fmt), KERN_INFO, ##__VA_ARGS__); \
+ icnss_ipc_log_string("%s" pr_fmt(_fmt), "", \
+ ##__VA_ARGS__); \
} while (0)
+#if defined(CONFIG_DYNAMIC_DEBUG)
#define icnss_pr_dbg(_fmt, ...) do { \
- pr_debug(_fmt, ##__VA_ARGS__); \
- icnss_ipc_log_string("DBG: " pr_fmt(_fmt), \
- ##__VA_ARGS__); \
+ pr_debug(_fmt, ##__VA_ARGS__); \
+ icnss_ipc_log_string(pr_fmt(_fmt), ##__VA_ARGS__); \
} while (0)
#define icnss_pr_vdbg(_fmt, ...) do { \
- pr_debug(_fmt, ##__VA_ARGS__); \
- icnss_ipc_log_long_string("DBG: " pr_fmt(_fmt), \
- ##__VA_ARGS__); \
+ pr_debug(_fmt, ##__VA_ARGS__); \
+ icnss_ipc_log_long_string(pr_fmt(_fmt), ##__VA_ARGS__); \
} while (0)
+#elif defined(DEBUG)
+#define icnss_pr_dbg(_fmt, ...) do { \
+ printk("%s" pr_fmt(_fmt), KERN_DEBUG, ##__VA_ARGS__); \
+ icnss_ipc_log_string("%s" pr_fmt(_fmt), "", \
+ ##__VA_ARGS__); \
+ } while (0)
+
+#define icnss_pr_vdbg(_fmt, ...) do { \
+ printk("%s" pr_fmt(_fmt), KERN_DEBUG, ##__VA_ARGS__); \
+ icnss_ipc_log_long_string("%s" pr_fmt(_fmt), "", \
+ ##__VA_ARGS__); \
+ } while (0)
+#else
+#define icnss_pr_dbg(_fmt, ...) do { \
+ no_printk("%s" pr_fmt(_fmt), KERN_DEBUG, ##__VA_ARGS__); \
+ icnss_ipc_log_string("%s" pr_fmt(_fmt), "", \
+ ##__VA_ARGS__); \
+ } while (0)
+
+#define icnss_pr_vdbg(_fmt, ...) do { \
+ no_printk("%s" pr_fmt(_fmt), KERN_DEBUG, ##__VA_ARGS__); \
+ icnss_ipc_log_long_string("%s" pr_fmt(_fmt), "", \
+ ##__VA_ARGS__); \
+ } while (0)
+#endif
#ifdef CONFIG_ICNSS_DEBUG
#define ICNSS_ASSERT(_condition) do { \
@@ -242,7 +266,6 @@
struct icnss_event_pd_service_down_data {
bool crashed;
bool fw_rejuvenate;
- bool wdog_bite;
};
struct icnss_driver_event {
@@ -267,7 +290,6 @@
ICNSS_PD_RESTART,
ICNSS_MSA0_ASSIGNED,
ICNSS_WLFW_EXISTS,
- ICNSS_WDOG_BITE,
ICNSS_SHUTDOWN_DONE,
ICNSS_HOST_TRIGGERED_PDR,
};
@@ -2125,10 +2147,7 @@
icnss_pm_relax(priv);
- if (test_bit(ICNSS_WDOG_BITE, &priv->state)) {
- icnss_call_driver_shutdown(priv);
- clear_bit(ICNSS_WDOG_BITE, &priv->state);
- }
+ icnss_call_driver_shutdown(priv);
clear_bit(ICNSS_PD_RESTART, &priv->state);
@@ -2278,8 +2297,7 @@
static int icnss_fw_crashed(struct icnss_priv *priv,
struct icnss_event_pd_service_down_data *event_data)
{
- icnss_pr_dbg("FW crashed, state: 0x%lx, wdog_bite: %d\n",
- priv->state, event_data->wdog_bite);
+ icnss_pr_dbg("FW crashed, state: 0x%lx\n", priv->state);
set_bit(ICNSS_PD_RESTART, &priv->state);
clear_bit(ICNSS_FW_READY, &priv->state);
@@ -2289,17 +2307,9 @@
if (test_bit(ICNSS_DRIVER_PROBED, &priv->state))
icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_CRASHED, NULL);
- if (event_data->wdog_bite) {
- set_bit(ICNSS_WDOG_BITE, &priv->state);
- goto out;
- }
-
- icnss_call_driver_shutdown(priv);
-
if (event_data->fw_rejuvenate)
wlfw_rejuvenate_ack_send_sync_msg(priv);
-out:
return 0;
}
@@ -2496,9 +2506,6 @@
event_data->crashed = notif->crashed;
- if (notif->crashed == CRASH_STATUS_WDOG_BITE)
- event_data->wdog_bite = true;
-
fw_down_data.crashed = !!notif->crashed;
icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_DOWN, &fw_down_data);
@@ -2579,21 +2586,21 @@
if (event_data == NULL)
return notifier_from_errno(-ENOMEM);
+ event_data->crashed = true;
+
if (state == NULL) {
- event_data->crashed = true;
priv->stats.recovery.root_pd_crash++;
goto event_post;
}
switch (*state) {
case ROOT_PD_WDOG_BITE:
- event_data->crashed = true;
- event_data->wdog_bite = true;
priv->stats.recovery.root_pd_crash++;
break;
case ROOT_PD_SHUTDOWN:
cause = ICNSS_ROOT_PD_SHUTDOWN;
priv->stats.recovery.root_pd_shutdown++;
+ event_data->crashed = false;
break;
case USER_PD_STATE_CHANGE:
if (test_bit(ICNSS_HOST_TRIGGERED_PDR, &priv->state)) {
@@ -2605,7 +2612,6 @@
}
break;
default:
- event_data->crashed = true;
priv->stats.recovery.root_pd_crash++;
break;
}
@@ -3822,9 +3828,6 @@
case ICNSS_WLFW_EXISTS:
seq_puts(s, "WLAN FW EXISTS");
continue;
- case ICNSS_WDOG_BITE:
- seq_puts(s, "MODEM WDOG BITE");
- continue;
case ICNSS_SHUTDOWN_DONE:
seq_puts(s, "SHUTDOWN DONE");
continue;
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_dbg.c b/drivers/soc/qcom/msm_bus/msm_bus_dbg.c
index 015edb3..df29233 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_dbg.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_dbg.c
@@ -38,6 +38,7 @@
static struct dentry *clients;
static struct dentry *dir;
static DEFINE_MUTEX(msm_bus_dbg_fablist_lock);
+static DEFINE_RT_MUTEX(msm_bus_dbg_cllist_lock);
struct msm_bus_dbg_state {
uint32_t cl;
uint8_t enable;
@@ -289,7 +290,9 @@
struct msm_bus_cldata *cldata = NULL;
const struct msm_bus_client_handle *handle = file->private_data;
int found = 0;
+ ssize_t ret;
+ rt_mutex_lock(&msm_bus_dbg_cllist_lock);
list_for_each_entry(cldata, &cl_list, list) {
if ((cldata->clid == cl) ||
(cldata->handle && (cldata->handle == handle))) {
@@ -298,12 +301,17 @@
}
}
- if (!found)
+ if (!found) {
+ rt_mutex_unlock(&msm_bus_dbg_cllist_lock);
return 0;
+ }
bsize = cldata->size;
- return simple_read_from_buffer(buf, count, ppos,
+ ret = simple_read_from_buffer(buf, count, ppos,
cldata->buffer, bsize);
+ rt_mutex_unlock(&msm_bus_dbg_cllist_lock);
+
+ return ret;
}
static int client_data_open(struct inode *inode, struct file *file)
@@ -339,7 +347,9 @@
return -ENOMEM;
}
cldata->handle = pdata;
+ rt_mutex_lock(&msm_bus_dbg_cllist_lock);
list_add_tail(&cldata->list, &cl_list);
+ rt_mutex_unlock(&msm_bus_dbg_cllist_lock);
return 0;
}
@@ -352,6 +362,7 @@
bool found = false;
char *buf = NULL;
+ rt_mutex_lock(&msm_bus_dbg_cllist_lock);
list_for_each_entry(cldata, &cl_list, list) {
if (cldata->handle == pdata) {
found = true;
@@ -359,12 +370,15 @@
}
}
- if (!found)
+ if (!found) {
+ rt_mutex_unlock(&msm_bus_dbg_cllist_lock);
return -ENOENT;
+ }
if (cldata->file == NULL) {
if (pdata->name == NULL) {
MSM_BUS_DBG("Client doesn't have a name\n");
+ rt_mutex_unlock(&msm_bus_dbg_cllist_lock);
return -EINVAL;
}
cldata->file = debugfs_create_file(pdata->name, S_IRUGO,
@@ -393,6 +407,7 @@
i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "%llu ", ib);
i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "\n");
cldata->size = i;
+ rt_mutex_unlock(&msm_bus_dbg_cllist_lock);
trace_bus_update_request((int)ts.tv_sec, (int)ts.tv_nsec,
pdata->name, pdata->mas, pdata->slv, ab, ib);
@@ -404,6 +419,7 @@
{
struct msm_bus_cldata *cldata = NULL;
+ rt_mutex_lock(&msm_bus_dbg_cllist_lock);
list_for_each_entry(cldata, &cl_list, list) {
if (cldata->handle == pdata) {
debugfs_remove(cldata->file);
@@ -412,6 +428,7 @@
break;
}
}
+ rt_mutex_unlock(&msm_bus_dbg_cllist_lock);
}
static int msm_bus_dbg_record_client(const struct msm_bus_scale_pdata *pdata,
@@ -429,7 +446,9 @@
cldata->clid = clid;
cldata->file = file;
cldata->size = 0;
+ rt_mutex_lock(&msm_bus_dbg_cllist_lock);
list_add_tail(&cldata->list, &cl_list);
+ rt_mutex_unlock(&msm_bus_dbg_cllist_lock);
return 0;
}
@@ -437,13 +456,16 @@
{
struct msm_bus_cldata *cldata = NULL;
+ rt_mutex_lock(&msm_bus_dbg_cllist_lock);
list_for_each_entry(cldata, &cl_list, list) {
if (cldata->clid == clid) {
+ debugfs_remove(cldata->file);
list_del(&cldata->list);
kfree(cldata);
break;
}
}
+ rt_mutex_unlock(&msm_bus_dbg_cllist_lock);
}
static int msm_bus_dbg_fill_cl_buffer(const struct msm_bus_scale_pdata *pdata,
@@ -455,6 +477,7 @@
struct timespec ts;
int found = 0;
+ rt_mutex_lock(&msm_bus_dbg_cllist_lock);
list_for_each_entry(cldata, &cl_list, list) {
if (cldata->clid == clid) {
found = 1;
@@ -462,11 +485,14 @@
}
}
- if (!found)
+ if (!found) {
+ rt_mutex_unlock(&msm_bus_dbg_cllist_lock);
return -ENOENT;
+ }
if (cldata->file == NULL) {
if (pdata->name == NULL) {
+ rt_mutex_unlock(&msm_bus_dbg_cllist_lock);
MSM_BUS_DBG("Client doesn't have a name\n");
return -EINVAL;
}
@@ -514,21 +540,11 @@
cldata->index = index;
cldata->size = i;
+ rt_mutex_unlock(&msm_bus_dbg_cllist_lock);
+
return i;
}
-static int msm_bus_dbg_update_request(struct msm_bus_cldata *cldata, int index)
-{
- int ret = 0;
-
- if ((index < 0) || (index > cldata->pdata->num_usecases)) {
- MSM_BUS_DBG("Invalid index!\n");
- return -EINVAL;
- }
- ret = msm_bus_scale_client_update_request(cldata->clid, index);
- return ret;
-}
-
static ssize_t msm_bus_dbg_update_request_write(struct file *file,
const char __user *ubuf, size_t cnt, loff_t *ppos)
{
@@ -538,19 +554,26 @@
char *chid;
char *buf = kmalloc((sizeof(char) * (cnt + 1)), GFP_KERNEL);
int found = 0;
+ uint32_t clid;
+ ssize_t res = cnt;
if (!buf || IS_ERR(buf)) {
MSM_BUS_ERR("Memory allocation for buffer failed\n");
return -ENOMEM;
}
- if (cnt == 0)
- return 0;
- if (copy_from_user(buf, ubuf, cnt))
- return -EFAULT;
+ if (cnt == 0) {
+ res = 0;
+ goto out;
+ }
+ if (copy_from_user(buf, ubuf, cnt)) {
+ res = -EFAULT;
+ goto out;
+ }
buf[cnt] = '\0';
chid = buf;
MSM_BUS_DBG("buffer: %s\n size: %zu\n", buf, sizeof(ubuf));
+ rt_mutex_lock(&msm_bus_dbg_cllist_lock);
list_for_each_entry(cldata, &cl_list, list) {
if (strnstr(chid, cldata->pdata->name, cnt)) {
found = 1;
@@ -559,23 +582,37 @@
if (chid) {
ret = kstrtoul(chid, 10, &index);
if (ret) {
- MSM_BUS_DBG("Index conversion failed\n"
- );
- return -EFAULT;
+ MSM_BUS_DBG("Index conversion\n"
+ " failed\n");
+ rt_mutex_unlock(
+ &msm_bus_dbg_cllist_lock);
+ res = -EFAULT;
+ goto out;
}
} else {
- MSM_BUS_DBG("Error parsing input.\n"
- "Index not found\n");
+ MSM_BUS_DBG("Error parsing input. Index not\n"
+ " found\n");
found = 0;
}
+ if ((index < 0) ||
+ (index > cldata->pdata->num_usecases)) {
+ MSM_BUS_DBG("Invalid index!\n");
+ rt_mutex_unlock(&msm_bus_dbg_cllist_lock);
+ res = -EINVAL;
+ goto out;
+ }
+ clid = cldata->clid;
break;
}
}
+ rt_mutex_unlock(&msm_bus_dbg_cllist_lock);
if (found)
- msm_bus_dbg_update_request(cldata, index);
+ msm_bus_scale_client_update_request(clid, index);
+
+out:
kfree(buf);
- return cnt;
+ return res;
}
/**
@@ -598,8 +635,10 @@
break;
}
}
- if (!found)
+ if (!found) {
+ mutex_unlock(&msm_bus_dbg_fablist_lock);
return -ENOENT;
+ }
bsize = fablist->size;
ret = simple_read_from_buffer(buf, count, ppos,
fablist->buffer, bsize);
@@ -689,8 +728,10 @@
break;
}
}
- if (!found)
+ if (!found) {
+ mutex_unlock(&msm_bus_dbg_fablist_lock);
return -ENOENT;
+ }
if (fablist->file == NULL) {
MSM_BUS_DBG("Fabric dbg entry does not exist\n");
@@ -741,6 +782,8 @@
"\nDumping curent client votes to trace log\n");
if (*ppos)
goto exit_dump_clients_read;
+
+ rt_mutex_lock(&msm_bus_dbg_cllist_lock);
list_for_each_entry(cldata, &cl_list, list) {
if (IS_ERR_OR_NULL(cldata->pdata))
continue;
@@ -756,6 +799,7 @@
cldata->pdata->active_only);
}
}
+ rt_mutex_unlock(&msm_bus_dbg_cllist_lock);
exit_dump_clients_read:
return simple_read_from_buffer(buf, count, ppos, msg, cnt);
}
@@ -880,6 +924,7 @@
goto err;
}
+ rt_mutex_lock(&msm_bus_dbg_cllist_lock);
list_for_each_entry(cldata, &cl_list, list) {
if (cldata->pdata) {
if (cldata->pdata->name == NULL) {
@@ -899,6 +944,7 @@
&client_data_fops);
}
}
+ rt_mutex_unlock(&msm_bus_dbg_cllist_lock);
if (debugfs_create_file("dump_clients", S_IRUGO | S_IWUSR,
clients, NULL, &msm_bus_dbg_dump_clients_fops) == NULL)
@@ -911,6 +957,7 @@
if (fablist->file == NULL) {
MSM_BUS_DBG("Cannot create files for commit data\n");
kfree(rules_buf);
+ mutex_unlock(&msm_bus_dbg_fablist_lock);
goto err;
}
}
@@ -930,10 +977,14 @@
struct msm_bus_cldata *cldata = NULL, *cldata_temp;
debugfs_remove_recursive(dir);
+
+ rt_mutex_lock(&msm_bus_dbg_cllist_lock);
list_for_each_entry_safe(cldata, cldata_temp, &cl_list, list) {
list_del(&cldata->list);
kfree(cldata);
}
+ rt_mutex_unlock(&msm_bus_dbg_cllist_lock);
+
mutex_lock(&msm_bus_dbg_fablist_lock);
list_for_each_entry_safe(fablist, fablist_temp, &fabdata_list, list) {
list_del(&fablist->list);
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_dbg_voter.c b/drivers/soc/qcom/msm_bus/msm_bus_dbg_voter.c
index 3f8b52c..6c69bec 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_dbg_voter.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_dbg_voter.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, The Linux Foundation. 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 and
@@ -133,7 +133,7 @@
return 0;
}
- if (sscanf(buf, "%s %llu", name, &vote_khz) != 2) {
+ if (sscanf(buf, "%9s %llu", name, &vote_khz) != 2) {
pr_err("%s:return error", __func__);
return -EINVAL;
}
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c b/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
index 185d862..0e5ead0 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
@@ -595,6 +595,9 @@
cnt_vcd++;
}
+ if (!cnt_active)
+ goto exit_msm_bus_commit_data;
+
n_active = kcalloc(cnt_vcd+1, sizeof(int), GFP_KERNEL);
if (!n_active)
return -ENOMEM;
@@ -624,42 +627,54 @@
MSM_BUS_ERR("%s: Error invalidating mbox: %d\n",
__func__, ret);
- if (cur_rsc->rscdev->req_state == RPMH_AWAKE_STATE)
+ if (cur_rsc->rscdev->req_state == RPMH_AWAKE_STATE) {
ret = rpmh_write(cur_mbox, cur_rsc->rscdev->req_state,
cmdlist_active, cnt_active);
- else
+ /*
+ * Ignore -EBUSY from rpmh_write if it's an AWAKE_STATE
+ * request since AWAKE requests are invalid when
+ * the display RSC is in solver mode and the bus driver
+ * does not know the current state of the display RSC.
+ */
+ if (ret && ret != -EBUSY)
+ MSM_BUS_ERR("%s: error sending active/awake sets: %d\n",
+ __func__, ret);
+ } else {
ret = rpmh_write_passthru(cur_mbox, cur_rsc->rscdev->req_state,
cmdlist_active, n_active);
- if (ret)
- MSM_BUS_ERR("%s: error sending active/awake sets: %d\n",
+ if (ret)
+ MSM_BUS_ERR("%s: error sending active/awake sets: %d\n",
__func__, ret);
-
-
- ret = rpmh_write_passthru(cur_mbox, RPMH_WAKE_ONLY_STATE,
- cmdlist_wake, n_wake);
- if (ret)
- MSM_BUS_ERR("%s: error sending wake sets: %d\n",
- __func__, ret);
-
- ret = rpmh_write_passthru(cur_mbox, RPMH_SLEEP_STATE,
- cmdlist_sleep, n_sleep);
- if (ret)
- MSM_BUS_ERR("%s: error sending sleep sets: %d\n",
- __func__, ret);
-
- list_for_each_entry_safe(node, node_tmp, clist, link) {
- bcm_clist_clean(node);
- node->dirty = false;
- list_del_init(&node->link);
+ }
+ if (cnt_wake) {
+ ret = rpmh_write_passthru(cur_mbox, RPMH_WAKE_ONLY_STATE,
+ cmdlist_wake, n_wake);
+ if (ret)
+ MSM_BUS_ERR("%s: error sending wake sets: %d\n",
+ __func__, ret);
+ }
+ if (cnt_sleep) {
+ ret = rpmh_write_passthru(cur_mbox, RPMH_SLEEP_STATE,
+ cmdlist_sleep, n_sleep);
+ if (ret)
+ MSM_BUS_ERR("%s: error sending sleep sets: %d\n",
+ __func__, ret);
}
- cur_rsc = NULL;
kfree(cmdlist_active);
kfree(cmdlist_wake);
kfree(cmdlist_sleep);
kfree(n_active);
kfree(n_wake);
kfree(n_sleep);
+
+exit_msm_bus_commit_data:
+ list_for_each_entry_safe(node, node_tmp, clist, link) {
+ bcm_clist_clean(node);
+ node->dirty = false;
+ list_del_init(&node->link);
+ }
+ cur_rsc = NULL;
return ret;
}
diff --git a/drivers/soc/qcom/msm_performance.c b/drivers/soc/qcom/msm_performance.c
index 25e6a9d..979c628 100644
--- a/drivers/soc/qcom/msm_performance.c
+++ b/drivers/soc/qcom/msm_performance.c
@@ -25,6 +25,7 @@
#include <linux/module.h>
#include <linux/input.h>
#include <linux/kthread.h>
+#include <soc/qcom/msm-core.h>
static struct mutex managed_cpus_lock;
diff --git a/drivers/soc/qcom/qbt1000.c b/drivers/soc/qcom/qbt1000.c
index 67a5e05..e4ada03 100644
--- a/drivers/soc/qcom/qbt1000.c
+++ b/drivers/soc/qcom/qbt1000.c
@@ -342,6 +342,13 @@
goto end;
}
+ if (strcmp(app.name, FP_APP_NAME)) {
+ dev_err(drvdata->dev, "%s: Invalid app name\n",
+ __func__);
+ rc = -EINVAL;
+ goto end;
+ }
+
if (drvdata->app_handle) {
dev_err(drvdata->dev, "%s: LOAD app already loaded, unloading first\n",
__func__);
@@ -388,9 +395,7 @@
pr_debug("app %s load after\n", app.name);
- if (!strcmp(app.name, FP_APP_NAME))
- drvdata->fp_app_handle = drvdata->app_handle;
-
+ drvdata->fp_app_handle = drvdata->app_handle;
break;
}
case QBT1000_UNLOAD_APP:
diff --git a/drivers/soc/qcom/qdsp6v2/apr.c b/drivers/soc/qcom/qdsp6v2/apr.c
index e45f61e..de89b8f 100644
--- a/drivers/soc/qcom/qdsp6v2/apr.c
+++ b/drivers/soc/qcom/qdsp6v2/apr.c
@@ -821,6 +821,7 @@
uint16_t clnt;
int i, j;
+ memset(&data, 0, sizeof(data));
data.opcode = RESET_EVENTS;
data.reset_event = code;
diff --git a/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c b/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c
index 92a97fae..9f12564a 100644
--- a/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c
+++ b/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c
@@ -239,7 +239,7 @@
int num_of_intents, uint32_t size)
{
int i;
- int rc;
+ int rc = 0;
if (!apr_ch || !num_of_intents || !size) {
pr_err("%s: Invalid parameter\n", __func__);
diff --git a/drivers/soc/qcom/qdsp6v2/audio_notifier.c b/drivers/soc/qcom/qdsp6v2/audio_notifier.c
index 2320fea..94533a7 100644
--- a/drivers/soc/qcom/qdsp6v2/audio_notifier.c
+++ b/drivers/soc/qcom/qdsp6v2/audio_notifier.c
@@ -510,7 +510,7 @@
int ret = 0;
int ret2;
struct list_head *ptr, *next;
- struct client_data *client_data;
+ struct client_data *client_data = NULL;
if (client_name == NULL) {
pr_err("%s: client_name is NULL\n", __func__);
diff --git a/drivers/soc/qcom/qsee_ipc_irq_bridge.c b/drivers/soc/qcom/qsee_ipc_irq_bridge.c
new file mode 100644
index 0000000..ac3dcc3
--- /dev/null
+++ b/drivers/soc/qcom/qsee_ipc_irq_bridge.c
@@ -0,0 +1,624 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. 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 and
+ * only 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/interrupt.h>
+#include <linux/ipc_logging.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <soc/qcom/subsystem_notif.h>
+#include <soc/qcom/subsystem_restart.h>
+
+#define MODULE_NAME "qsee_ipc_irq_bridge"
+#define DEVICE_NAME MODULE_NAME
+#define NUM_LOG_PAGES 4
+
+#define QIIB_DBG(x...) do { \
+ if (qiib_info->log_ctx) \
+ ipc_log_string(qiib_info->log_ctx, x); \
+ else \
+ pr_debug(x); \
+ } while (0)
+
+#define QIIB_ERR(x...) do { \
+ pr_err(x); \
+ if (qiib_info->log_ctx) \
+ ipc_log_string(qiib_info->log_ctx, x); \
+ } while (0)
+
+static void qiib_cleanup(void);
+
+/**
+ * qiib_dev - QSEE IPC IRQ bridge device
+ * @dev_list: qiib device list.
+ * @i: Index to this character device.
+ * @dev_name: Device node name used by the clients.
+ * @cdev: structure to the internal character device.
+ * @devicep: Pointer to the qiib class device structure.
+ * @poll_wait_queue: poll thread wait queue.
+ * @irq_num: IRQ number usd for this device.
+ * @rx_irq_reset_reg: Reference to the register to reset the rx irq
+ * line, if applicable.
+ * @irq_mask: Mask written to @rx_irq_reset_reg to clear the irq.
+ * @irq_pending_count: The number of IRQs pending.
+ * @irq_pending_count_lock: Lock to protect @irq_pending_cont.
+ * @ssr_name: Name of the subsystem recognized by the SSR framework.
+ * @nb: SSR Notifier callback.
+ * @notifier_handle: SSR Notifier handle.
+ * @in_reset: Flag to check the SSR state.
+ */
+struct qiib_dev {
+ struct list_head dev_list;
+ uint32_t i;
+
+ const char *dev_name;
+ struct cdev cdev;
+ struct device *devicep;
+
+ wait_queue_head_t poll_wait_queue;
+
+ uint32_t irq_line;
+ void __iomem *rx_irq_reset_reg;
+ uint32_t irq_mask;
+ uint32_t irq_pending_count;
+ spinlock_t irq_pending_count_lock;
+
+ const char *ssr_name;
+ struct notifier_block nb;
+ void *notifier_handle;
+ bool in_reset;
+};
+
+/**
+ * qiib_driver_data - QSEE IPC IRQ bridge driver data
+ * @list: list of all nodes devices.
+ * @list_lock: lock to synchronize the @list access.
+ * @nprots: Number of device nodes.
+ * @classp: Pointer to the device class.
+ * @dev_num: qiib device number.
+ * @log_ctx: pointer to the ipc logging context.
+ */
+struct qiib_driver_data {
+ struct list_head list;
+ struct mutex list_lock;
+
+ int nports;
+ struct class *classp;
+ dev_t dev_num;
+
+ void *log_ctx;
+};
+
+static struct qiib_driver_data *qiib_info;
+
+/**
+ * qiib_driver_data_init() - Initialize the QIIB driver data.
+ *
+ * This function used to initialize the driver specific data
+ * during the module init.
+ *
+ * Return: 0 for success, Standard Linux errors
+ */
+static int qiib_driver_data_init(void)
+{
+ qiib_info = kzalloc(sizeof(*qiib_info), GFP_KERNEL);
+ if (!qiib_info)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&qiib_info->list);
+ mutex_init(&qiib_info->list_lock);
+
+ qiib_info->log_ctx = ipc_log_context_create(NUM_LOG_PAGES,
+ "qsee_ipc_irq_bridge", 0);
+ if (!qiib_info->log_ctx)
+ QIIB_ERR("%s: unable to create logging context\n", __func__);
+
+ return 0;
+}
+
+/**
+ * qiib_driver_data_deinit() - De-Initialize the QIIB driver data.
+ *
+ * This function used to de-initialize the driver specific data
+ * during the module exit.
+ */
+static void qiib_driver_data_deinit(void)
+{
+ qiib_cleanup();
+ if (!qiib_info->log_ctx)
+ ipc_log_context_destroy(qiib_info->log_ctx);
+ kfree(qiib_info);
+ qiib_info = NULL;
+}
+
+/**
+ * qiib_restart_notifier_cb() - SSR restart notifier callback function
+ * @this: Notifier block used by the SSR framework
+ * @code: The SSR code for which stage of restart is occurring
+ * @data: Structure containing private data - not used here.
+ *
+ * This function is a callback for the SSR framework. From here we initiate
+ * our handling of SSR.
+ *
+ * Return: Status of SSR handling
+ */
+static int qiib_restart_notifier_cb(struct notifier_block *this,
+ unsigned long code,
+ void *data)
+{
+ struct qiib_dev *devp = container_of(this, struct qiib_dev, nb);
+
+ if (code == SUBSYS_BEFORE_SHUTDOWN) {
+ QIIB_DBG("%s: %s: subsystem restart for %s\n", __func__,
+ "SUBSYS_BEFORE_SHUTDOWN",
+ devp->ssr_name);
+ devp->in_reset = true;
+ wake_up_interruptible(&devp->poll_wait_queue);
+ } else if (code == SUBSYS_AFTER_POWERUP) {
+ QIIB_DBG("%s: %s: subsystem restart for %s\n", __func__,
+ "SUBSYS_AFTER_POWERUP",
+ devp->ssr_name);
+ devp->in_reset = false;
+ }
+ return NOTIFY_DONE;
+}
+
+/**
+ * qiib_poll() - poll() syscall for the qiib device
+ * @file: Pointer to the file structure.
+ * @wait: pointer to Poll table.
+ *
+ * This function is used to poll on the qiib device when
+ * userspace client do a poll() system call. All input arguments are
+ * validated by the virtual file system before calling this function.
+ *
+ * Return: POLLIN for interrupt intercepted case and POLLRDHUP for SSR.
+ */
+static unsigned int qiib_poll(struct file *file, poll_table *wait)
+{
+ struct qiib_dev *devp = file->private_data;
+ unsigned int mask = 0;
+ unsigned long flags;
+
+ if (!devp) {
+ QIIB_ERR("%s on NULL device\n", __func__);
+ return POLLERR;
+ }
+
+ if (devp->in_reset)
+ return POLLRDHUP;
+
+ poll_wait(file, &devp->poll_wait_queue, wait);
+ spin_lock_irqsave(&devp->irq_pending_count_lock, flags);
+ if (devp->irq_pending_count) {
+ mask |= POLLIN;
+ QIIB_DBG("%s set POLLIN on [%s] count[%d]\n",
+ __func__, devp->dev_name,
+ devp->irq_pending_count);
+ devp->irq_pending_count = 0;
+ }
+ spin_unlock_irqrestore(&devp->irq_pending_count_lock, flags);
+
+ if (devp->in_reset) {
+ mask |= POLLRDHUP;
+ QIIB_DBG("%s set POLLRDHUP on [%s] count[%d]\n",
+ __func__, devp->dev_name,
+ devp->irq_pending_count);
+ }
+ return mask;
+}
+
+/**
+ * qiib_open() - open() syscall for the qiib device
+ * @inode: Pointer to the inode structure.
+ * @file: Pointer to the file structure.
+ *
+ * This function is used to open the qiib device when
+ * userspace client do a open() system call. All input arguments are
+ * validated by the virtual file system before calling this function.
+ *
+ * Return: 0 for success, Standard Linux errors
+ */
+static int qiib_open(struct inode *inode, struct file *file)
+{
+ struct qiib_dev *devp = NULL;
+
+ devp = container_of(inode->i_cdev, struct qiib_dev, cdev);
+ if (!devp) {
+ QIIB_ERR("%s on NULL device\n", __func__);
+ return -EINVAL;
+ }
+ file->private_data = devp;
+ QIIB_DBG("%s on [%s]\n", __func__, devp->dev_name);
+ return 0;
+}
+
+/**
+ * qiib_release() - release operation on qiibdevice
+ * @inode: Pointer to the inode structure.
+ * @file: Pointer to the file structure.
+ *
+ * This function is used to release the qiib device when
+ * userspace client do a close() system call. All input arguments are
+ * validated by the virtual file system before calling this function.
+ */
+static int qiib_release(struct inode *inode, struct file *file)
+{
+ struct qiib_dev *devp = file->private_data;
+
+ if (!devp) {
+ QIIB_ERR("%s on NULL device\n", __func__);
+ return -EINVAL;
+ }
+
+ QIIB_DBG("%s on [%s]\n", __func__, devp->dev_name);
+ return 0;
+}
+
+static const struct file_operations qiib_fops = {
+ .owner = THIS_MODULE,
+ .open = qiib_open,
+ .release = qiib_release,
+ .poll = qiib_poll,
+};
+
+/**
+ * qiib_add_device() - Initialize qiib device and add cdev
+ * @devp: pointer to the qiib device.
+ * @i: index of the qiib device.
+ *
+ * Return: 0 for success, Standard Linux errors
+ */
+static int qiib_add_device(struct qiib_dev *devp, int i)
+{
+ int ret = 0;
+
+ devp->i = i;
+ init_waitqueue_head(&devp->poll_wait_queue);
+ spin_lock_init(&devp->irq_pending_count_lock);
+
+ cdev_init(&devp->cdev, &qiib_fops);
+ devp->cdev.owner = THIS_MODULE;
+
+ ret = cdev_add(&devp->cdev, qiib_info->dev_num + i, 1);
+ if (IS_ERR_VALUE((unsigned long)ret)) {
+ QIIB_ERR("%s: cdev_add() failed for dev [%s] ret:%i\n",
+ __func__, devp->dev_name, ret);
+ return ret;
+ }
+
+ devp->devicep = device_create(qiib_info->classp,
+ NULL,
+ (qiib_info->dev_num + i),
+ NULL,
+ devp->dev_name);
+
+ if (IS_ERR_OR_NULL(devp->devicep)) {
+ QIIB_ERR("%s: device_create() failed for dev [%s]\n",
+ __func__, devp->dev_name);
+ ret = -ENOMEM;
+ cdev_del(&devp->cdev);
+ return ret;
+ }
+
+ mutex_lock(&qiib_info->list_lock);
+ list_add(&devp->dev_list, &qiib_info->list);
+ mutex_unlock(&qiib_info->list_lock);
+
+ return ret;
+}
+
+static irqreturn_t qiib_irq_handler(int irq, void *priv)
+{
+ struct qiib_dev *devp = priv;
+ unsigned long flags;
+
+ spin_lock_irqsave(&devp->irq_pending_count_lock, flags);
+ devp->irq_pending_count++;
+ spin_unlock_irqrestore(&devp->irq_pending_count_lock, flags);
+ wake_up_interruptible(&devp->poll_wait_queue);
+
+ if (devp->rx_irq_reset_reg)
+ writel_relaxed(devp->irq_mask, devp->rx_irq_reset_reg);
+
+ QIIB_DBG("%s name[%s] pend_count[%d]\n", __func__,
+ devp->dev_name, devp->irq_pending_count);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * qiib_parse_node() - parse node from device tree binding
+ * @node: pointer to device tree node
+ * @devp: pointer to the qiib device
+ *
+ * Return: 0 on success, -ENODEV on failure.
+ */
+static int qiib_parse_node(struct device_node *node, struct qiib_dev *devp)
+{
+ char *key;
+ const char *subsys_name;
+ const char *dev_name;
+ uint32_t irqtype;
+ uint32_t irq_clear[2];
+ struct irq_data *irqtype_data;
+ int ret = -ENODEV;
+
+ key = "qcom,dev-name";
+ dev_name = of_get_property(node, key, NULL);
+ if (!dev_name) {
+ QIIB_ERR("%s: missing key: %s\n", __func__, key);
+ goto missing_key;
+ }
+ QIIB_DBG("%s: %s = %s\n", __func__, key, dev_name);
+
+ key = "interrupts";
+ devp->irq_line = irq_of_parse_and_map(node, 0);
+ if (!devp->irq_line) {
+ QIIB_ERR("%s: missing key: %s\n", __func__, key);
+ goto missing_key;
+ }
+ QIIB_DBG("%s: %s = %d\n", __func__, key, devp->irq_line);
+
+ irqtype_data = irq_get_irq_data(devp->irq_line);
+ if (!irqtype_data) {
+ QIIB_ERR("%s: get irqdata fail:%d\n", __func__, devp->irq_line);
+ goto missing_key;
+ }
+ irqtype = irqd_get_trigger_type(irqtype_data);
+ QIIB_DBG("%s: irqtype = %d\n", __func__, irqtype);
+
+ key = "label";
+ subsys_name = of_get_property(node, key, NULL);
+ if (!subsys_name) {
+ QIIB_ERR("%s: missing key: %s\n", __func__, key);
+ goto missing_key;
+ }
+ QIIB_DBG("%s: %s = %s\n", __func__, key, subsys_name);
+
+ if (irqtype & IRQF_TRIGGER_HIGH) {
+ key = "qcom,rx-irq-clr-mask";
+ ret = of_property_read_u32(node, key, &devp->irq_mask);
+ if (ret) {
+ QIIB_ERR("%s: missing key: %s\n", __func__, key);
+ ret = -ENODEV;
+ goto missing_key;
+ }
+ QIIB_DBG("%s: %s = %d\n", __func__, key, devp->irq_mask);
+
+ key = "qcom,rx-irq-clr";
+ ret = of_property_read_u32_array(node, key, irq_clear,
+ ARRAY_SIZE(irq_clear));
+ if (ret) {
+ QIIB_ERR("%s: missing key: %s\n", __func__, key);
+ ret = -ENODEV;
+ goto missing_key;
+ }
+
+ devp->rx_irq_reset_reg = ioremap_nocache(irq_clear[0],
+ irq_clear[1]);
+ if (!devp->rx_irq_reset_reg) {
+ QIIB_ERR("%s: unable to map rx reset reg\n", __func__);
+ ret = -ENOMEM;
+ goto missing_key;
+ }
+ }
+
+ devp->dev_name = dev_name;
+ devp->ssr_name = subsys_name;
+ devp->nb.notifier_call = qiib_restart_notifier_cb;
+
+ devp->notifier_handle = subsys_notif_register_notifier(devp->ssr_name,
+ &devp->nb);
+ if (IS_ERR_OR_NULL(devp->notifier_handle)) {
+ QIIB_ERR("%s: Could not register SSR notifier cb\n", __func__);
+ ret = -EINVAL;
+ goto ssr_reg_fail;
+ }
+
+ ret = request_irq(devp->irq_line, qiib_irq_handler,
+ irqtype | IRQF_NO_SUSPEND,
+ devp->dev_name, devp);
+ if (ret < 0) {
+ QIIB_ERR("%s: request_irq() failed on %d\n", __func__,
+ devp->irq_line);
+ goto req_irq_fail;
+ } else {
+ ret = enable_irq_wake(devp->irq_line);
+ if (ret < 0)
+ QIIB_ERR("%s: enable_irq_wake() failed on %d\n",
+ __func__, devp->irq_line);
+ }
+
+ return ret;
+
+req_irq_fail:
+ subsys_notif_unregister_notifier(devp->notifier_handle, &devp->nb);
+ssr_reg_fail:
+ if (devp->rx_irq_reset_reg) {
+ iounmap(devp->rx_irq_reset_reg);
+ devp->rx_irq_reset_reg = NULL;
+ }
+missing_key:
+ return ret;
+}
+
+/**
+ * qiib_cleanup - cleanup all the resources
+ *
+ * This function remove all the memory and unregister
+ * the char device region.
+ */
+static void qiib_cleanup(void)
+{
+ struct qiib_dev *devp;
+ struct qiib_dev *index;
+
+ mutex_lock(&qiib_info->list_lock);
+ list_for_each_entry_safe(devp, index, &qiib_info->list, dev_list) {
+ cdev_del(&devp->cdev);
+ list_del(&devp->dev_list);
+ device_destroy(qiib_info->classp,
+ MKDEV(MAJOR(qiib_info->dev_num), devp->i));
+ if (devp->notifier_handle)
+ subsys_notif_unregister_notifier(devp->notifier_handle,
+ &devp->nb);
+ kfree(devp);
+ }
+ mutex_unlock(&qiib_info->list_lock);
+
+ if (!IS_ERR_OR_NULL(qiib_info->classp))
+ class_destroy(qiib_info->classp);
+
+ unregister_chrdev_region(MAJOR(qiib_info->dev_num), qiib_info->nports);
+}
+
+/**
+ * qiib_alloc_chrdev_region() - allocate the char device region
+ *
+ * This function allocate memory for qiib character-device region and
+ * create the class.
+ */
+static int qiib_alloc_chrdev_region(void)
+{
+ int ret;
+
+ ret = alloc_chrdev_region(&qiib_info->dev_num,
+ 0,
+ qiib_info->nports,
+ DEVICE_NAME);
+ if (IS_ERR_VALUE((unsigned long)ret)) {
+ QIIB_ERR("%s: alloc_chrdev_region() failed ret:%i\n",
+ __func__, ret);
+ return ret;
+ }
+
+ qiib_info->classp = class_create(THIS_MODULE, DEVICE_NAME);
+ if (IS_ERR(qiib_info->classp)) {
+ QIIB_ERR("%s: class_create() failed ENOMEM\n", __func__);
+ ret = -ENOMEM;
+ unregister_chrdev_region(MAJOR(qiib_info->dev_num),
+ qiib_info->nports);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int qsee_ipc_irq_bridge_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct device_node *node;
+ struct qiib_dev *devp;
+ int i = 0;
+
+ qiib_info->nports = of_get_available_child_count(pdev->dev.of_node);
+ if (!qiib_info->nports) {
+ QIIB_ERR("%s:Fail nports = %d\n", __func__, qiib_info->nports);
+ return -EINVAL;
+ }
+
+ ret = qiib_alloc_chrdev_region();
+ if (ret) {
+ QIIB_ERR("%s: chrdev_region allocation failed ret:%i\n",
+ __func__, ret);
+ return ret;
+ }
+
+ for_each_available_child_of_node(pdev->dev.of_node, node) {
+ devp = kzalloc(sizeof(*devp), GFP_KERNEL);
+ if (IS_ERR_OR_NULL(devp)) {
+ QIIB_ERR("%s:Allocation failed id:%d\n", __func__, i);
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ ret = qiib_parse_node(node, devp);
+ if (ret) {
+ QIIB_ERR("%s:qiib_parse_node failed %d\n", __func__, i);
+ kfree(devp);
+ goto error;
+ }
+
+ ret = qiib_add_device(devp, i);
+ if (ret < 0) {
+ QIIB_ERR("%s: add [%s] device failed ret=%d\n",
+ __func__, devp->dev_name, ret);
+ kfree(devp);
+ goto error;
+ }
+ i++;
+ }
+
+ QIIB_DBG("%s: Driver Initialized.\n", __func__);
+ return 0;
+
+error:
+ qiib_cleanup();
+ return ret;
+}
+
+static int qsee_ipc_irq_bridge_remove(struct platform_device *pdev)
+{
+ qiib_cleanup();
+ return 0;
+}
+
+static const struct of_device_id qsee_ipc_irq_bridge_match_table[] = {
+ { .compatible = "qcom,qsee-ipc-irq-bridge" },
+ {},
+};
+
+static struct platform_driver qsee_ipc_irq_bridge_driver = {
+ .probe = qsee_ipc_irq_bridge_probe,
+ .remove = qsee_ipc_irq_bridge_remove,
+ .driver = {
+ .name = MODULE_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = qsee_ipc_irq_bridge_match_table,
+ },
+};
+
+static int __init qsee_ipc_irq_bridge_init(void)
+{
+ int ret;
+
+ ret = qiib_driver_data_init();
+ if (ret) {
+ QIIB_ERR("%s: driver data init failed %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ ret = platform_driver_register(&qsee_ipc_irq_bridge_driver);
+ if (ret) {
+ QIIB_ERR("%s: platform driver register failed %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+module_init(qsee_ipc_irq_bridge_init);
+
+static void __exit qsee_ipc_irq_bridge_exit(void)
+{
+ platform_driver_unregister(&qsee_ipc_irq_bridge_driver);
+ qiib_driver_data_deinit();
+}
+module_exit(qsee_ipc_irq_bridge_exit);
+MODULE_DESCRIPTION("QSEE IPC interrupt bridge");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c
index 17e0a4c..8a7043a6 100644
--- a/drivers/soc/qcom/rpmh.c
+++ b/drivers/soc/qcom/rpmh.c
@@ -77,6 +77,8 @@
DECLARE_BITMAP(fast_req, RPMH_MAX_FAST_RES);
bool dirty;
bool in_solver_mode;
+ /* Cache sleep and wake requests sent as passthru */
+ struct rpmh_msg *passthru_cache[2 * RPMH_MAX_REQ_IN_BATCH];
};
struct rpmh_client {
@@ -111,17 +113,24 @@
return msg;
}
+static void __free_msg_to_pool(struct rpmh_msg *rpm_msg)
+{
+ struct rpmh_mbox *rpm = rpm_msg->rc->rpmh;
+
+ /* If we allocated the pool, set it as available */
+ if (rpm_msg->bit >= 0 && rpm_msg->bit != RPMH_MAX_FAST_RES) {
+ bitmap_clear(rpm->fast_req, rpm_msg->bit, 1);
+ }
+}
+
static void free_msg_to_pool(struct rpmh_msg *rpm_msg)
{
struct rpmh_mbox *rpm = rpm_msg->rc->rpmh;
unsigned long flags;
- /* If we allocated the pool, set it as available */
- if (rpm_msg->bit >= 0 && rpm_msg->bit != RPMH_MAX_FAST_RES) {
- spin_lock_irqsave(&rpm->lock, flags);
- bitmap_clear(rpm->fast_req, rpm_msg->bit, 1);
- spin_unlock_irqrestore(&rpm->lock, flags);
- }
+ spin_lock_irqsave(&rpm->lock, flags);
+ __free_msg_to_pool(rpm_msg);
+ spin_unlock_irqrestore(&rpm->lock, flags);
}
static void rpmh_rx_cb(struct mbox_client *cl, void *msg)
@@ -181,6 +190,7 @@
{
int ret;
int count = 4;
+ int skip = 0;
do {
ret = wait_for_completion_timeout(compl, RPMH_TIMEOUT);
@@ -192,7 +202,12 @@
return;
}
if (!count) {
+ if (skip++ % 100)
+ continue;
+ dev_err(rc->dev,
+ "RPMH waiting for interrupt from AOSS\n");
mbox_chan_debug(rc->chan);
+ BUG();
} else {
dev_err(rc->dev,
"RPMH response timeout (%d) addr=0x%x,data=0x%x\n",
@@ -511,6 +526,70 @@
}
EXPORT_SYMBOL(rpmh_write);
+static int cache_passthru(struct rpmh_client *rc, struct rpmh_msg **rpm_msg,
+ int count)
+{
+ struct rpmh_mbox *rpm = rc->rpmh;
+ unsigned long flags;
+ int ret = 0;
+ int index = 0;
+ int i;
+
+ spin_lock_irqsave(&rpm->lock, flags);
+ while (rpm->passthru_cache[index])
+ index++;
+ if (index + count >= 2 * RPMH_MAX_REQ_IN_BATCH) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ for (i = 0; i < count; i++)
+ rpm->passthru_cache[index + i] = rpm_msg[i];
+fail:
+ spin_unlock_irqrestore(&rpm->lock, flags);
+
+ return ret;
+}
+
+static int flush_passthru(struct rpmh_client *rc)
+{
+ struct rpmh_mbox *rpm = rc->rpmh;
+ struct rpmh_msg *rpm_msg;
+ unsigned long flags;
+ int ret = 0;
+ int i;
+
+ /* Send Sleep/Wake requests to the controller, expect no response */
+ spin_lock_irqsave(&rpm->lock, flags);
+ for (i = 0; rpm->passthru_cache[i]; i++) {
+ rpm_msg = rpm->passthru_cache[i];
+ ret = mbox_send_controller_data(rc->chan, &rpm_msg->msg);
+ if (ret)
+ goto fail;
+ }
+fail:
+ spin_unlock_irqrestore(&rpm->lock, flags);
+
+ return ret;
+}
+
+static void invalidate_passthru(struct rpmh_client *rc)
+{
+ struct rpmh_mbox *rpm = rc->rpmh;
+ unsigned long flags;
+ int index = 0;
+ int i;
+
+ spin_lock_irqsave(&rpm->lock, flags);
+ while (rpm->passthru_cache[index])
+ index++;
+ for (i = 0; i < index; i++) {
+ __free_msg_to_pool(rpm->passthru_cache[i]);
+ rpm->passthru_cache[i] = NULL;
+ }
+ spin_unlock_irqrestore(&rpm->lock, flags);
+}
+
/**
* rpmh_write_passthru: Write multiple batches of RPMH commands without caching
*
@@ -530,7 +609,7 @@
int rpmh_write_passthru(struct rpmh_client *rc, enum rpmh_state state,
struct tcs_cmd *cmd, int *n)
{
- struct rpmh_msg *rpm_msg[RPMH_MAX_REQ_IN_BATCH];
+ struct rpmh_msg *rpm_msg[RPMH_MAX_REQ_IN_BATCH] = { NULL };
DECLARE_COMPLETION_ONSTACK(compl);
atomic_t wait_count = ATOMIC_INIT(0); /* overwritten */
int count = 0;
@@ -548,7 +627,7 @@
if (ret)
return ret;
- while (n[count++])
+ while (n[count++] > 0)
;
count--;
if (!count || count > RPMH_MAX_REQ_IN_BATCH)
@@ -607,14 +686,11 @@
rpmh_tx_done(&rc->client, &rpm_msg[j]->msg, ret);
wait_for_tx_done(rc, &compl, addr, data);
} else {
- /* Send Sleep requests to the controller, expect no response */
- for (i = 0; i < count; i++) {
- rpm_msg[i]->completion = NULL;
- ret = mbox_send_controller_data(rc->chan,
- &rpm_msg[i]->msg);
- free_msg_to_pool(rpm_msg[i]);
- }
- return 0;
+ /*
+ * Cache sleep/wake data in store.
+ * But flush passthru first before flushing all other data.
+ */
+ return cache_passthru(rc, rpm_msg, count);
}
return 0;
@@ -674,7 +750,7 @@
{
DEFINE_RPMH_MSG_ONSTACK(rc, 0, NULL, NULL, rpm_msg);
- if (IS_ERR_OR_NULL(rc) || n > MAX_RPMH_PAYLOAD)
+ if (IS_ERR_OR_NULL(rc) || n <= 0 || n > MAX_RPMH_PAYLOAD)
return -EINVAL;
if (rpmh_standalone)
@@ -710,6 +786,8 @@
if (rpmh_standalone)
return 0;
+ invalidate_passthru(rc);
+
rpm = rc->rpmh;
rpm_msg.msg.invalidate = true;
rpm_msg.msg.is_complete = false;
@@ -767,6 +845,28 @@
}
EXPORT_SYMBOL(rpmh_read);
+/**
+ * rpmh_ctrlr_idle: Check if the controller is idle
+ *
+ * @rc: The RPMH handle got from rpmh_get_dev_channel
+ *
+ * Returns if the controller is idle or not.
+ */
+int rpmh_ctrlr_idle(struct rpmh_client *rc)
+{
+ if (IS_ERR_OR_NULL(rc))
+ return -EINVAL;
+
+ if (rpmh_standalone)
+ return 0;
+
+ if (!mbox_controller_is_idle(rc->chan))
+ return -EBUSY;
+
+ return 0;
+}
+EXPORT_SYMBOL(rpmh_ctrlr_idle);
+
static inline int is_req_valid(struct rpmh_req *req)
{
return (req->sleep_val != UINT_MAX && req->wake_val != UINT_MAX
@@ -823,6 +923,11 @@
}
spin_unlock_irqrestore(&rpm->lock, flags);
+ /* First flush the cached passthru's */
+ ret = flush_passthru(rc);
+ if (ret)
+ return ret;
+
/*
* Nobody else should be calling this function other than sleep,
* hence we can run without locks.
@@ -906,8 +1011,10 @@
rpmh->msg_pool = kzalloc(sizeof(struct rpmh_msg) *
RPMH_MAX_FAST_RES, GFP_KERNEL);
- if (!rpmh->msg_pool)
+ if (!rpmh->msg_pool) {
+ of_node_put(spec.np);
return ERR_PTR(-ENOMEM);
+ }
rpmh->mbox_dn = spec.np;
INIT_LIST_HEAD(&rpmh->resources);
diff --git a/drivers/soc/qcom/scm.c b/drivers/soc/qcom/scm.c
index fcb3731..ac5cc54 100644
--- a/drivers/soc/qcom/scm.c
+++ b/drivers/soc/qcom/scm.c
@@ -397,18 +397,22 @@
__asmeq("%1", R1_STR)
__asmeq("%2", R2_STR)
__asmeq("%3", R3_STR)
- __asmeq("%4", R0_STR)
- __asmeq("%5", R1_STR)
- __asmeq("%6", R2_STR)
- __asmeq("%7", R3_STR)
- __asmeq("%8", R4_STR)
- __asmeq("%9", R5_STR)
- __asmeq("%10", R6_STR)
+ __asmeq("%4", R4_STR)
+ __asmeq("%5", R5_STR)
+ __asmeq("%6", R6_STR)
+ __asmeq("%7", R0_STR)
+ __asmeq("%8", R1_STR)
+ __asmeq("%9", R2_STR)
+ __asmeq("%10", R3_STR)
+ __asmeq("%11", R4_STR)
+ __asmeq("%12", R5_STR)
+ __asmeq("%13", R6_STR)
#ifdef REQUIRES_SEC
".arch_extension sec\n"
#endif
"smc #0\n"
- : "=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3)
+ : "=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3),
+ "=r" (r4), "=r" (r5), "=r" (r6)
: "r" (r0), "r" (r1), "r" (r2), "r" (r3), "r" (r4),
"r" (r5), "r" (r6)
: "x7", "x8", "x9", "x10", "x11", "x12", "x13",
@@ -442,18 +446,22 @@
__asmeq("%1", R1_STR)
__asmeq("%2", R2_STR)
__asmeq("%3", R3_STR)
- __asmeq("%4", R0_STR)
- __asmeq("%5", R1_STR)
- __asmeq("%6", R2_STR)
- __asmeq("%7", R3_STR)
- __asmeq("%8", R4_STR)
- __asmeq("%9", R5_STR)
- __asmeq("%10", R6_STR)
+ __asmeq("%4", R4_STR)
+ __asmeq("%5", R5_STR)
+ __asmeq("%6", R6_STR)
+ __asmeq("%7", R0_STR)
+ __asmeq("%8", R1_STR)
+ __asmeq("%9", R2_STR)
+ __asmeq("%10", R3_STR)
+ __asmeq("%11", R4_STR)
+ __asmeq("%12", R5_STR)
+ __asmeq("%13", R6_STR)
#ifdef REQUIRES_SEC
".arch_extension sec\n"
#endif
"smc #0\n"
- : "=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3)
+ : "=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3),
+ "=r" (r4), "=r" (r5), "=r" (r6)
: "r" (r0), "r" (r1), "r" (r2), "r" (r3), "r" (r4),
"r" (r5), "r" (r6)
: "x7", "x8", "x9", "x10", "x11", "x12", "x13",
@@ -490,18 +498,22 @@
__asmeq("%1", R1_STR)
__asmeq("%2", R2_STR)
__asmeq("%3", R3_STR)
- __asmeq("%4", R0_STR)
- __asmeq("%5", R1_STR)
- __asmeq("%6", R2_STR)
- __asmeq("%7", R3_STR)
- __asmeq("%8", R4_STR)
- __asmeq("%9", R5_STR)
- __asmeq("%10", R6_STR)
+ __asmeq("%4", R4_STR)
+ __asmeq("%5", R5_STR)
+ __asmeq("%6", R6_STR)
+ __asmeq("%7", R0_STR)
+ __asmeq("%8", R1_STR)
+ __asmeq("%9", R2_STR)
+ __asmeq("%10", R3_STR)
+ __asmeq("%11", R4_STR)
+ __asmeq("%12", R5_STR)
+ __asmeq("%13", R6_STR)
#ifdef REQUIRES_SEC
".arch_extension sec\n"
#endif
"smc #0\n"
- : "=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3)
+ : "=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3),
+ "=r" (r4), "=r" (r5), "=r" (r6)
: "r" (r0), "r" (r1), "r" (r2), "r" (r3), "r" (r4),
"r" (r5), "r" (r6));
@@ -668,10 +680,6 @@
desc->ret[0] = desc->ret[1] = desc->ret[2] = 0;
- pr_debug("scm_call: func id %#llx, args: %#x, %#llx, %#llx, %#llx, %#llx\n",
- x0, desc->arginfo, desc->args[0], desc->args[1],
- desc->args[2], desc->x5);
-
trace_scm_call_start(x0, desc);
if (scm_version == SCM_ARMV8_64)
@@ -701,10 +709,8 @@
} while (ret == SCM_V2_EBUSY && (retry_count++ < SCM_EBUSY_MAX_RETRY));
if (ret < 0)
- pr_err("scm_call failed: func id %#llx, arginfo: %#x, args: %#llx, %#llx, %#llx, %#llx, ret: %d, syscall returns: %#llx, %#llx, %#llx\n",
- x0, desc->arginfo, desc->args[0], desc->args[1],
- desc->args[2], desc->x5, ret, desc->ret[0],
- desc->ret[1], desc->ret[2]);
+ pr_err("scm_call failed: func id %#llx, ret: %d, syscall returns: %#llx, %#llx, %#llx\n",
+ x0, ret, desc->ret[0], desc->ret[1], desc->ret[2]);
if (arglen > N_REGISTER_ARGS)
kfree(desc->extra_arg_buf);
@@ -737,10 +743,6 @@
x0 = fn_id | BIT(SMC_ATOMIC_SYSCALL) | scm_version_mask;
- pr_debug("scm_call: func id %#llx, args: %#x, %#llx, %#llx, %#llx, %#llx\n",
- x0, desc->arginfo, desc->args[0], desc->args[1],
- desc->args[2], desc->x5);
-
if (scm_version == SCM_ARMV8_64)
ret = __scm_call_armv8_64(x0, desc->arginfo, desc->args[0],
desc->args[1], desc->args[2],
@@ -752,9 +754,8 @@
desc->x5, &desc->ret[0],
&desc->ret[1], &desc->ret[2]);
if (ret < 0)
- pr_err("scm_call failed: func id %#llx, arginfo: %#x, args: %#llx, %#llx, %#llx, %#llx, ret: %d, syscall returns: %#llx, %#llx, %#llx\n",
- x0, desc->arginfo, desc->args[0], desc->args[1],
- desc->args[2], desc->x5, ret, desc->ret[0],
+ pr_err("scm_call failed: func id %#llx, ret: %d, syscall returns: %#llx, %#llx, %#llx\n",
+ x0, ret, desc->ret[0],
desc->ret[1], desc->ret[2]);
if (arglen > N_REGISTER_ARGS)
diff --git a/drivers/soc/qcom/secure_buffer.c b/drivers/soc/qcom/secure_buffer.c
index 49fd7fe..6553ac0 100644
--- a/drivers/soc/qcom/secure_buffer.c
+++ b/drivers/soc/qcom/secure_buffer.c
@@ -25,29 +25,12 @@
DEFINE_MUTEX(secure_buffer_mutex);
-struct cp2_mem_chunks {
- u32 chunk_list;
- u32 chunk_list_size;
- u32 chunk_size;
-} __attribute__ ((__packed__));
-
-struct cp2_lock_req {
- struct cp2_mem_chunks chunks;
- u32 mem_usage;
- u32 lock;
-} __attribute__ ((__packed__));
-
-
struct mem_prot_info {
phys_addr_t addr;
u64 size;
};
#define MEM_PROT_ASSIGN_ID 0x16
-#define MEM_PROTECT_LOCK_ID2 0x0A
-#define MEM_PROTECT_LOCK_ID2_FLAT 0x11
-#define V2_CHUNK_SIZE SZ_1M
-#define FEATURE_ID_CP 12
struct dest_vm_and_perm_info {
u32 vm;
@@ -59,137 +42,6 @@
static void *qcom_secure_mem;
#define QCOM_SECURE_MEM_SIZE (512*1024)
-static int secure_buffer_change_chunk(u32 chunks,
- u32 nchunks,
- u32 chunk_size,
- int lock)
-{
- struct cp2_lock_req request;
- u32 resp;
- int ret;
- struct scm_desc desc = {0};
-
- desc.args[0] = request.chunks.chunk_list = chunks;
- desc.args[1] = request.chunks.chunk_list_size = nchunks;
- desc.args[2] = request.chunks.chunk_size = chunk_size;
- /* Usage is now always 0 */
- desc.args[3] = request.mem_usage = 0;
- desc.args[4] = request.lock = lock;
- desc.args[5] = 0;
- desc.arginfo = SCM_ARGS(6, SCM_RW, SCM_VAL, SCM_VAL, SCM_VAL, SCM_VAL,
- SCM_VAL);
-
- kmap_flush_unused();
- kmap_atomic_flush_unused();
-
- if (!is_scm_armv8()) {
- ret = scm_call(SCM_SVC_MP, MEM_PROTECT_LOCK_ID2,
- &request, sizeof(request), &resp, sizeof(resp));
- } else {
- ret = scm_call2(SCM_SIP_FNID(SCM_SVC_MP,
- MEM_PROTECT_LOCK_ID2_FLAT), &desc);
- resp = desc.ret[0];
- }
-
- return ret;
-}
-
-
-
-static int secure_buffer_change_table(struct sg_table *table, int lock)
-{
- int i, j;
- int ret = -EINVAL;
- u32 *chunk_list;
- struct scatterlist *sg;
-
- for_each_sg(table->sgl, sg, table->nents, i) {
- int nchunks;
- int size = sg->length;
- int chunk_list_len;
- phys_addr_t chunk_list_phys;
-
- /*
- * This should theoretically be a phys_addr_t but the protocol
- * indicates this should be a u32.
- */
- u32 base;
- u64 tmp = sg_dma_address(sg);
-
- WARN((tmp >> 32) & 0xffffffff,
- "%s: there are ones in the upper 32 bits of the sg at %p! They will be truncated! Address: 0x%llx\n",
- __func__, sg, tmp);
- if (unlikely(!size || (size % V2_CHUNK_SIZE))) {
- WARN(1,
- "%s: chunk %d has invalid size: 0x%x. Must be a multiple of 0x%x\n",
- __func__, i, size, V2_CHUNK_SIZE);
- return -EINVAL;
- }
-
- base = (u32)tmp;
-
- nchunks = size / V2_CHUNK_SIZE;
- chunk_list_len = sizeof(u32)*nchunks;
-
- chunk_list = kzalloc(chunk_list_len, GFP_KERNEL);
-
- if (!chunk_list)
- return -ENOMEM;
-
- chunk_list_phys = virt_to_phys(chunk_list);
- for (j = 0; j < nchunks; j++)
- chunk_list[j] = base + j * V2_CHUNK_SIZE;
-
- /*
- * Flush the chunk list before sending the memory to the
- * secure environment to ensure the data is actually present
- * in RAM
- */
- dmac_flush_range(chunk_list, chunk_list + chunk_list_len);
-
- ret = secure_buffer_change_chunk(virt_to_phys(chunk_list),
- nchunks, V2_CHUNK_SIZE, lock);
-
- if (!ret) {
- /*
- * Set or clear the private page flag to communicate the
- * status of the chunk to other entities
- */
- if (lock)
- SetPagePrivate(sg_page(sg));
- else
- ClearPagePrivate(sg_page(sg));
- }
-
- kfree(chunk_list);
- }
-
- return ret;
-}
-
-int msm_secure_table(struct sg_table *table)
-{
- int ret;
-
- mutex_lock(&secure_buffer_mutex);
- ret = secure_buffer_change_table(table, 1);
- mutex_unlock(&secure_buffer_mutex);
-
- return ret;
-
-}
-
-int msm_unsecure_table(struct sg_table *table)
-{
- int ret;
-
- mutex_lock(&secure_buffer_mutex);
- ret = secure_buffer_change_table(table, 0);
- mutex_unlock(&secure_buffer_mutex);
- return ret;
-
-}
-
static struct dest_vm_and_perm_info *
populate_dest_info(int *dest_vmids, int nelements, int *dest_perms,
size_t *size_in_bytes)
@@ -426,20 +278,6 @@
}
}
-#define MAKE_CP_VERSION(major, minor, patch) \
- (((major & 0x3FF) << 22) | ((minor & 0x3FF) << 12) | (patch & 0xFFF))
-
-bool msm_secure_v2_is_supported(void)
-{
- int version = scm_get_feat_version(FEATURE_ID_CP);
-
- /*
- * if the version is < 1.1.0 then dynamic buffer allocation is
- * not supported
- */
- return version >= MAKE_CP_VERSION(1, 1, 0);
-}
-
static int __init alloc_secure_shared_memory(void)
{
int ret = 0;
diff --git a/drivers/soc/qcom/service-notifier.c b/drivers/soc/qcom/service-notifier.c
index 221ae0c..f4c67f1 100644
--- a/drivers/soc/qcom/service-notifier.c
+++ b/drivers/soc/qcom/service-notifier.c
@@ -84,6 +84,7 @@
struct ind_req_resp {
char service_path[SERVREG_NOTIF_NAME_LENGTH];
int transaction_id;
+ int curr_state;
};
/*
@@ -200,8 +201,30 @@
struct qmi_servreg_notif_set_ack_req_msg_v01 req;
struct msg_desc req_desc, resp_desc;
struct qmi_servreg_notif_set_ack_resp_msg_v01 resp = { { 0, 0 } };
+ struct service_notif_info *service_notif;
+ enum pd_subsys_state state = USER_PD_STATE_CHANGE;
int rc;
+ service_notif = _find_service_info(data->ind_msg.service_path);
+ if (!service_notif)
+ return;
+ if ((int)data->ind_msg.curr_state < QMI_STATE_MIN_VAL ||
+ (int)data->ind_msg.curr_state > QMI_STATE_MAX_VAL)
+ pr_err("Unexpected indication notification state %d\n",
+ data->ind_msg.curr_state);
+ else {
+ mutex_lock(¬if_add_lock);
+ mutex_lock(&service_list_lock);
+ rc = service_notif_queue_notification(service_notif,
+ data->ind_msg.curr_state, &state);
+ if (rc & NOTIFY_STOP_MASK)
+ pr_err("Notifier callback aborted for %s with error %d\n",
+ data->ind_msg.service_path, rc);
+ service_notif->curr_state = data->ind_msg.curr_state;
+ mutex_unlock(&service_list_lock);
+ mutex_unlock(¬if_add_lock);
+ }
+
req.transaction_id = data->ind_msg.transaction_id;
snprintf(req.service_name, ARRAY_SIZE(req.service_name), "%s",
data->ind_msg.service_path);
@@ -236,11 +259,9 @@
unsigned int msg_len, void *ind_cb_priv)
{
struct qmi_client_info *data = (struct qmi_client_info *)ind_cb_priv;
- struct service_notif_info *service_notif;
struct msg_desc ind_desc;
struct qmi_servreg_notif_state_updated_ind_msg_v01 ind_msg = {
QMI_STATE_MIN_VAL, "", 0xFFFF };
- enum pd_subsys_state state = USER_PD_STATE_CHANGE;
int rc;
ind_desc.msg_id = SERVREG_NOTIF_STATE_UPDATED_IND_MSG;
@@ -256,27 +277,8 @@
ind_msg.service_name, ind_msg.curr_state,
ind_msg.transaction_id);
- service_notif = _find_service_info(ind_msg.service_name);
- if (!service_notif)
- return;
-
- if ((int)ind_msg.curr_state < QMI_STATE_MIN_VAL ||
- (int)ind_msg.curr_state > QMI_STATE_MAX_VAL)
- pr_err("Unexpected indication notification state %d\n",
- ind_msg.curr_state);
- else {
- mutex_lock(¬if_add_lock);
- mutex_lock(&service_list_lock);
- rc = service_notif_queue_notification(service_notif,
- ind_msg.curr_state, &state);
- if (rc & NOTIFY_STOP_MASK)
- pr_err("Notifier callback aborted for %s with error %d\n",
- ind_msg.service_name, rc);
- service_notif->curr_state = ind_msg.curr_state;
- mutex_unlock(&service_list_lock);
- mutex_unlock(¬if_add_lock);
- }
data->ind_msg.transaction_id = ind_msg.transaction_id;
+ data->ind_msg.curr_state = ind_msg.curr_state;
snprintf(data->ind_msg.service_path,
ARRAY_SIZE(data->ind_msg.service_path), "%s",
ind_msg.service_name);
@@ -373,6 +375,12 @@
mutex_unlock(&qmi_client_release_lock);
pr_info("Connection established between QMI handle and %d service\n",
data->instance_id);
+ /* Register for indication messages about service */
+ rc = qmi_register_ind_cb(data->clnt_handle,
+ root_service_service_ind_cb, (void *)data);
+ if (rc < 0)
+ pr_err("Indication callback register failed(instance-id: %d) rc:%d\n",
+ data->instance_id, rc);
mutex_lock(¬if_add_lock);
mutex_lock(&service_list_lock);
list_for_each_entry(service_notif, &service_list, list) {
@@ -395,12 +403,6 @@
}
mutex_unlock(&service_list_lock);
mutex_unlock(¬if_add_lock);
- /* Register for indication messages about service */
- rc = qmi_register_ind_cb(data->clnt_handle,
- root_service_service_ind_cb, (void *)data);
- if (rc < 0)
- pr_err("Indication callback register failed(instance-id: %d) rc:%d\n",
- data->instance_id, rc);
}
static void root_service_service_exit(struct qmi_client_info *data,
diff --git a/drivers/soc/qcom/smp2p_sleepstate.c b/drivers/soc/qcom/smp2p_sleepstate.c
index 5b0129e..9c764aa 100644
--- a/drivers/soc/qcom/smp2p_sleepstate.c
+++ b/drivers/soc/qcom/smp2p_sleepstate.c
@@ -14,6 +14,8 @@
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/suspend.h>
+#include <linux/delay.h>
+#include <linux/ipc_router.h>
#include "smp2p_private.h"
#define SET_DELAY (2 * HZ)
@@ -35,10 +37,14 @@
switch (event) {
case PM_SUSPEND_PREPARE:
gpio_set_value(slst_gpio_base_id + PROC_AWAKE_ID, 0);
+ msleep(25); /* To be tuned based on SMP2P latencies */
+ msm_ipc_router_set_ws_allowed(true);
break;
case PM_POST_SUSPEND:
gpio_set_value(slst_gpio_base_id + PROC_AWAKE_ID, 1);
+ msleep(25); /* To be tuned based on SMP2P latencies */
+ msm_ipc_router_set_ws_allowed(false);
break;
}
return NOTIFY_DONE;
diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c
index 31760ee..c69429c 100644
--- a/drivers/soc/qcom/socinfo.c
+++ b/drivers/soc/qcom/socinfo.c
@@ -592,10 +592,11 @@
}
EXPORT_SYMBOL_GPL(socinfo_get_id);
-static char *socinfo_get_id_string(void)
+char *socinfo_get_id_string(void)
{
return (socinfo) ? cpu_of_id[socinfo->v0_1.id].soc_id_string : NULL;
}
+EXPORT_SYMBOL(socinfo_get_id_string);
uint32_t socinfo_get_version(void)
{
diff --git a/drivers/soc/qcom/spcom.c b/drivers/soc/qcom/spcom.c
index 1c7c4a1..806b756 100644
--- a/drivers/soc/qcom/spcom.c
+++ b/drivers/soc/qcom/spcom.c
@@ -93,8 +93,6 @@
/* SPCOM driver name */
#define DEVICE_NAME "spcom"
-#define SPCOM_MAX_CHANNELS 0x20
-
/* maximum ION buffers should be >= SPCOM_MAX_CHANNELS */
#define SPCOM_MAX_ION_BUF_PER_CH (SPCOM_MAX_CHANNELS + 4)
@@ -195,6 +193,7 @@
* glink state: CONNECTED / LOCAL_DISCONNECTED, REMOTE_DISCONNECTED
*/
unsigned int glink_state;
+ bool is_closing;
/* Events notification */
struct completion connect;
@@ -244,7 +243,7 @@
int channel_count;
/* private */
- struct mutex lock;
+ struct mutex cmd_lock;
/* Link state */
struct completion link_state_changed;
@@ -483,7 +482,17 @@
switch (event) {
case GLINK_CONNECTED:
pr_debug("GLINK_CONNECTED, ch name [%s].\n", ch->name);
+ mutex_lock(&ch->lock);
+
+ if (ch->is_closing) {
+ pr_err("Unexpected CONNECTED while closing [%s].\n",
+ ch->name);
+ mutex_unlock(&ch->lock);
+ return;
+ }
+
ch->glink_state = event;
+
/*
* if spcom_notify_state() is called within glink_open()
* then ch->glink_handle is not updated yet.
@@ -493,17 +502,28 @@
ch->glink_handle = handle;
}
- /* prepare default rx buffer after connected */
+ /* signal before unlock mutex & before calling glink */
+ complete_all(&ch->connect);
+
+ /*
+ * Prepare default rx buffer.
+ * glink_queue_rx_intent() can be called only AFTER connected.
+ * We do it here, ASAP, to allow rx data.
+ */
+
+ pr_debug("call glink_queue_rx_intent() ch [%s].\n", ch->name);
ret = glink_queue_rx_intent(ch->glink_handle,
ch, ch->rx_buf_size);
if (ret) {
pr_err("glink_queue_rx_intent() err [%d]\n", ret);
} else {
- pr_debug("rx buf is ready, size [%zu].\n",
+ pr_debug("rx buf is ready, size [%zu]\n",
ch->rx_buf_size);
ch->rx_buf_ready = true;
}
- complete_all(&ch->connect);
+
+ pr_debug("GLINK_CONNECTED, ch name [%s] done.\n", ch->name);
+ mutex_unlock(&ch->lock);
break;
case GLINK_LOCAL_DISCONNECTED:
/*
@@ -556,9 +576,7 @@
static bool spcom_notify_rx_intent_req(void *handle, const void *priv,
size_t req_size)
{
- struct spcom_channel *ch = (struct spcom_channel *) priv;
-
- pr_err("Unexpected intent request for ch [%s].\n", ch->name);
+ pr_err("Unexpected intent request\n");
return false;
}
@@ -670,6 +688,13 @@
ch->glink_state = GLINK_LOCAL_DISCONNECTED;
ch->actual_rx_size = 0;
ch->rx_buf_size = SPCOM_RX_BUF_SIZE;
+ ch->is_closing = false;
+ ch->glink_handle = NULL;
+ ch->ref_count = 0;
+ ch->rx_abort = false;
+ ch->tx_abort = false;
+ ch->txn_id = INITIAL_TXN_ID; /* use non-zero nonce for debug */
+ ch->pid = 0;
return 0;
}
@@ -739,6 +764,8 @@
/* init completion before calling glink_open() */
reinit_completion(&ch->connect);
+ ch->is_closing = false;
+
handle = glink_open(&cfg);
if (IS_ERR_OR_NULL(handle)) {
pr_err("glink_open failed.\n");
@@ -753,6 +780,8 @@
ch->pid = current_pid();
ch->txn_id = INITIAL_TXN_ID;
+ mutex_unlock(&ch->lock);
+
pr_debug("Wait for connection on channel [%s] timeout_msec [%d].\n",
name, timeout_msec);
@@ -769,8 +798,6 @@
pr_debug("Channel [%s] opened, no timeout.\n", name);
}
- mutex_unlock(&ch->lock);
-
return 0;
exit_err:
mutex_unlock(&ch->lock);
@@ -797,6 +824,8 @@
return 0;
}
+ ch->is_closing = true;
+
ret = glink_close(ch->glink_handle);
if (ret)
pr_err("glink_close() fail, ret [%d].\n", ret);
@@ -812,6 +841,7 @@
ch->pid = 0;
pr_debug("Channel closed [%s].\n", ch->name);
+
mutex_unlock(&ch->lock);
return 0;
@@ -1090,12 +1120,12 @@
if (!spcom_is_ready()) {
pr_err("spcom is not ready.\n");
- return NULL;
+ return NULL;
}
if (!info) {
pr_err("Invalid parameter.\n");
- return NULL;
+ return NULL;
}
name = info->ch_name;
@@ -1924,18 +1954,6 @@
}
/**
- * spcom_handle_fake_ssr_command() - Handle fake ssr command from user space.
- */
-static int spcom_handle_fake_ssr_command(struct spcom_channel *ch, int arg)
-{
- pr_debug("Start Fake glink SSR subsystem [%s].\n", spcom_edge);
- glink_ssr(spcom_edge);
- pr_debug("Fake glink SSR subsystem [%s] done.\n", spcom_edge);
-
- return 0;
-}
-
-/**
* spcom_handle_write() - Handle user space write commands.
*
* @buf: command buffer.
@@ -1964,6 +1982,8 @@
swap_id = htonl(cmd->cmd_id);
memcpy(cmd_name, &swap_id, sizeof(int));
+ mutex_lock(&spcom_dev->cmd_lock);
+
pr_debug("cmd_id [0x%x] cmd_name [%s].\n", cmd_id, cmd_name);
switch (cmd_id) {
@@ -1979,17 +1999,16 @@
case SPCOM_CMD_UNLOCK_ION_BUF:
ret = spcom_handle_unlock_ion_buf_command(ch, buf, buf_size);
break;
- case SPCOM_CMD_FSSR:
- ret = spcom_handle_fake_ssr_command(ch, cmd->arg);
- break;
case SPCOM_CMD_CREATE_CHANNEL:
ret = spcom_handle_create_channel_command(buf, buf_size);
break;
default:
pr_err("Invalid Command Id [0x%x].\n", (int) cmd->cmd_id);
- return -EINVAL;
+ ret = -EINVAL;
}
+ mutex_unlock(&spcom_dev->cmd_lock);
+
return ret;
}
@@ -2690,7 +2709,7 @@
return -ENOMEM;
spcom_dev = dev;
- mutex_init(&dev->lock);
+ mutex_init(&spcom_dev->cmd_lock);
init_completion(&dev->link_state_changed);
spcom_dev->link_state = GLINK_LINK_STATE_DOWN;
@@ -2763,7 +2782,7 @@
{
int ret;
- pr_info("spcom driver Ver 1.0 23-Nov-2015.\n");
+ pr_info("spcom driver version 1.1 17-July-2017.\n");
ret = platform_driver_register(&spcom_driver);
if (ret)
diff --git a/drivers/soc/qcom/subsys-pil-tz.c b/drivers/soc/qcom/subsys-pil-tz.c
index f8f6829..01eb260 100644
--- a/drivers/soc/qcom/subsys-pil-tz.c
+++ b/drivers/soc/qcom/subsys-pil-tz.c
@@ -795,6 +795,33 @@
return rc;
}
+static int pil_deinit_image_trusted(struct pil_desc *pil)
+{
+ struct pil_tz_data *d = desc_to_data(pil);
+ u32 proc, scm_ret = 0;
+ int rc;
+ struct scm_desc desc = {0};
+
+ if (d->subsys_desc.no_auth)
+ return 0;
+
+ desc.args[0] = proc = d->pas_id;
+ desc.arginfo = SCM_ARGS(1);
+
+ if (!is_scm_armv8()) {
+ rc = scm_call(SCM_SVC_PIL, PAS_SHUTDOWN_CMD, &proc,
+ sizeof(proc), &scm_ret, sizeof(scm_ret));
+ } else {
+ rc = scm_call2(SCM_SIP_FNID(SCM_SVC_PIL, PAS_SHUTDOWN_CMD),
+ &desc);
+ scm_ret = desc.ret[0];
+ }
+
+ if (rc)
+ return rc;
+ return scm_ret;
+}
+
static struct pil_reset_ops pil_ops_trusted = {
.init_image = pil_init_image_trusted,
.mem_setup = pil_mem_setup_trusted,
@@ -802,6 +829,7 @@
.shutdown = pil_shutdown_trusted,
.proxy_vote = pil_make_proxy_vote,
.proxy_unvote = pil_remove_proxy_vote,
+ .deinit_image = pil_deinit_image_trusted,
};
static void log_failure_reason(const struct pil_tz_data *d)
diff --git a/drivers/soc/qcom/system_pm.c b/drivers/soc/qcom/system_pm.c
index f4f4c36..2ecbf15 100644
--- a/drivers/soc/qcom/system_pm.c
+++ b/drivers/soc/qcom/system_pm.c
@@ -15,6 +15,7 @@
#include <linux/platform_device.h>
#include <soc/qcom/rpmh.h>
+#include <soc/qcom/system_pm.h>
#define ARCH_TIMER_HZ (19200000UL)
#define PDC_TIME_VALID_SHIFT 31
@@ -34,6 +35,15 @@
}
/**
+ * system_sleep_allowed() - Returns if its okay to enter system low power modes
+ */
+bool system_sleep_allowed(void)
+{
+ return (rpmh_ctrlr_idle(rpmh_client) == 0);
+}
+EXPORT_SYMBOL(system_sleep_allowed);
+
+/**
* system_sleep_enter() - Activties done when entering system low power modes
*
* @sleep_val: The sleep duration in us.
diff --git a/drivers/soundwire/swr-wcd-ctrl.c b/drivers/soundwire/swr-wcd-ctrl.c
index e338d58..be0b5ce 100644
--- a/drivers/soundwire/swr-wcd-ctrl.c
+++ b/drivers/soundwire/swr-wcd-ctrl.c
@@ -396,11 +396,17 @@
return -EINVAL;
if (enable) {
- swrm->clk(swrm->handle, true);
- swrm->state = SWR_MSTR_UP;
- } else {
+ swrm->clk_ref_count++;
+ if (swrm->clk_ref_count == 1) {
+ swrm->clk(swrm->handle, true);
+ swrm->state = SWR_MSTR_UP;
+ }
+ } else if (--swrm->clk_ref_count == 0) {
swrm->clk(swrm->handle, false);
swrm->state = SWR_MSTR_DOWN;
+ } else if (swrm->clk_ref_count < 0) {
+ pr_err("%s: swrm clk count mismatch\n", __func__);
+ swrm->clk_ref_count = 0;
}
return 0;
}
@@ -1170,7 +1176,10 @@
u8 devnum = 0;
int ret = IRQ_HANDLED;
- pm_runtime_get_sync(&swrm->pdev->dev);
+ mutex_lock(&swrm->reslock);
+ swrm_clk_request(swrm, true);
+ mutex_unlock(&swrm->reslock);
+
intr_sts = swrm->read(swrm->handle, SWRM_INTERRUPT_STATUS);
intr_sts &= SWRM_INTERRUPT_STATUS_RMSK;
for (i = 0; i < SWRM_INTERRUPT_MAX; i++) {
@@ -1258,8 +1267,10 @@
break;
}
}
- pm_runtime_mark_last_busy(&swrm->pdev->dev);
- pm_runtime_put_autosuspend(&swrm->pdev->dev);
+
+ mutex_lock(&swrm->reslock);
+ swrm_clk_request(swrm, false);
+ mutex_unlock(&swrm->reslock);
return ret;
}
@@ -1447,6 +1458,7 @@
swrm->wcmd_id = 0;
swrm->slave_status = 0;
swrm->num_rx_chs = 0;
+ swrm->clk_ref_count = 0;
swrm->state = SWR_MSTR_RESUME;
init_completion(&swrm->reset);
init_completion(&swrm->broadcast);
diff --git a/drivers/soundwire/swr-wcd-ctrl.h b/drivers/soundwire/swr-wcd-ctrl.h
index b7a3eda..104ac8f 100644
--- a/drivers/soundwire/swr-wcd-ctrl.h
+++ b/drivers/soundwire/swr-wcd-ctrl.h
@@ -78,6 +78,7 @@
struct device *dev;
struct resource *supplies;
struct clk *mclk;
+ int clk_ref_count;
struct completion reset;
struct completion broadcast;
struct mutex mlock;
diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c
index ad3eb187..6acb731 100644
--- a/drivers/spi/spi-geni-qcom.c
+++ b/drivers/spi/spi-geni-qcom.c
@@ -12,18 +12,21 @@
*
*/
#include <linux/clk.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
+#include <linux/ipc_logging.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/pm_runtime.h>
#include <linux/qcom-geni-se.h>
+#include <linux/msm_gpi.h>
#include <linux/spi/spi.h>
#define SPI_NUM_CHIPSELECT (4)
#define SPI_XFER_TIMEOUT_MS (250)
-#define SPI_OVERSAMPLING (2)
/* SPI SE specific registers */
#define SE_SPI_CPHA (0x224)
#define SE_SPI_LOOPBACK (0x22C)
@@ -80,6 +83,36 @@
#define POST_CMD_DELAY BIT(4)
#define SPI_CORE2X_VOTE (10000)
+/* GSI CONFIG0 TRE Params */
+/* Flags bit fields */
+#define GSI_LOOPBACK_EN (BIT(0))
+#define GSI_CS_TOGGLE (BIT(3))
+#define GSI_CPHA (BIT(4))
+#define GSI_CPOL (BIT(5))
+
+#define MAX_TX_SG (3)
+#define NUM_SPI_XFER (8)
+
+struct gsi_desc_cb {
+ struct spi_master *spi;
+ struct spi_transfer *xfer;
+};
+
+struct spi_geni_gsi {
+ struct msm_gpi_tre config0_tre;
+ struct msm_gpi_tre go_tre;
+ struct msm_gpi_tre tx_dma_tre;
+ struct msm_gpi_tre rx_dma_tre;
+ struct scatterlist tx_sg[MAX_TX_SG];
+ struct scatterlist rx_sg;
+ dma_cookie_t tx_cookie;
+ dma_cookie_t rx_cookie;
+ struct msm_gpi_dma_async_tx_cb_param tx_cb_param;
+ struct msm_gpi_dma_async_tx_cb_param rx_cb_param;
+ struct dma_async_tx_descriptor *tx_desc;
+ struct dma_async_tx_descriptor *rx_desc;
+ struct gsi_desc_cb desc_cb;
+};
struct spi_geni_master {
struct se_geni_rsc spi_rsc;
@@ -100,6 +133,20 @@
struct spi_transfer *cur_xfer;
struct completion xfer_done;
struct device *wrapper_dev;
+ int oversampling;
+ struct spi_geni_gsi *gsi;
+ struct dma_chan *tx;
+ struct dma_chan *rx;
+ struct msm_gpi_ctrl tx_event;
+ struct msm_gpi_ctrl rx_event;
+ struct completion tx_cb;
+ struct completion rx_cb;
+ bool qn_err;
+ int cur_xfer_mode;
+ int num_tx_eot;
+ int num_rx_eot;
+ int num_xfers;
+ void *ipc;
};
static struct spi_master *get_spi_master(struct device *dev)
@@ -110,69 +157,68 @@
return spi;
}
-static int do_spi_clk_cfg(u32 speed_hz, struct spi_geni_master *mas)
+static int get_spi_clk_cfg(u32 speed_hz, struct spi_geni_master *mas,
+ int *clk_idx, int *clk_div)
{
unsigned long sclk_freq;
- int div = 0;
- int idx;
struct se_geni_rsc *rsc = &mas->spi_rsc;
- u32 clk_sel = geni_read_reg(mas->base, SE_GENI_CLK_SEL);
- u32 m_clk_cfg = geni_read_reg(mas->base, GENI_SER_M_CLK_CFG);
- int ret;
+ int ret = 0;
- clk_sel &= ~CLK_SEL_MSK;
- m_clk_cfg &= ~CLK_DIV_MSK;
-
- ret = geni_se_clk_freq_match(&mas->spi_rsc, speed_hz, &idx,
- &sclk_freq, true);
+ ret = geni_se_clk_freq_match(&mas->spi_rsc,
+ (speed_hz * mas->oversampling), clk_idx,
+ &sclk_freq, true);
if (ret) {
dev_err(mas->dev, "%s: Failed(%d) to find src clk for 0x%x\n",
__func__, ret, speed_hz);
return ret;
}
- div = ((sclk_freq / SPI_OVERSAMPLING) / speed_hz);
- if (!div)
+ *clk_div = ((sclk_freq / mas->oversampling) / speed_hz);
+ if (!(*clk_div)) {
+ dev_err(mas->dev, "%s:Err:sclk:%lu oversampling:%d speed:%u\n",
+ __func__, sclk_freq, mas->oversampling, speed_hz);
return -EINVAL;
+ }
dev_dbg(mas->dev, "%s: req %u sclk %lu, idx %d, div %d\n", __func__,
- speed_hz, sclk_freq, idx, div);
- clk_sel |= (idx & CLK_SEL_MSK);
- m_clk_cfg |= ((div << CLK_DIV_SHFT) | SER_CLK_EN);
+ speed_hz, sclk_freq, *clk_idx, *clk_div);
ret = clk_set_rate(rsc->se_clk, sclk_freq);
if (ret)
- return ret;
-
- geni_write_reg(clk_sel, mas->base, SE_GENI_CLK_SEL);
- geni_write_reg(m_clk_cfg, mas->base, GENI_SER_M_CLK_CFG);
- return 0;
+ dev_err(mas->dev, "%s: clk_set_rate failed %d\n",
+ __func__, ret);
+ return ret;
}
static void spi_setup_word_len(struct spi_geni_master *mas, u32 mode,
int bits_per_word)
{
- int pack_words = mas->tx_fifo_width / bits_per_word;
+ int pack_words = 0;
bool msb_first = (mode & SPI_LSB_FIRST) ? false : true;
u32 word_len = geni_read_reg(mas->base, SE_SPI_WORD_LEN);
+ if (!(mas->tx_fifo_width % bits_per_word))
+ pack_words = mas->tx_fifo_width / bits_per_word;
word_len &= ~WORD_LEN_MSK;
word_len |= ((bits_per_word - MIN_WORD_LEN) & WORD_LEN_MSK);
se_config_packing(mas->base, bits_per_word, pack_words, msb_first);
geni_write_reg(word_len, mas->base, SE_SPI_WORD_LEN);
}
-static int spi_geni_prepare_message(struct spi_master *spi_mas,
- struct spi_message *spi_msg)
+static int setup_fifo_params(struct spi_device *spi_slv,
+ struct spi_master *spi)
{
- struct spi_device *spi_slv = spi_msg->spi;
- struct spi_geni_master *mas = spi_master_get_devdata(spi_mas);
+ struct spi_geni_master *mas = spi_master_get_devdata(spi);
u16 mode = spi_slv->mode;
u32 loopback_cfg = geni_read_reg(mas->base, SE_SPI_LOOPBACK);
u32 cpol = geni_read_reg(mas->base, SE_SPI_CPOL);
u32 cpha = geni_read_reg(mas->base, SE_SPI_CPHA);
u32 demux_sel = 0;
u32 demux_output_inv = 0;
+ u32 clk_sel = geni_read_reg(mas->base, SE_GENI_CLK_SEL);
+ u32 m_clk_cfg = geni_read_reg(mas->base, GENI_SER_M_CLK_CFG);
int ret = 0;
+ int idx;
+ int div;
loopback_cfg &= ~LOOPBACK_MSK;
cpol &= ~CPOL;
@@ -194,21 +240,434 @@
mas->cur_speed_hz = spi_slv->max_speed_hz;
mas->cur_word_len = spi_slv->bits_per_word;
- ret = do_spi_clk_cfg(mas->cur_speed_hz, mas);
+ ret = get_spi_clk_cfg(mas->cur_speed_hz, mas, &idx, &div);
if (ret) {
- dev_err(&spi_mas->dev, "Err setting clks ret(%d) for %d\n",
+ dev_err(mas->dev, "Err setting clks ret(%d) for %d\n",
ret, mas->cur_speed_hz);
- goto prepare_message_exit;
+ goto setup_fifo_params_exit;
}
+
+ clk_sel |= (idx & CLK_SEL_MSK);
+ m_clk_cfg |= ((div << CLK_DIV_SHFT) | SER_CLK_EN);
spi_setup_word_len(mas, spi_slv->mode, spi_slv->bits_per_word);
geni_write_reg(loopback_cfg, mas->base, SE_SPI_LOOPBACK);
geni_write_reg(demux_sel, mas->base, SE_SPI_DEMUX_SEL);
geni_write_reg(cpha, mas->base, SE_SPI_CPHA);
geni_write_reg(cpol, mas->base, SE_SPI_CPOL);
geni_write_reg(demux_output_inv, mas->base, SE_SPI_DEMUX_OUTPUT_INV);
+ geni_write_reg(clk_sel, mas->base, SE_GENI_CLK_SEL);
+ geni_write_reg(m_clk_cfg, mas->base, GENI_SER_M_CLK_CFG);
/* Ensure message level attributes are written before returning */
mb();
-prepare_message_exit:
+setup_fifo_params_exit:
+ return ret;
+}
+
+
+static int select_xfer_mode(struct spi_master *spi,
+ struct spi_message *spi_msg)
+{
+ struct spi_geni_master *mas = spi_master_get_devdata(spi);
+ int mode = FIFO_MODE;
+ int fifo_disable = (geni_read_reg(mas->base, GENI_IF_FIFO_DISABLE_RO) &
+ FIFO_IF_DISABLE);
+ bool dma_chan_valid =
+ !(IS_ERR_OR_NULL(mas->tx) || IS_ERR_OR_NULL(mas->rx));
+
+ /*
+ * If FIFO Interface is disabled and there are no DMA channels then we
+ * can't do this transfer.
+ * If FIFO interface is disabled, we can do GSI only,
+ * else pick FIFO mode.
+ */
+ if (fifo_disable && !dma_chan_valid)
+ mode = -EINVAL;
+ else if (fifo_disable)
+ mode = GSI_DMA;
+ else
+ mode = FIFO_MODE;
+ return mode;
+}
+
+static struct msm_gpi_tre *setup_config0_tre(struct spi_transfer *xfer,
+ struct spi_geni_master *mas, u16 mode)
+{
+ struct msm_gpi_tre *c0_tre = &mas->gsi[mas->num_xfers].config0_tre;
+ u8 flags = 0;
+ u8 word_len = 0;
+ u8 pack = 0;
+ int div = 0;
+ int idx = 0;
+ int ret = 0;
+
+ if (IS_ERR_OR_NULL(c0_tre))
+ return c0_tre;
+
+ if (mode & SPI_LOOP)
+ flags |= GSI_LOOPBACK_EN;
+
+ if (mode & SPI_CPOL)
+ flags |= GSI_CPOL;
+
+ if (mode & SPI_CPHA)
+ flags |= GSI_CPHA;
+
+ if (xfer->cs_change)
+ flags |= GSI_CS_TOGGLE;
+
+ word_len = xfer->bits_per_word - MIN_WORD_LEN;
+ if (mas->tx_fifo_width % xfer->bits_per_word)
+ pack = 0;
+ else
+ pack |= (GSI_TX_PACK_EN | GSI_RX_PACK_EN);
+ ret = get_spi_clk_cfg(mas->cur_speed_hz, mas, &idx, &div);
+ if (ret) {
+ dev_err(mas->dev, "%s:Err setting clks:%d\n", __func__, ret);
+ return ERR_PTR(ret);
+ }
+ c0_tre->dword[0] = MSM_GPI_SPI_CONFIG0_TRE_DWORD0(pack, flags,
+ word_len);
+ c0_tre->dword[1] = MSM_GPI_SPI_CONFIG0_TRE_DWORD1(0, 0, 0);
+ c0_tre->dword[2] = MSM_GPI_SPI_CONFIG0_TRE_DWORD2(idx, div);
+ c0_tre->dword[3] = MSM_GPI_SPI_CONFIG0_TRE_DWORD3(0, 0, 0, 1);
+ GENI_SE_DBG(mas->ipc, false, mas->dev,
+ "%s: flags 0x%x word %d pack %d idx %d div %d\n",
+ __func__, flags, word_len, pack, idx, div);
+ return c0_tre;
+}
+
+static struct msm_gpi_tre *setup_go_tre(int cmd, int cs, int rx_len, int flags,
+ struct spi_geni_master *mas)
+{
+ struct msm_gpi_tre *go_tre = &mas->gsi[mas->num_xfers].go_tre;
+ int chain;
+ int eot;
+ int eob;
+
+ if (IS_ERR_OR_NULL(go_tre))
+ return go_tre;
+
+ go_tre->dword[0] = MSM_GPI_SPI_GO_TRE_DWORD0(flags, cs, cmd);
+ go_tre->dword[1] = MSM_GPI_SPI_GO_TRE_DWORD1;
+ go_tre->dword[2] = MSM_GPI_SPI_GO_TRE_DWORD2(rx_len);
+ if (cmd == SPI_RX_ONLY) {
+ eot = 0;
+ chain = 0;
+ eob = 1;
+ } else {
+ eot = 0;
+ chain = 1;
+ eob = 0;
+ }
+ go_tre->dword[3] = MSM_GPI_SPI_GO_TRE_DWORD3(0, eot, eob, chain);
+ GENI_SE_DBG(mas->ipc, false, mas->dev,
+ "%s: rx len %d flags 0x%x cs %d cmd %d eot %d eob %d chain %d\n",
+ __func__, rx_len, flags, cs, cmd, eot, eob, chain);
+ return go_tre;
+}
+
+static struct msm_gpi_tre *setup_dma_tre(struct msm_gpi_tre *tre,
+ dma_addr_t buf, u32 len,
+ struct spi_geni_master *mas,
+ bool is_tx)
+{
+ if (IS_ERR_OR_NULL(tre))
+ return tre;
+
+ tre->dword[0] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD0(buf);
+ tre->dword[1] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD1(buf);
+ tre->dword[2] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD2(len);
+ tre->dword[3] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD3(0, is_tx, 0, 0);
+ return tre;
+}
+
+static void spi_gsi_ch_cb(struct dma_chan *ch, struct msm_gpi_cb const *cb,
+ void *ptr)
+{
+ struct spi_master *spi = ptr;
+ struct spi_geni_master *mas = spi_master_get_devdata(spi);
+
+ switch (cb->cb_event) {
+ case MSM_GPI_QUP_NOTIFY:
+ case MSM_GPI_QUP_MAX_EVENT:
+ GENI_SE_DBG(mas->ipc, false, mas->dev,
+ "%s:cb_ev%d status%llu ts%llu count%llu\n",
+ __func__, cb->cb_event, cb->status,
+ cb->timestamp, cb->count);
+ break;
+ case MSM_GPI_QUP_ERROR:
+ case MSM_GPI_QUP_CH_ERROR:
+ case MSM_GPI_QUP_FW_ERROR:
+ case MSM_GPI_QUP_PENDING_EVENT:
+ case MSM_GPI_QUP_EOT_DESC_MISMATCH:
+ case MSM_GPI_QUP_SW_ERROR:
+ GENI_SE_ERR(mas->ipc, true, mas->dev,
+ "%s: cb_ev %d status %llu ts %llu count %llu\n",
+ __func__, cb->cb_event, cb->status,
+ cb->timestamp, cb->count);
+ GENI_SE_ERR(mas->ipc, true, mas->dev,
+ "err.routine %u, err.type %u, err.code %u\n",
+ cb->error_log.routine,
+ cb->error_log.type,
+ cb->error_log.error_code);
+ mas->qn_err = true;
+ complete_all(&mas->tx_cb);
+ complete_all(&mas->rx_cb);
+
+ break;
+ };
+}
+
+static void spi_gsi_rx_callback(void *cb)
+{
+ struct msm_gpi_dma_async_tx_cb_param *cb_param =
+ (struct msm_gpi_dma_async_tx_cb_param *)cb;
+ struct gsi_desc_cb *desc_cb = (struct gsi_desc_cb *)cb_param->userdata;
+ struct spi_master *spi = desc_cb->spi;
+ struct spi_transfer *xfer = desc_cb->xfer;
+ struct spi_geni_master *mas = spi_master_get_devdata(spi);
+
+ if (xfer->rx_buf) {
+ if (cb_param->status == MSM_GPI_TCE_UNEXP_ERR) {
+ GENI_SE_ERR(mas->ipc, true, mas->dev,
+ "%s: Unexpected GSI CB error\n", __func__);
+ return;
+ }
+ if (cb_param->length == xfer->len) {
+ GENI_SE_DBG(mas->ipc, false, mas->dev,
+ "%s\n", __func__);
+ complete(&mas->rx_cb);
+ } else {
+ GENI_SE_ERR(mas->ipc, true, mas->dev,
+ "%s: Length mismatch. Expected %d Callback %d\n",
+ __func__, xfer->len, cb_param->length);
+ }
+ }
+}
+
+static void spi_gsi_tx_callback(void *cb)
+{
+ struct msm_gpi_dma_async_tx_cb_param *cb_param = cb;
+ struct gsi_desc_cb *desc_cb = (struct gsi_desc_cb *)cb_param->userdata;
+ struct spi_master *spi = desc_cb->spi;
+ struct spi_transfer *xfer = desc_cb->xfer;
+ struct spi_geni_master *mas = spi_master_get_devdata(spi);
+
+ if (xfer->tx_buf) {
+ if (cb_param->status == MSM_GPI_TCE_UNEXP_ERR) {
+ GENI_SE_ERR(mas->ipc, true, mas->dev,
+ "%s: Unexpected GSI CB error\n", __func__);
+ return;
+ }
+ if (cb_param->length == xfer->len) {
+ GENI_SE_DBG(mas->ipc, false, mas->dev,
+ "%s\n", __func__);
+ complete(&mas->tx_cb);
+ } else {
+ GENI_SE_ERR(mas->ipc, true, mas->dev,
+ "%s: Length mismatch. Expected %d Callback %d\n",
+ __func__, xfer->len, cb_param->length);
+ }
+ }
+}
+
+static int setup_gsi_xfer(struct spi_transfer *xfer,
+ struct spi_geni_master *mas,
+ struct spi_device *spi_slv,
+ struct spi_master *spi)
+{
+ int ret = 0;
+ struct msm_gpi_tre *c0_tre = NULL;
+ struct msm_gpi_tre *go_tre = NULL;
+ struct msm_gpi_tre *tx_tre = NULL;
+ struct msm_gpi_tre *rx_tre = NULL;
+ struct scatterlist *xfer_tx_sg = mas->gsi[mas->num_xfers].tx_sg;
+ struct scatterlist *xfer_rx_sg = &mas->gsi[mas->num_xfers].rx_sg;
+ int rx_nent = 0;
+ int tx_nent = 0;
+ u8 cmd = 0;
+ u8 cs = 0;
+ u32 rx_len = 0;
+ int go_flags = 0;
+ unsigned long flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK;
+
+ if ((xfer->bits_per_word != mas->cur_word_len) ||
+ (xfer->speed_hz != mas->cur_speed_hz)) {
+ mas->cur_word_len = xfer->bits_per_word;
+ mas->cur_speed_hz = xfer->speed_hz;
+ tx_nent++;
+ c0_tre = setup_config0_tre(xfer, mas, spi_slv->mode);
+ if (IS_ERR_OR_NULL(c0_tre)) {
+ dev_err(mas->dev, "%s:Err setting c0tre:%d\n",
+ __func__, ret);
+ return PTR_ERR(c0_tre);
+ }
+ }
+
+ if (xfer->tx_buf && xfer->rx_buf) {
+ cmd = SPI_FULL_DUPLEX;
+ tx_nent += 2;
+ rx_nent++;
+ rx_len = ((xfer->len << 3) / mas->cur_word_len);
+ } else if (xfer->tx_buf) {
+ cmd = SPI_TX_ONLY;
+ tx_nent += 2;
+ } else if (xfer->rx_buf) {
+ cmd = SPI_RX_ONLY;
+ tx_nent++;
+ rx_nent++;
+ rx_len = ((xfer->len << 3) / mas->cur_word_len);
+ }
+
+ cs |= spi_slv->chip_select;
+ if (!list_is_last(&xfer->transfer_list, &spi->cur_msg->transfers))
+ go_flags |= FRAGMENTATION;
+ go_tre = setup_go_tre(cmd, cs, rx_len, go_flags, mas);
+
+ sg_init_table(xfer_tx_sg, tx_nent);
+ if (rx_nent)
+ sg_init_table(xfer_rx_sg, rx_nent);
+
+ if (c0_tre)
+ sg_set_buf(xfer_tx_sg++, c0_tre, sizeof(*c0_tre));
+
+ sg_set_buf(xfer_tx_sg++, go_tre, sizeof(*go_tre));
+ mas->gsi[mas->num_xfers].desc_cb.spi = spi;
+ mas->gsi[mas->num_xfers].desc_cb.xfer = xfer;
+ if (cmd & SPI_RX_ONLY) {
+ rx_tre = &mas->gsi[mas->num_xfers].rx_dma_tre;
+ rx_tre = setup_dma_tre(rx_tre, xfer->rx_dma, xfer->len, mas, 0);
+ if (IS_ERR_OR_NULL(rx_tre)) {
+ dev_err(mas->dev, "Err setting up rx tre\n");
+ return PTR_ERR(rx_tre);
+ }
+ sg_set_buf(xfer_rx_sg, rx_tre, sizeof(*rx_tre));
+ mas->gsi[mas->num_xfers].rx_desc =
+ dmaengine_prep_slave_sg(mas->rx,
+ &mas->gsi[mas->num_xfers].rx_sg, rx_nent,
+ DMA_DEV_TO_MEM, flags);
+ if (IS_ERR_OR_NULL(mas->gsi[mas->num_xfers].rx_desc)) {
+ dev_err(mas->dev, "Err setting up rx desc\n");
+ return -EIO;
+ }
+ mas->gsi[mas->num_xfers].rx_desc->callback =
+ spi_gsi_rx_callback;
+ mas->gsi[mas->num_xfers].rx_desc->callback_param =
+ &mas->gsi[mas->num_xfers].rx_cb_param;
+ mas->gsi[mas->num_xfers].rx_cb_param.userdata =
+ &mas->gsi[mas->num_xfers].desc_cb;
+ mas->num_rx_eot++;
+ }
+
+ if (cmd & SPI_TX_ONLY) {
+ tx_tre = &mas->gsi[mas->num_xfers].tx_dma_tre;
+ tx_tre = setup_dma_tre(tx_tre, xfer->tx_dma, xfer->len, mas, 1);
+ if (IS_ERR_OR_NULL(tx_tre)) {
+ dev_err(mas->dev, "Err setting up tx tre\n");
+ return PTR_ERR(tx_tre);
+ }
+ sg_set_buf(xfer_tx_sg++, tx_tre, sizeof(*tx_tre));
+ mas->num_tx_eot++;
+ }
+ mas->gsi[mas->num_xfers].tx_desc = dmaengine_prep_slave_sg(mas->tx,
+ mas->gsi[mas->num_xfers].tx_sg, tx_nent,
+ DMA_MEM_TO_DEV, flags);
+ if (IS_ERR_OR_NULL(mas->gsi[mas->num_xfers].tx_desc)) {
+ dev_err(mas->dev, "Err setting up tx desc\n");
+ return -EIO;
+ }
+ mas->gsi[mas->num_xfers].tx_desc->callback = spi_gsi_tx_callback;
+ mas->gsi[mas->num_xfers].tx_desc->callback_param =
+ &mas->gsi[mas->num_xfers].tx_cb_param;
+ mas->gsi[mas->num_xfers].tx_cb_param.userdata =
+ &mas->gsi[mas->num_xfers].desc_cb;
+ mas->gsi[mas->num_xfers].tx_cookie =
+ dmaengine_submit(mas->gsi[mas->num_xfers].tx_desc);
+ if (mas->num_rx_eot)
+ mas->gsi[mas->num_xfers].rx_cookie =
+ dmaengine_submit(mas->gsi[mas->num_xfers].rx_desc);
+ dma_async_issue_pending(mas->tx);
+ if (mas->num_rx_eot)
+ dma_async_issue_pending(mas->rx);
+ mas->num_xfers++;
+ return ret;
+}
+
+static int spi_geni_map_buf(struct spi_geni_master *mas,
+ struct spi_message *msg)
+{
+ struct spi_transfer *xfer;
+ struct device *gsi_dev = mas->dev;
+
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+ if (xfer->rx_buf) {
+ xfer->rx_dma = dma_map_single(gsi_dev, xfer->rx_buf,
+ xfer->len, DMA_FROM_DEVICE);
+ if (dma_mapping_error(mas->dev, xfer->rx_dma)) {
+ dev_err(mas->dev, "Err mapping buf\n");
+ return -ENOMEM;
+ }
+ }
+
+ if (xfer->tx_buf) {
+ xfer->tx_dma = dma_map_single(gsi_dev,
+ (void *)xfer->tx_buf, xfer->len, DMA_TO_DEVICE);
+ if (dma_mapping_error(gsi_dev, xfer->tx_dma)) {
+ dev_err(mas->dev, "Err mapping buf\n");
+ dma_unmap_single(gsi_dev, xfer->rx_dma,
+ xfer->len, DMA_FROM_DEVICE);
+ return -ENOMEM;
+ }
+ }
+ };
+
+ return 0;
+}
+
+static void spi_geni_unmap_buf(struct spi_geni_master *mas,
+ struct spi_message *msg)
+{
+ struct spi_transfer *xfer;
+ struct device *gsi_dev = mas->dev;
+
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+ if (xfer->rx_buf)
+ dma_unmap_single(gsi_dev, xfer->rx_dma,
+ xfer->len, DMA_FROM_DEVICE);
+ if (xfer->tx_buf)
+ dma_unmap_single(gsi_dev, xfer->tx_dma,
+ xfer->len, DMA_TO_DEVICE);
+ };
+}
+
+static int spi_geni_prepare_message(struct spi_master *spi,
+ struct spi_message *spi_msg)
+{
+ int ret = 0;
+ struct spi_geni_master *mas = spi_master_get_devdata(spi);
+
+ mas->cur_xfer_mode = select_xfer_mode(spi, spi_msg);
+
+ if (mas->cur_xfer_mode == FIFO_MODE) {
+ geni_se_select_mode(mas->base, FIFO_MODE);
+ reinit_completion(&mas->xfer_done);
+ setup_fifo_params(spi_msg->spi, spi);
+ } else if (mas->cur_xfer_mode == GSI_DMA) {
+ mas->num_tx_eot = 0;
+ mas->num_rx_eot = 0;
+ mas->num_xfers = 0;
+ reinit_completion(&mas->tx_cb);
+ reinit_completion(&mas->rx_cb);
+ memset(mas->gsi, 0,
+ (sizeof(struct spi_geni_gsi) * NUM_SPI_XFER));
+ geni_se_select_mode(mas->base, GSI_DMA);
+ dmaengine_resume(mas->tx);
+ ret = spi_geni_map_buf(mas, spi_msg);
+ } else {
+ dev_err(mas->dev, "%s: Couldn't select mode %d", __func__,
+ mas->cur_xfer_mode);
+ ret = -EINVAL;
+ }
return ret;
}
@@ -219,6 +678,10 @@
mas->cur_speed_hz = 0;
mas->cur_word_len = 0;
+ if (mas->cur_xfer_mode == GSI_DMA) {
+ dmaengine_pause(mas->tx);
+ spi_geni_unmap_buf(mas, spi_msg);
+ }
return 0;
}
@@ -238,22 +701,89 @@
if (unlikely(!mas->setup)) {
int proto = get_se_proto(mas->base);
+ unsigned int major;
+ unsigned int minor;
+ unsigned int step;
+ int hw_ver;
if (unlikely(proto != SPI)) {
dev_err(mas->dev, "Invalid proto %d\n", proto);
return -ENXIO;
}
geni_se_init(mas->base, 0x0, (mas->tx_fifo_depth - 2));
- geni_se_select_mode(mas->base, FIFO_MODE);
mas->tx_fifo_depth = get_tx_fifo_depth(mas->base);
mas->rx_fifo_depth = get_rx_fifo_depth(mas->base);
mas->tx_fifo_width = get_tx_fifo_width(mas->base);
+ mas->oversampling = 1;
/* Transmit an entire FIFO worth of data per IRQ */
mas->tx_wm = 1;
- dev_dbg(mas->dev, "tx_fifo %d rx_fifo %d tx_width %d\n",
+
+ mas->tx = dma_request_slave_channel(mas->dev, "tx");
+ if (IS_ERR_OR_NULL(mas->tx)) {
+ dev_info(mas->dev, "Failed to get tx DMA ch %ld",
+ PTR_ERR(mas->tx));
+ } else {
+ mas->rx = dma_request_slave_channel(mas->dev, "rx");
+ if (IS_ERR_OR_NULL(mas->rx)) {
+ dev_info(mas->dev, "Failed to get rx DMA ch %ld",
+ PTR_ERR(mas->rx));
+ dma_release_channel(mas->tx);
+ }
+ mas->gsi = devm_kzalloc(mas->dev,
+ (sizeof(struct spi_geni_gsi) * NUM_SPI_XFER),
+ GFP_KERNEL);
+ if (IS_ERR_OR_NULL(mas->gsi)) {
+ dev_err(mas->dev, "Failed to get GSI mem\n");
+ dma_release_channel(mas->tx);
+ dma_release_channel(mas->rx);
+ mas->tx = NULL;
+ mas->rx = NULL;
+ goto setup_ipc;
+ }
+ mas->tx_event.init.callback = spi_gsi_ch_cb;
+ mas->tx_event.init.cb_param = spi;
+ mas->tx_event.cmd = MSM_GPI_INIT;
+ mas->tx->private = &mas->tx_event;
+ mas->rx_event.init.callback = spi_gsi_ch_cb;
+ mas->rx_event.init.cb_param = spi;
+ mas->rx_event.cmd = MSM_GPI_INIT;
+ mas->rx->private = &mas->rx_event;
+ if (dmaengine_slave_config(mas->tx, NULL)) {
+ dev_err(mas->dev, "Failed to Config Tx\n");
+ dma_release_channel(mas->tx);
+ dma_release_channel(mas->rx);
+ mas->tx = NULL;
+ mas->rx = NULL;
+ goto setup_ipc;
+ }
+ if (dmaengine_slave_config(mas->rx, NULL)) {
+ dev_err(mas->dev, "Failed to Config Rx\n");
+ dma_release_channel(mas->tx);
+ dma_release_channel(mas->rx);
+ mas->tx = NULL;
+ mas->rx = NULL;
+ goto setup_ipc;
+ }
+
+ }
+setup_ipc:
+ mas->ipc = ipc_log_context_create(4, dev_name(mas->dev), 0);
+ dev_info(mas->dev, "tx_fifo %d rx_fifo %d tx_width %d\n",
mas->tx_fifo_depth, mas->rx_fifo_depth,
mas->tx_fifo_width);
mas->setup = true;
+ hw_ver = geni_se_qupv3_hw_version(mas->wrapper_dev, &major,
+ &minor, &step);
+ if (hw_ver)
+ dev_err(mas->dev, "%s:Err getting HW version %d\n",
+ __func__, hw_ver);
+ else {
+ if ((major == 1) && (minor == 0))
+ mas->oversampling = 2;
+ GENI_SE_DBG(mas->ipc, false, mas->dev,
+ "%s:Major:%d Minor:%d step:%dos%d\n",
+ __func__, major, minor, step, mas->oversampling);
+ }
}
exit_prepare_transfer_hardware:
return ret;
@@ -281,6 +811,29 @@
mas->cur_word_len = xfer->bits_per_word;
}
+ /* Speed and bits per word can be overridden per transfer */
+ if (xfer->speed_hz != mas->cur_speed_hz) {
+ int ret = 0;
+ u32 clk_sel = geni_read_reg(mas->base, SE_GENI_CLK_SEL);
+ u32 m_clk_cfg = geni_read_reg(mas->base, GENI_SER_M_CLK_CFG);
+ int idx = 0;
+ int div = 0;
+
+ ret = get_spi_clk_cfg(xfer->speed_hz, mas, &idx, &div);
+ if (ret) {
+ dev_err(mas->dev, "%s:Err setting clks:%d\n",
+ __func__, ret);
+ return;
+ }
+ mas->cur_speed_hz = xfer->speed_hz;
+ clk_sel |= (idx & CLK_SEL_MSK);
+ m_clk_cfg |= ((div << CLK_DIV_SHFT) | SER_CLK_EN);
+ geni_write_reg(clk_sel, mas->base, SE_GENI_CLK_SEL);
+ geni_write_reg(m_clk_cfg, mas->base, GENI_SER_M_CLK_CFG);
+ }
+
+ mas->tx_rem_bytes = 0;
+ mas->rx_rem_bytes = 0;
if (xfer->tx_buf && xfer->rx_buf)
m_cmd = SPI_FULL_DUPLEX;
else if (xfer->tx_buf)
@@ -291,7 +844,7 @@
spi_tx_cfg &= ~CS_TOGGLE;
if (xfer->cs_change)
spi_tx_cfg |= CS_TOGGLE;
- trans_len = ((xfer->len / (mas->cur_word_len >> 3)) & TRANS_LEN_MSK);
+ trans_len = ((xfer->len << 3) / mas->cur_word_len) & TRANS_LEN_MSK;
if (!list_is_last(&xfer->transfer_list, &spi->cur_msg->transfers))
m_param |= FRAGMENTATION;
@@ -307,7 +860,8 @@
}
geni_write_reg(spi_tx_cfg, mas->base, SE_SPI_TRANS_CFG);
geni_setup_m_cmd(mas->base, m_cmd, m_param);
- geni_write_reg(mas->tx_wm, mas->base, SE_GENI_TX_WATERMARK_REG);
+ if (m_cmd & SPI_TX_ONLY)
+ geni_write_reg(mas->tx_wm, mas->base, SE_GENI_TX_WATERMARK_REG);
/* Ensure all writes are done before the WM interrupt */
mb();
}
@@ -315,17 +869,7 @@
static void handle_fifo_timeout(struct spi_geni_master *mas)
{
unsigned long timeout;
- u32 tx_trans_len = geni_read_reg(mas->base, SE_SPI_TX_TRANS_LEN);
- u32 rx_trans_len = geni_read_reg(mas->base, SE_SPI_RX_TRANS_LEN);
- u32 spi_tx_cfg = geni_read_reg(mas->base, SE_SPI_TRANS_CFG);
- u32 m_cmd = geni_read_reg(mas->base, SE_GENI_M_CMD0);
- /* Timed-out on a FIFO xfer, print relevant reg info. */
- dev_err(mas->dev, "tx_rem_bytes %d rx_rem_bytes %d\n",
- mas->tx_rem_bytes, mas->rx_rem_bytes);
- dev_err(mas->dev, "tx_trans_len %d rx_trans_len %d\n", tx_trans_len,
- rx_trans_len);
- dev_err(mas->dev, "spi_tx_cfg 0x%x m_cmd 0x%x\n", spi_tx_cfg, m_cmd);
reinit_completion(&mas->xfer_done);
geni_cancel_m_cmd(mas->base);
/* Ensure cmd cancel is written */
@@ -357,30 +901,64 @@
return -EINVAL;
}
- reinit_completion(&mas->xfer_done);
- /* Speed and bits per word can be overridden per transfer */
- if (xfer->speed_hz != mas->cur_speed_hz) {
- mas->cur_speed_hz = xfer->speed_hz;
- ret = do_spi_clk_cfg(mas->cur_speed_hz, mas);
- if (ret) {
- dev_err(mas->dev, "%s:Err setting clks:%d\n",
- __func__, ret);
- goto geni_transfer_one_exit;
- }
- }
-
- setup_fifo_xfer(xfer, mas, slv->mode, spi);
- timeout = wait_for_completion_timeout(&mas->xfer_done,
+ if (mas->cur_xfer_mode == FIFO_MODE) {
+ setup_fifo_xfer(xfer, mas, slv->mode, spi);
+ timeout = wait_for_completion_timeout(&mas->xfer_done,
msecs_to_jiffies(SPI_XFER_TIMEOUT_MS));
- if (!timeout) {
- dev_err(mas->dev, "Xfer[len %d tx %p rx %p n %d] timed out.\n",
+ if (!timeout) {
+ GENI_SE_ERR(mas->ipc, true, mas->dev,
+ "Xfer[len %d tx %pK rx %pK n %d] timed out.\n",
xfer->len, xfer->tx_buf,
xfer->rx_buf,
xfer->bits_per_word);
- ret = -ETIMEDOUT;
- handle_fifo_timeout(mas);
+ mas->cur_xfer = NULL;
+ ret = -ETIMEDOUT;
+ goto err_fifo_geni_transfer_one;
+ }
+ } else {
+ setup_gsi_xfer(xfer, mas, slv, spi);
+ if ((mas->num_xfers >= NUM_SPI_XFER) ||
+ (list_is_last(&xfer->transfer_list,
+ &spi->cur_msg->transfers))) {
+ int i;
+
+ for (i = 0 ; i < mas->num_tx_eot; i++) {
+ timeout =
+ wait_for_completion_interruptible_timeout(
+ &mas->tx_cb,
+ msecs_to_jiffies(SPI_XFER_TIMEOUT_MS));
+ if (timeout <= 0) {
+ GENI_SE_ERR(mas->ipc, true, mas->dev,
+ "Tx[%d] timeout%lu\n", i, timeout);
+ ret = -ETIMEDOUT;
+ goto err_gsi_geni_transfer_one;
+ }
+ }
+ for (i = 0 ; i < mas->num_rx_eot; i++) {
+ timeout =
+ wait_for_completion_interruptible_timeout(
+ &mas->rx_cb,
+ msecs_to_jiffies(SPI_XFER_TIMEOUT_MS));
+ if (timeout <= 0) {
+ GENI_SE_ERR(mas->ipc, true, mas->dev,
+ "Rx[%d] timeout%lu\n", i, timeout);
+ ret = -ETIMEDOUT;
+ goto err_gsi_geni_transfer_one;
+ }
+ }
+ if (mas->qn_err) {
+ ret = -EIO;
+ mas->qn_err = false;
+ goto err_gsi_geni_transfer_one;
+ }
+ }
}
-geni_transfer_one_exit:
+ return ret;
+err_gsi_geni_transfer_one:
+ dmaengine_terminate_all(mas->tx);
+ return ret;
+err_fifo_geni_transfer_one:
+ handle_fifo_timeout(mas);
return ret;
}
@@ -389,8 +967,12 @@
int i = 0;
int tx_fifo_width = (mas->tx_fifo_width >> 3);
int max_bytes = (mas->tx_fifo_depth - mas->tx_wm) * tx_fifo_width;
- const u8 *tx_buf = mas->cur_xfer->tx_buf;
+ const u8 *tx_buf = NULL;
+ if (!mas->cur_xfer)
+ return;
+
+ tx_buf = mas->cur_xfer->tx_buf;
tx_buf += (mas->cur_xfer->len - mas->tx_rem_bytes);
max_bytes = min_t(int, mas->tx_rem_bytes, max_bytes);
while (i < max_bytes) {
@@ -421,8 +1003,12 @@
u32 rx_fifo_status = geni_read_reg(mas->base, SE_GENI_RX_FIFO_STATUS);
int rx_bytes = 0;
int rx_wc = 0;
- u8 *rx_buf = mas->cur_xfer->rx_buf;
+ u8 *rx_buf = NULL;
+ if (!mas->cur_xfer)
+ return;
+
+ rx_buf = mas->cur_xfer->rx_buf;
rx_wc = (rx_fifo_status & RX_FIFO_WC_MSK);
if (rx_fifo_status & RX_LAST) {
int rx_last_byte_valid =
@@ -608,6 +1194,8 @@
spi->auto_runtime_pm = false;
init_completion(&geni_mas->xfer_done);
+ init_completion(&geni_mas->tx_cb);
+ init_completion(&geni_mas->rx_cb);
pm_runtime_enable(&pdev->dev);
ret = spi_register_master(spi);
if (ret) {
diff --git a/drivers/spmi/spmi.c b/drivers/spmi/spmi.c
index a8107cc..df8900a 100644
--- a/drivers/spmi/spmi.c
+++ b/drivers/spmi/spmi.c
@@ -365,11 +365,23 @@
return 0;
}
+static int spmi_drv_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ int ret;
+
+ ret = of_device_uevent_modalias(dev, env);
+ if (ret != -ENODEV)
+ return ret;
+
+ return 0;
+}
+
static struct bus_type spmi_bus_type = {
.name = "spmi",
.match = spmi_device_match,
.probe = spmi_drv_probe,
.remove = spmi_drv_remove,
+ .uevent = spmi_drv_uevent,
};
/**
diff --git a/drivers/staging/android/fiq_debugger/fiq_debugger.c b/drivers/staging/android/fiq_debugger/fiq_debugger.c
index 675b974..ce9dc7e 100644
--- a/drivers/staging/android/fiq_debugger/fiq_debugger.c
+++ b/drivers/staging/android/fiq_debugger/fiq_debugger.c
@@ -30,6 +30,7 @@
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/smp.h>
+#include <linux/sysrq.h>
#include <linux/timer.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
@@ -400,7 +401,7 @@
cmd += 6;
while (*cmd == ' ')
cmd++;
- if (cmd != '\0')
+ if ((cmd != '\0') && sysrq_on())
kernel_restart(cmd);
else
kernel_restart(NULL);
@@ -430,29 +431,39 @@
static void fiq_debugger_help(struct fiq_debugger_state *state)
{
fiq_debugger_printf(&state->output,
- "FIQ Debugger commands:\n"
- " pc PC status\n"
- " regs Register dump\n"
- " allregs Extended Register dump\n"
- " bt Stack trace\n"
- " reboot [<c>] Reboot with command <c>\n"
- " reset [<c>] Hard reset with command <c>\n"
- " irqs Interupt status\n"
- " kmsg Kernel log\n"
- " version Kernel version\n");
+ "FIQ Debugger commands:\n");
+ if (sysrq_on()) {
+ fiq_debugger_printf(&state->output,
+ " pc PC status\n"
+ " regs Register dump\n"
+ " allregs Extended Register dump\n"
+ " bt Stack trace\n");
+ fiq_debugger_printf(&state->output,
+ " reboot [<c>] Reboot with command <c>\n"
+ " reset [<c>] Hard reset with command <c>\n"
+ " irqs Interrupt status\n"
+ " kmsg Kernel log\n"
+ " version Kernel version\n");
+ fiq_debugger_printf(&state->output,
+ " cpu Current CPU\n"
+ " cpu <number> Switch to CPU<number>\n"
+ " sysrq sysrq options\n"
+ " sysrq <param> Execute sysrq with <param>\n");
+ } else {
+ fiq_debugger_printf(&state->output,
+ " reboot Reboot\n"
+ " reset Hard reset\n"
+ " irqs Interrupt status\n");
+ }
fiq_debugger_printf(&state->output,
- " sleep Allow sleep while in FIQ\n"
- " nosleep Disable sleep while in FIQ\n"
- " console Switch terminal to console\n"
- " cpu Current CPU\n"
- " cpu <number> Switch to CPU<number>\n");
- fiq_debugger_printf(&state->output,
- " ps Process list\n"
- " sysrq sysrq options\n"
- " sysrq <param> Execute sysrq with <param>\n");
+ " sleep Allow sleep while in FIQ\n"
+ " nosleep Disable sleep while in FIQ\n"
+ " console Switch terminal to console\n"
+ " ps Process list\n");
#ifdef CONFIG_KGDB
- fiq_debugger_printf(&state->output,
- " kgdb Enter kernel debugger\n");
+ if (fiq_kgdb_enable) {
+ fiq_debugger_printf(&state->output,
+ " kgdb Enter kernel debugger\n");
#endif
}
@@ -484,18 +495,23 @@
if (!strcmp(cmd, "help") || !strcmp(cmd, "?")) {
fiq_debugger_help(state);
} else if (!strcmp(cmd, "pc")) {
- fiq_debugger_dump_pc(&state->output, regs);
+ if (sysrq_on())
+ fiq_debugger_dump_pc(&state->output, regs);
} else if (!strcmp(cmd, "regs")) {
- fiq_debugger_dump_regs(&state->output, regs);
+ if (sysrq_on())
+ fiq_debugger_dump_regs(&state->output, regs);
} else if (!strcmp(cmd, "allregs")) {
- fiq_debugger_dump_allregs(&state->output, regs);
+ if (sysrq_on())
+ fiq_debugger_dump_allregs(&state->output, regs);
} else if (!strcmp(cmd, "bt")) {
- fiq_debugger_dump_stacktrace(&state->output, regs, 100, svc_sp);
+ if (sysrq_on())
+ fiq_debugger_dump_stacktrace(&state->output, regs,
+ 100, svc_sp);
} else if (!strncmp(cmd, "reset", 5)) {
cmd += 5;
while (*cmd == ' ')
cmd++;
- if (*cmd) {
+ if (*cmd && sysrq_on()) {
char tmp_cmd[32];
strlcpy(tmp_cmd, cmd, sizeof(tmp_cmd));
machine_restart(tmp_cmd);
@@ -505,9 +521,12 @@
} else if (!strcmp(cmd, "irqs")) {
fiq_debugger_dump_irqs(state);
} else if (!strcmp(cmd, "kmsg")) {
- fiq_debugger_dump_kernel_log(state);
+ if (sysrq_on())
+ fiq_debugger_dump_kernel_log(state);
} else if (!strcmp(cmd, "version")) {
- fiq_debugger_printf(&state->output, "%s\n", linux_banner);
+ if (sysrq_on())
+ fiq_debugger_printf(&state->output, "%s\n",
+ linux_banner);
} else if (!strcmp(cmd, "sleep")) {
state->no_sleep = false;
fiq_debugger_printf(&state->output, "enabling sleep\n");
@@ -519,14 +538,17 @@
fiq_debugger_uart_flush(state);
state->console_enable = true;
} else if (!strcmp(cmd, "cpu")) {
- fiq_debugger_printf(&state->output, "cpu %d\n", state->current_cpu);
- } else if (!strncmp(cmd, "cpu ", 4)) {
+ if (sysrq_on())
+ fiq_debugger_printf(&state->output, "cpu %d\n",
+ state->current_cpu);
+ } else if (!strncmp(cmd, "cpu ", 4) && sysrq_on()) {
unsigned long cpu = 0;
if (kstrtoul(cmd + 4, 10, &cpu) == 0)
fiq_debugger_switch_cpu(state, cpu);
else
fiq_debugger_printf(&state->output, "invalid cpu\n");
- fiq_debugger_printf(&state->output, "cpu %d\n", state->current_cpu);
+ fiq_debugger_printf(&state->output, "cpu %d\n",
+ state->current_cpu);
} else {
if (state->debug_busy) {
fiq_debugger_printf(&state->output,
diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c
index 4082a7d..9f47fb3 100644
--- a/drivers/staging/android/ion/ion.c
+++ b/drivers/staging/android/ion/ion.c
@@ -16,6 +16,7 @@
*
*/
+#include <linux/atomic.h>
#include <linux/err.h>
#include <linux/file.h>
#include <linux/freezer.h>
@@ -114,6 +115,7 @@
*/
struct ion_handle {
struct kref ref;
+ unsigned int user_ref_count;
struct ion_client *client;
struct ion_buffer *buffer;
struct rb_node node;
@@ -264,7 +266,7 @@
mutex_lock(&dev->buffer_lock);
ion_buffer_add(dev, buffer);
mutex_unlock(&dev->buffer_lock);
- atomic_add(len, &heap->total_allocated);
+ atomic_long_add(len, &heap->total_allocated);
return buffer;
err:
@@ -282,7 +284,7 @@
buffer->heap->ops->unmap_kernel(buffer->heap, buffer);
buffer->heap->ops->unmap_dma(buffer->heap, buffer);
- atomic_sub(buffer->size, &buffer->heap->total_allocated);
+ atomic_long_sub(buffer->size, &buffer->heap->total_allocated);
buffer->heap->ops->free(buffer);
vfree(buffer->pages);
kfree(buffer);
@@ -320,7 +322,7 @@
{
mutex_lock(&buffer->lock);
if (buffer->handle_count == 0)
- atomic_add(buffer->size, &buffer->heap->total_handles);
+ atomic_long_add(buffer->size, &buffer->heap->total_handles);
buffer->handle_count++;
mutex_unlock(&buffer->lock);
@@ -346,7 +348,7 @@
task = current->group_leader;
get_task_comm(buffer->task_comm, task);
buffer->pid = task_pid_nr(task);
- atomic_sub(buffer->size, &buffer->heap->total_handles);
+ atomic_long_sub(buffer->size, &buffer->heap->total_handles);
}
mutex_unlock(&buffer->lock);
}
@@ -402,6 +404,15 @@
kref_get(&handle->ref);
}
+/* Must hold the client lock */
+static struct ion_handle* ion_handle_get_check_overflow(struct ion_handle *handle)
+{
+ if (atomic_read(&handle->ref.refcount) + 1 == 0)
+ return ERR_PTR(-EOVERFLOW);
+ ion_handle_get(handle);
+ return handle;
+}
+
static int ion_handle_put_nolock(struct ion_handle *handle)
{
int ret;
@@ -423,6 +434,50 @@
return ret;
}
+/* Must hold the client lock */
+static void user_ion_handle_get(struct ion_handle *handle)
+{
+ if (handle->user_ref_count++ == 0)
+ kref_get(&handle->ref);
+}
+
+/* Must hold the client lock */
+static struct ion_handle *user_ion_handle_get_check_overflow(
+ struct ion_handle *handle)
+{
+ if (handle->user_ref_count + 1 == 0)
+ return ERR_PTR(-EOVERFLOW);
+ user_ion_handle_get(handle);
+ return handle;
+}
+
+/* passes a kref to the user ref count.
+ * We know we're holding a kref to the object before and
+ * after this call, so no need to reverify handle.
+ */
+static struct ion_handle *pass_to_user(struct ion_handle *handle)
+{
+ struct ion_client *client = handle->client;
+ struct ion_handle *ret;
+
+ mutex_lock(&client->lock);
+ ret = user_ion_handle_get_check_overflow(handle);
+ ion_handle_put_nolock(handle);
+ mutex_unlock(&client->lock);
+ return ret;
+}
+
+/* Must hold the client lock */
+static int user_ion_handle_put_nolock(struct ion_handle *handle)
+{
+ int ret = 0;
+
+ if (--handle->user_ref_count == 0)
+ ret = ion_handle_put_nolock(handle);
+
+ return ret;
+}
+
static struct ion_handle *ion_handle_lookup(struct ion_client *client,
struct ion_buffer *buffer)
{
@@ -448,9 +503,9 @@
handle = idr_find(&client->idr, id);
if (handle)
- ion_handle_get(handle);
+ return ion_handle_get_check_overflow(handle);
- return handle ? handle : ERR_PTR(-EINVAL);
+ return ERR_PTR(-EINVAL);
}
struct ion_handle *ion_handle_get_by_id(struct ion_client *client,
@@ -640,6 +695,25 @@
ion_handle_put_nolock(handle);
}
+static void user_ion_free_nolock(struct ion_client *client,
+ struct ion_handle *handle)
+{
+ bool valid_handle;
+
+ WARN_ON(client != handle->client);
+
+ valid_handle = ion_handle_validate(client, handle);
+ if (!valid_handle) {
+ WARN(1, "%s: invalid handle passed to free.\n", __func__);
+ return;
+ }
+ if (!handle->user_ref_count > 0) {
+ WARN(1, "%s: User does not have access!\n", __func__);
+ return;
+ }
+ user_ion_handle_put_nolock(handle);
+}
+
void ion_free(struct ion_client *client, struct ion_handle *handle)
{
BUG_ON(client != handle->client);
@@ -1394,7 +1468,7 @@
/* if a handle exists for this buffer just take a reference to it */
handle = ion_handle_lookup(client, buffer);
if (!IS_ERR(handle)) {
- ion_handle_get(handle);
+ handle = ion_handle_get_check_overflow(handle);
mutex_unlock(&client->lock);
goto end;
}
@@ -1504,7 +1578,7 @@
data.allocation.flags, true);
if (IS_ERR(handle))
return PTR_ERR(handle);
-
+ pass_to_user(handle);
data.allocation.handle = handle->id;
cleanup_handle = handle;
@@ -1521,7 +1595,7 @@
mutex_unlock(&client->lock);
return PTR_ERR(handle);
}
- ion_free_nolock(client, handle);
+ user_ion_free_nolock(client, handle);
ion_handle_put_nolock(handle);
mutex_unlock(&client->lock);
break;
@@ -1545,10 +1619,15 @@
struct ion_handle *handle;
handle = ion_import_dma_buf_fd(client, data.fd.fd);
- if (IS_ERR(handle))
+ if (IS_ERR(handle)) {
ret = PTR_ERR(handle);
- else
- data.handle.handle = handle->id;
+ } else {
+ handle = pass_to_user(handle);
+ if (IS_ERR(handle))
+ ret = PTR_ERR(handle);
+ else
+ data.handle.handle = handle->id;
+ }
break;
}
case ION_IOC_SYNC:
@@ -1580,8 +1659,10 @@
if (dir & _IOC_READ) {
if (copy_to_user((void __user *)arg, &data, _IOC_SIZE(cmd))) {
if (cleanup_handle) {
- ion_free(client, cleanup_handle);
- ion_handle_put(cleanup_handle);
+ mutex_lock(&client->lock);
+ user_ion_free_nolock(client, cleanup_handle);
+ ion_handle_put_nolock(cleanup_handle);
+ mutex_unlock(&client->lock);
}
return -EFAULT;
}
@@ -1838,10 +1919,10 @@
"Total orphaned size");
pr_info("---------------------------------\n");
plist_for_each_entry(heap, &dev->heaps, node) {
- pr_info("%16.s 0x%16.x 0x%16.x\n",
- heap->name, atomic_read(&heap->total_allocated),
- atomic_read(&heap->total_allocated) -
- atomic_read(&heap->total_handles));
+ pr_info("%16.s 0x%16.lx 0x%16.lx\n",
+ heap->name, atomic_long_read(&heap->total_allocated),
+ atomic_long_read(&heap->total_allocated) -
+ atomic_long_read(&heap->total_handles));
if (heap->debug_show)
heap->debug_show(heap, NULL, 0);
}
diff --git a/drivers/staging/android/ion/ion_cma_heap.c b/drivers/staging/android/ion/ion_cma_heap.c
index ff6436f..b264ec2 100644
--- a/drivers/staging/android/ion/ion_cma_heap.c
+++ b/drivers/staging/android/ion/ion_cma_heap.c
@@ -241,14 +241,18 @@
static void ion_secure_cma_free(struct ion_buffer *buffer)
{
- int ret = 0;
+ int i, ret = 0;
int *source_vm_list;
int source_nelems;
int dest_vmid;
int dest_perms;
+ struct sg_table *sgt;
+ struct scatterlist *sg;
struct ion_cma_buffer_info *info = buffer->priv_virt;
source_nelems = count_set_bits(buffer->flags & ION_FLAGS_CP_MASK);
+ if (!source_nelems)
+ return;
source_vm_list = kcalloc(source_nelems, sizeof(*source_vm_list),
GFP_KERNEL);
if (!source_vm_list)
@@ -262,7 +266,8 @@
dest_vmid = VMID_HLOS;
dest_perms = PERM_READ | PERM_WRITE | PERM_EXEC;
- ret = hyp_assign_table(info->table, source_vm_list, source_nelems,
+ sgt = info->table;
+ ret = hyp_assign_table(sgt, source_vm_list, source_nelems,
&dest_vmid, &dest_perms, 1);
if (ret) {
pr_err("%s: Not freeing memory since assign failed\n",
@@ -270,6 +275,9 @@
goto out_free_source;
}
+ for_each_sg(sgt->sgl, sg, sgt->nents, i)
+ ClearPagePrivate(sg_page(sg));
+
ion_cma_free(buffer);
out_free_source:
kfree(source_vm_list);
@@ -280,17 +288,23 @@
struct ion_buffer *buffer, unsigned long len,
unsigned long align, unsigned long flags)
{
- int ret = 0;
+ int i, ret = 0;
int count;
int source_vm;
int *dest_vm_list = NULL;
int *dest_perms = NULL;
int dest_nelems;
struct ion_cma_buffer_info *info;
+ struct sg_table *sgt;
+ struct scatterlist *sg;
source_vm = VMID_HLOS;
dest_nelems = count_set_bits(flags & ION_FLAGS_CP_MASK);
+ if (!dest_nelems) {
+ ret = -EINVAL;
+ goto out;
+ }
dest_vm_list = kcalloc(dest_nelems, sizeof(*dest_vm_list), GFP_KERNEL);
if (!dest_vm_list) {
ret = -ENOMEM;
@@ -321,13 +335,18 @@
}
info = buffer->priv_virt;
- ret = hyp_assign_table(info->table, &source_vm, 1,
- dest_vm_list, dest_perms, dest_nelems);
+ sgt = info->table;
+ ret = hyp_assign_table(sgt, &source_vm, 1, dest_vm_list, dest_perms,
+ dest_nelems);
if (ret) {
pr_err("%s: Assign call failed\n", __func__);
goto err;
}
+ /* Set the private bit to indicate that we've secured this */
+ for_each_sg(sgt->sgl, sg, sgt->nents, i)
+ SetPagePrivate(sg_page(sg));
+
kfree(dest_vm_list);
kfree(dest_perms);
return ret;
diff --git a/drivers/staging/android/ion/ion_priv.h b/drivers/staging/android/ion/ion_priv.h
index aa2d2d7..bb119cc 100644
--- a/drivers/staging/android/ion/ion_priv.h
+++ b/drivers/staging/android/ion/ion_priv.h
@@ -216,8 +216,8 @@
struct task_struct *task;
int (*debug_show)(struct ion_heap *heap, struct seq_file *, void *);
- atomic_t total_allocated;
- atomic_t total_handles;
+ atomic_long_t total_allocated;
+ atomic_long_t total_handles;
};
/**
diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c
index c0cda28..616375a 100644
--- a/drivers/staging/android/lowmemorykiller.c
+++ b/drivers/staging/android/lowmemorykiller.c
@@ -51,6 +51,7 @@
#define CREATE_TRACE_POINTS
#include <trace/events/almk.h>
+#include <linux/show_mem_notifier.h>
#ifdef CONFIG_HIGHMEM
#define _ZONE ZONE_HIGHMEM
@@ -525,7 +526,7 @@
task_set_lmk_waiting(selected);
task_unlock(selected);
trace_lowmemory_kill(selected, cache_size, cache_limit, free);
- lowmem_print(1, "Killing '%s' (%d), adj %hd,\n"
+ lowmem_print(1, "Killing '%s' (%d) (tgid %d), adj %hd,\n"
"to free %ldkB on behalf of '%s' (%d) because\n"
"cache %ldkB is below limit %ldkB for oom score %hd\n"
"Free memory is %ldkB above reserved.\n"
@@ -534,7 +535,7 @@
"Total free pages is %ldkB\n"
"Total file cache is %ldkB\n"
"GFP mask is 0x%x\n",
- selected->comm, selected->pid,
+ selected->comm, selected->pid, selected->tgid,
selected_oom_score_adj,
selected_tasksize * (long)(PAGE_SIZE / 1024),
current->comm, current->pid,
@@ -552,6 +553,7 @@
if (lowmem_debug_level >= 2 && selected_oom_score_adj == 0) {
show_mem(SHOW_MEM_FILTER_NODES);
+ show_mem_call_notifiers();
dump_tasks(NULL, NULL);
}
diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c
index 1c967c3..a574885 100644
--- a/drivers/staging/comedi/drivers/ni_mio_common.c
+++ b/drivers/staging/comedi/drivers/ni_mio_common.c
@@ -3078,8 +3078,7 @@
/* following line: 2-1 per STC */
ni_stc_writel(dev, 1, NISTC_AO_UI_LOADA_REG);
ni_stc_writew(dev, NISTC_AO_CMD1_UI_LOAD, NISTC_AO_CMD1_REG);
- /* following line: N-1 per STC */
- ni_stc_writel(dev, trigvar - 1, NISTC_AO_UI_LOADA_REG);
+ ni_stc_writel(dev, trigvar, NISTC_AO_UI_LOADA_REG);
} else { /* TRIG_EXT */
/* FIXME: assert scan_begin_arg != 0, ret failure otherwise */
devpriv->ao_cmd2 |= NISTC_AO_CMD2_BC_GATE_ENA;
diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c
index b27de88..995f2da 100644
--- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c
+++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c
@@ -1650,8 +1650,13 @@
ibmsg = tx->tx_msg;
ibmsg->ibm_u.immediate.ibim_hdr = *hdr;
- copy_from_iter(&ibmsg->ibm_u.immediate.ibim_payload, IBLND_MSG_SIZE,
- &from);
+ rc = copy_from_iter(&ibmsg->ibm_u.immediate.ibim_payload, payload_nob,
+ &from);
+ if (rc != payload_nob) {
+ kiblnd_pool_free_node(&tx->tx_pool->tpo_pool, &tx->tx_list);
+ return -EFAULT;
+ }
+
nob = offsetof(struct kib_immediate_msg, ibim_payload[payload_nob]);
kiblnd_init_tx_msg(ni, tx, IBLND_MSG_IMMEDIATE, nob);
@@ -1751,8 +1756,14 @@
break;
}
- copy_to_iter(&rxmsg->ibm_u.immediate.ibim_payload,
- IBLND_MSG_SIZE, to);
+ rc = copy_to_iter(&rxmsg->ibm_u.immediate.ibim_payload, rlen,
+ to);
+ if (rc != rlen) {
+ rc = -EFAULT;
+ break;
+ }
+
+ rc = 0;
lnet_finalize(ni, lntmsg, 0);
break;
diff --git a/drivers/staging/rtl8188eu/os_dep/usb_intf.c b/drivers/staging/rtl8188eu/os_dep/usb_intf.c
index 68e1e6b..b432153 100644
--- a/drivers/staging/rtl8188eu/os_dep/usb_intf.c
+++ b/drivers/staging/rtl8188eu/os_dep/usb_intf.c
@@ -43,6 +43,7 @@
{USB_DEVICE(0x2001, 0x330F)}, /* DLink DWA-125 REV D1 */
{USB_DEVICE(0x2001, 0x3310)}, /* Dlink DWA-123 REV D1 */
{USB_DEVICE(0x2001, 0x3311)}, /* DLink GO-USB-N150 REV B1 */
+ {USB_DEVICE(0x2357, 0x010c)}, /* TP-Link TL-WN722N v2 */
{USB_DEVICE(0x0df6, 0x0076)}, /* Sitecom N150 v2 */
{} /* Terminating entry */
};
diff --git a/drivers/staging/rts5208/rtsx_scsi.c b/drivers/staging/rts5208/rtsx_scsi.c
index becb4bb..01438fa 100644
--- a/drivers/staging/rts5208/rtsx_scsi.c
+++ b/drivers/staging/rts5208/rtsx_scsi.c
@@ -536,7 +536,7 @@
if (sendbytes > 8) {
memcpy(buf, inquiry_buf, 8);
- memcpy(buf + 8, inquiry_string, sendbytes - 8);
+ strncpy(buf + 8, inquiry_string, sendbytes - 8);
if (pro_formatter_flag) {
/* Additional Length */
buf[4] = 0x33;
diff --git a/drivers/staging/sm750fb/sm750.c b/drivers/staging/sm750fb/sm750.c
index 7d90e25..86ace14 100644
--- a/drivers/staging/sm750fb/sm750.c
+++ b/drivers/staging/sm750fb/sm750.c
@@ -1049,6 +1049,26 @@
return err;
}
+static int lynxfb_kick_out_firmware_fb(struct pci_dev *pdev)
+{
+ struct apertures_struct *ap;
+ bool primary = false;
+
+ ap = alloc_apertures(1);
+ if (!ap)
+ return -ENOMEM;
+
+ ap->ranges[0].base = pci_resource_start(pdev, 0);
+ ap->ranges[0].size = pci_resource_len(pdev, 0);
+#ifdef CONFIG_X86
+ primary = pdev->resource[PCI_ROM_RESOURCE].flags &
+ IORESOURCE_ROM_SHADOW;
+#endif
+ remove_conflicting_framebuffers(ap, "sm750_fb1", primary);
+ kfree(ap);
+ return 0;
+}
+
static int lynxfb_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -1057,6 +1077,10 @@
int fbidx;
int err;
+ err = lynxfb_kick_out_firmware_fb(pdev);
+ if (err)
+ return err;
+
/* enable device */
err = pcim_enable_device(pdev);
if (err)
diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c
index 7e70fe8..9cbbc9c 100644
--- a/drivers/target/iscsi/iscsi_target_configfs.c
+++ b/drivers/target/iscsi/iscsi_target_configfs.c
@@ -802,6 +802,7 @@
DEF_TPG_ATTRIB(t10_pi);
DEF_TPG_ATTRIB(fabric_prot_type);
DEF_TPG_ATTRIB(tpg_enabled_sendtargets);
+DEF_TPG_ATTRIB(login_keys_workaround);
static struct configfs_attribute *lio_target_tpg_attrib_attrs[] = {
&iscsi_tpg_attrib_attr_authentication,
@@ -817,6 +818,7 @@
&iscsi_tpg_attrib_attr_t10_pi,
&iscsi_tpg_attrib_attr_fabric_prot_type,
&iscsi_tpg_attrib_attr_tpg_enabled_sendtargets,
+ &iscsi_tpg_attrib_attr_login_keys_workaround,
NULL,
};
diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c
index 89d34bd..6693d7c 100644
--- a/drivers/target/iscsi/iscsi_target_nego.c
+++ b/drivers/target/iscsi/iscsi_target_nego.c
@@ -819,7 +819,8 @@
SENDER_TARGET,
login->rsp_buf,
&login->rsp_length,
- conn->param_list);
+ conn->param_list,
+ conn->tpg->tpg_attrib.login_keys_workaround);
if (ret < 0)
return -1;
@@ -889,7 +890,8 @@
SENDER_TARGET,
login->rsp_buf,
&login->rsp_length,
- conn->param_list);
+ conn->param_list,
+ conn->tpg->tpg_attrib.login_keys_workaround);
if (ret < 0) {
iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
ISCSI_LOGIN_STATUS_INIT_ERR);
diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c
index 4a073339a..0151776 100644
--- a/drivers/target/iscsi/iscsi_target_parameters.c
+++ b/drivers/target/iscsi/iscsi_target_parameters.c
@@ -765,7 +765,8 @@
return 0;
}
-static void iscsi_check_proposer_for_optional_reply(struct iscsi_param *param)
+static void iscsi_check_proposer_for_optional_reply(struct iscsi_param *param,
+ bool keys_workaround)
{
if (IS_TYPE_BOOL_AND(param)) {
if (!strcmp(param->value, NO))
@@ -773,19 +774,31 @@
} else if (IS_TYPE_BOOL_OR(param)) {
if (!strcmp(param->value, YES))
SET_PSTATE_REPLY_OPTIONAL(param);
- /*
- * Required for gPXE iSCSI boot client
- */
- if (!strcmp(param->name, IMMEDIATEDATA))
- SET_PSTATE_REPLY_OPTIONAL(param);
+
+ if (keys_workaround) {
+ /*
+ * Required for gPXE iSCSI boot client
+ */
+ if (!strcmp(param->name, IMMEDIATEDATA))
+ SET_PSTATE_REPLY_OPTIONAL(param);
+ }
} else if (IS_TYPE_NUMBER(param)) {
if (!strcmp(param->name, MAXRECVDATASEGMENTLENGTH))
SET_PSTATE_REPLY_OPTIONAL(param);
- /*
- * Required for gPXE iSCSI boot client
- */
- if (!strcmp(param->name, MAXCONNECTIONS))
- SET_PSTATE_REPLY_OPTIONAL(param);
+
+ if (keys_workaround) {
+ /*
+ * Required for Mellanox Flexboot PXE boot ROM
+ */
+ if (!strcmp(param->name, FIRSTBURSTLENGTH))
+ SET_PSTATE_REPLY_OPTIONAL(param);
+
+ /*
+ * Required for gPXE iSCSI boot client
+ */
+ if (!strcmp(param->name, MAXCONNECTIONS))
+ SET_PSTATE_REPLY_OPTIONAL(param);
+ }
} else if (IS_PHASE_DECLARATIVE(param))
SET_PSTATE_REPLY_OPTIONAL(param);
}
@@ -1422,7 +1435,8 @@
u8 sender,
char *textbuf,
u32 *length,
- struct iscsi_param_list *param_list)
+ struct iscsi_param_list *param_list,
+ bool keys_workaround)
{
char *output_buf = NULL;
struct iscsi_extra_response *er;
@@ -1458,7 +1472,8 @@
*length += 1;
output_buf = textbuf + *length;
SET_PSTATE_PROPOSER(param);
- iscsi_check_proposer_for_optional_reply(param);
+ iscsi_check_proposer_for_optional_reply(param,
+ keys_workaround);
pr_debug("Sending key: %s=%s\n",
param->name, param->value);
}
diff --git a/drivers/target/iscsi/iscsi_target_parameters.h b/drivers/target/iscsi/iscsi_target_parameters.h
index a0751e3..17a58c2 100644
--- a/drivers/target/iscsi/iscsi_target_parameters.h
+++ b/drivers/target/iscsi/iscsi_target_parameters.h
@@ -40,7 +40,7 @@
extern int iscsi_update_param_value(struct iscsi_param *, char *);
extern int iscsi_decode_text_input(u8, u8, char *, u32, struct iscsi_conn *);
extern int iscsi_encode_text_output(u8, u8, char *, u32 *,
- struct iscsi_param_list *);
+ struct iscsi_param_list *, bool);
extern int iscsi_check_negotiated_keys(struct iscsi_param_list *);
extern void iscsi_set_connection_parameters(struct iscsi_conn_ops *,
struct iscsi_param_list *);
diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c
index 205a509..63e1dcc 100644
--- a/drivers/target/iscsi/iscsi_target_tpg.c
+++ b/drivers/target/iscsi/iscsi_target_tpg.c
@@ -227,6 +227,7 @@
a->t10_pi = TA_DEFAULT_T10_PI;
a->fabric_prot_type = TA_DEFAULT_FABRIC_PROT_TYPE;
a->tpg_enabled_sendtargets = TA_DEFAULT_TPG_ENABLED_SENDTARGETS;
+ a->login_keys_workaround = TA_DEFAULT_LOGIN_KEYS_WORKAROUND;
}
int iscsit_tpg_add_portal_group(struct iscsi_tiqn *tiqn, struct iscsi_portal_group *tpg)
@@ -899,3 +900,21 @@
return 0;
}
+
+int iscsit_ta_login_keys_workaround(
+ struct iscsi_portal_group *tpg,
+ u32 flag)
+{
+ struct iscsi_tpg_attrib *a = &tpg->tpg_attrib;
+
+ if ((flag != 0) && (flag != 1)) {
+ pr_err("Illegal value %d\n", flag);
+ return -EINVAL;
+ }
+
+ a->login_keys_workaround = flag;
+ pr_debug("iSCSI_TPG[%hu] - TPG enabled bit for login keys workaround: %s ",
+ tpg->tpgt, (a->login_keys_workaround) ? "ON" : "OFF");
+
+ return 0;
+}
diff --git a/drivers/target/iscsi/iscsi_target_tpg.h b/drivers/target/iscsi/iscsi_target_tpg.h
index 2da2119..901a712 100644
--- a/drivers/target/iscsi/iscsi_target_tpg.h
+++ b/drivers/target/iscsi/iscsi_target_tpg.h
@@ -39,5 +39,6 @@
extern int iscsit_ta_t10_pi(struct iscsi_portal_group *, u32);
extern int iscsit_ta_fabric_prot_type(struct iscsi_portal_group *, u32);
extern int iscsit_ta_tpg_enabled_sendtargets(struct iscsi_portal_group *, u32);
+extern int iscsit_ta_login_keys_workaround(struct iscsi_portal_group *, u32);
#endif /* ISCSI_TARGET_TPG_H */
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 1f9bfa4..e8a1f5c 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -753,6 +753,15 @@
if (cmd->transport_state & CMD_T_ABORTED ||
cmd->transport_state & CMD_T_STOP) {
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+ /*
+ * If COMPARE_AND_WRITE was stopped by __transport_wait_for_tasks(),
+ * release se_device->caw_sem obtained by sbc_compare_and_write()
+ * since target_complete_ok_work() or target_complete_failure_work()
+ * won't be called to invoke the normal CAW completion callbacks.
+ */
+ if (cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE) {
+ up(&dev->caw_sem);
+ }
complete_all(&cmd->t_transport_stop_comp);
return;
} else if (!success) {
diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
index cd5bde3..09f7f20 100644
--- a/drivers/thermal/cpu_cooling.c
+++ b/drivers/thermal/cpu_cooling.c
@@ -205,8 +205,10 @@
mutex_lock(&cooling_list_lock);
list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) {
if (cpumask_test_cpu(cpu, &cpufreq_dev->allowed_cpus)) {
+ unsigned long level = get_level(cpufreq_dev, freq);
+
mutex_unlock(&cooling_list_lock);
- return get_level(cpufreq_dev, freq);
+ return level;
}
}
mutex_unlock(&cooling_list_lock);
diff --git a/drivers/thermal/max77620_thermal.c b/drivers/thermal/max77620_thermal.c
index 83905ff..7e98927 100644
--- a/drivers/thermal/max77620_thermal.c
+++ b/drivers/thermal/max77620_thermal.c
@@ -104,8 +104,6 @@
return -EINVAL;
}
- pdev->dev.of_node = pdev->dev.parent->of_node;
-
mtherm->dev = &pdev->dev;
mtherm->rmap = dev_get_regmap(pdev->dev.parent, NULL);
if (!mtherm->rmap) {
@@ -113,6 +111,14 @@
return -ENODEV;
}
+ /*
+ * Drop any current reference to a device-tree node and get a
+ * reference to the parent's node which will be balanced on reprobe or
+ * on platform-device release.
+ */
+ of_node_put(pdev->dev.of_node);
+ pdev->dev.of_node = of_node_get(pdev->dev.parent->of_node);
+
mtherm->tz_device = devm_thermal_zone_of_sensor_register(&pdev->dev, 0,
mtherm, &max77620_thermal_ops);
if (IS_ERR(mtherm->tz_device)) {
diff --git a/drivers/thermal/msm-tsens.c b/drivers/thermal/msm-tsens.c
index a04ddae..fe0a7c7 100644
--- a/drivers/thermal/msm-tsens.c
+++ b/drivers/thermal/msm-tsens.c
@@ -160,14 +160,18 @@
for (i = 0; i < TSENS_MAX_SENSORS; i++) {
tmdev->sensor[i].tmdev = tmdev;
tmdev->sensor[i].hw_id = i;
- tmdev->sensor[i].tzd =
- devm_thermal_zone_of_sensor_register(
- &tmdev->pdev->dev, i,
- &tmdev->sensor[i], &tsens_tm_thermal_zone_ops);
- if (IS_ERR(tmdev->sensor[i].tzd)) {
- pr_debug("Error registering sensor:%d\n", i);
- sensor_missing++;
- continue;
+ if (tmdev->ops->sensor_en(tmdev, i)) {
+ tmdev->sensor[i].tzd =
+ devm_thermal_zone_of_sensor_register(
+ &tmdev->pdev->dev, i,
+ &tmdev->sensor[i], &tsens_tm_thermal_zone_ops);
+ if (IS_ERR(tmdev->sensor[i].tzd)) {
+ pr_debug("Error registering sensor:%d\n", i);
+ sensor_missing++;
+ continue;
+ }
+ } else {
+ pr_debug("Sensor not enabled:%d\n", i);
}
}
diff --git a/drivers/thermal/qcom/Kconfig b/drivers/thermal/qcom/Kconfig
index be33725..e7d6241 100644
--- a/drivers/thermal/qcom/Kconfig
+++ b/drivers/thermal/qcom/Kconfig
@@ -41,14 +41,14 @@
sensors to query for temperature and the aggregation logic to
determine the virtual sensor temperature.
-config QTI_REG_COOLING_DEVICE
- bool "QTI Regulator cooling device"
+config QTI_AOP_REG_COOLING_DEVICE
+ bool "QTI AOP Regulator cooling device"
depends on THERMAL_OF && MSM_QMP
help
- This enables the Regulator cooling device. This cooling device
- will be used by QTI chipset to place a floor voltage restriction at
- low temperatures. The regulator cooling device will message the AOP
- using mail box to establish the floor voltage.
+ This enables the AOP based Regulator cooling device. This cooling
+ device will be used by QTI chipset to place a floor voltage
+ restriction at low temperatures. The cooling device will message
+ the AOP using mail box to establish the floor voltage.
config QTI_QMI_COOLING_DEVICE
bool "QTI QMI cooling devices"
@@ -60,3 +60,14 @@
remote subsystem voltage restriction at low temperatures etc.
The QMI cooling device will interface with remote subsystem
using QTI QMI interface.
+
+config REGULATOR_COOLING_DEVICE
+ bool "Regulator voltage floor cooling device"
+ depends on REGULATOR && THERMAL_OF
+ help
+ This implements a mitigation device to place a minimum voltage floor
+ on a particular regulator. This mitigation device will be used by low
+ temperature reliability rules to mitigate a regulator at nominal
+ voltage.
+
+ If you want this support, you should say Y here.
diff --git a/drivers/thermal/qcom/Makefile b/drivers/thermal/qcom/Makefile
index 000c6e7..257b714 100644
--- a/drivers/thermal/qcom/Makefile
+++ b/drivers/thermal/qcom/Makefile
@@ -3,5 +3,6 @@
obj-$(CONFIG_MSM_BCL_PERIPHERAL_CTL) += bcl_peripheral.o
obj-$(CONFIG_QTI_THERMAL_LIMITS_DCVS) += msm_lmh_dcvs.o lmh_dbg.o
obj-$(CONFIG_QTI_VIRTUAL_SENSOR) += qti_virtual_sensor.o
-obj-$(CONFIG_QTI_REG_COOLING_DEVICE) += regulator_cooling.o
+obj-$(CONFIG_QTI_AOP_REG_COOLING_DEVICE) += regulator_aop_cdev.o
+obj-$(CONFIG_REGULATOR_COOLING_DEVICE) += regulator_cdev.o
obj-$(CONFIG_QTI_QMI_COOLING_DEVICE) += thermal_mitigation_device_service_v01.o qmi_cooling.o
diff --git a/drivers/thermal/qcom/msm_lmh_dcvs.c b/drivers/thermal/qcom/msm_lmh_dcvs.c
index 4284b6c..d590d24 100644
--- a/drivers/thermal/qcom/msm_lmh_dcvs.c
+++ b/drivers/thermal/qcom/msm_lmh_dcvs.c
@@ -26,6 +26,7 @@
#include <linux/pm_opp.h>
#include <linux/cpu_cooling.h>
#include <linux/atomic.h>
+#include <linux/regulator/consumer.h>
#include <asm/smp_plat.h>
#include <asm/cacheflush.h>
@@ -102,10 +103,12 @@
unsigned long max_freq;
unsigned long min_freq;
unsigned long hw_freq_limit;
+ struct device_attribute lmh_freq_attr;
struct list_head list;
atomic_t is_irq_enabled;
struct mutex access_lock;
struct __limits_cdev_data *cdev_data;
+ struct regulator *isens_reg;
};
LIST_HEAD(lmh_dcvs_hw_list);
@@ -430,6 +433,60 @@
return 0;
}
+static void limits_isens_vref_ldo_init(struct platform_device *pdev,
+ struct limits_dcvs_hw *hw)
+{
+ int ret = 0;
+ uint32_t settings[3];
+
+ hw->isens_reg = devm_regulator_get(&pdev->dev, "isens_vref");
+ if (IS_ERR_OR_NULL(hw->isens_reg)) {
+ if (PTR_ERR(hw->isens_reg) == -ENODEV)
+ return;
+
+ pr_err("Regulator:isens_vref init error:%ld\n",
+ PTR_ERR(hw->isens_reg));
+ return;
+ }
+ ret = of_property_read_u32_array(pdev->dev.of_node,
+ "isens-vref-settings",
+ settings, 3);
+ if (ret) {
+ pr_err("Regulator:isens_vref settings read error:%d\n",
+ ret);
+ devm_regulator_put(hw->isens_reg);
+ return;
+ }
+ ret = regulator_set_voltage(hw->isens_reg, settings[0], settings[1]);
+ if (ret) {
+ pr_err("Regulator:isens_vref set voltage error:%d\n", ret);
+ devm_regulator_put(hw->isens_reg);
+ return;
+ }
+ ret = regulator_set_load(hw->isens_reg, settings[2]);
+ if (ret) {
+ pr_err("Regulator:isens_vref set load error:%d\n", ret);
+ devm_regulator_put(hw->isens_reg);
+ return;
+ }
+ if (regulator_enable(hw->isens_reg)) {
+ pr_err("Failed to enable regulator:isens_vref\n");
+ devm_regulator_put(hw->isens_reg);
+ return;
+ }
+}
+
+static ssize_t
+lmh_freq_limit_show(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct limits_dcvs_hw *hw = container_of(devattr,
+ struct limits_dcvs_hw,
+ lmh_freq_attr);
+
+ return snprintf(buf, PAGE_SIZE, "%lu\n", hw->hw_freq_limit);
+}
+
static int limits_dcvs_probe(struct platform_device *pdev)
{
int ret;
@@ -585,6 +642,11 @@
ret = 0;
goto probe_exit;
}
+ limits_isens_vref_ldo_init(pdev, hw);
+ hw->lmh_freq_attr.attr.name = "lmh_freq_limit";
+ hw->lmh_freq_attr.show = lmh_freq_limit_show;
+ hw->lmh_freq_attr.attr.mode = 0444;
+ device_create_file(&pdev->dev, &hw->lmh_freq_attr);
probe_exit:
mutex_lock(&lmh_dcvs_list_access);
diff --git a/drivers/thermal/qcom/regulator_cooling.c b/drivers/thermal/qcom/regulator_aop_cdev.c
similarity index 98%
rename from drivers/thermal/qcom/regulator_cooling.c
rename to drivers/thermal/qcom/regulator_aop_cdev.c
index 3cbf198..965be2f 100644
--- a/drivers/thermal/qcom/regulator_cooling.c
+++ b/drivers/thermal/qcom/regulator_aop_cdev.c
@@ -17,7 +17,7 @@
#include <linux/slab.h>
#include <linux/mailbox_client.h>
-#define REG_CDEV_DRIVER "reg-cooling-device"
+#define REG_CDEV_DRIVER "reg-aop-cooling-device"
#define REG_MSG_FORMAT "{class:volt_flr, event:zero_temp, res:%s, value:%s}"
#define REG_CDEV_MAX_STATE 1
#define MBOX_TOUT_MS 1000
diff --git a/drivers/thermal/qcom/regulator_cdev.c b/drivers/thermal/qcom/regulator_cdev.c
new file mode 100644
index 0000000..a770dcb
--- /dev/null
+++ b/drivers/thermal/qcom/regulator_cdev.c
@@ -0,0 +1,184 @@
+/* Copyright (c) 2017, The Linux Foundation. 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 and
+ * only 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/platform_device.h>
+#include <linux/thermal.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/regulator/consumer.h>
+
+#define REG_CDEV_DRIVER "reg-cooling-device"
+
+struct reg_cooling_device {
+ struct regulator *reg;
+ struct thermal_cooling_device *cool_dev;
+ unsigned int min_reg_state;
+ unsigned int *lvl;
+ unsigned int lvl_ct;
+ char reg_name[THERMAL_NAME_LENGTH];
+ bool reg_enable;
+};
+
+static int reg_get_max_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ struct reg_cooling_device *reg_dev = cdev->devdata;
+
+ *state = reg_dev->lvl_ct;
+ return 0;
+}
+
+static int reg_get_min_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ struct reg_cooling_device *reg_dev = cdev->devdata;
+
+ *state = reg_dev->min_reg_state;
+ return 0;
+}
+
+static int reg_set_min_state(struct thermal_cooling_device *cdev,
+ unsigned long state)
+{
+ struct reg_cooling_device *reg_dev = cdev->devdata;
+ int ret = 0;
+
+ if (state > reg_dev->lvl_ct)
+ state = reg_dev->lvl_ct;
+
+ if (reg_dev->min_reg_state == state)
+ return ret;
+
+ ret = regulator_set_voltage(reg_dev->reg,
+ reg_dev->lvl[state], INT_MAX);
+ if (ret) {
+ dev_err(&cdev->device,
+ "switching to floor %lu err:%d\n",
+ state, ret);
+ return ret;
+ }
+ if (reg_dev->reg_enable && state == reg_dev->lvl_ct) {
+ ret = regulator_disable(reg_dev->reg);
+ if (ret) {
+ dev_err(&cdev->device,
+ "regulator disable err:%d\n", ret);
+ return ret;
+ }
+ reg_dev->reg_enable = false;
+ } else if (!reg_dev->reg_enable && state != reg_dev->lvl_ct) {
+ ret = regulator_enable(reg_dev->reg);
+ if (ret) {
+ dev_err(&cdev->device,
+ "regulator enable err:%d\n", ret);
+ return ret;
+ }
+ reg_dev->reg_enable = true;
+ }
+ reg_dev->min_reg_state = state;
+
+ return ret;
+}
+
+static int reg_get_cur_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ *state = 0;
+ return 0;
+}
+
+static int reg_set_cur_state(struct thermal_cooling_device *cdev,
+ unsigned long state)
+{
+ /* regulator cooling device doesn't support voltage ceil */
+ return 0;
+}
+
+static struct thermal_cooling_device_ops reg_device_ops = {
+ .get_max_state = reg_get_max_state,
+ .get_cur_state = reg_get_cur_state,
+ .set_cur_state = reg_set_cur_state,
+ .set_min_state = reg_set_min_state,
+ .get_min_state = reg_get_min_state,
+};
+
+static int reg_cdev_probe(struct platform_device *pdev)
+{
+ struct reg_cooling_device *reg_dev;
+ int ret = 0;
+ struct device_node *np;
+
+ np = dev_of_node(&pdev->dev);
+ if (!np) {
+ dev_err(&pdev->dev,
+ "of node not available for cooling device\n");
+ return -EINVAL;
+ }
+
+ reg_dev = devm_kzalloc(&pdev->dev, sizeof(*reg_dev), GFP_KERNEL);
+ if (!reg_dev)
+ return -ENOMEM;
+
+ reg_dev->reg = devm_regulator_get(&pdev->dev, "regulator-cdev");
+ if (IS_ERR_OR_NULL(reg_dev->reg)) {
+ ret = PTR_ERR(reg_dev->reg);
+ dev_err(&pdev->dev, "regulator register err:%d\n", ret);
+ return ret;
+ }
+ ret = of_property_count_u32_elems(np, "regulator-levels");
+ if (ret <= 0) {
+ dev_err(&pdev->dev, "Invalid levels err:%d\n", ret);
+ return ret;
+ }
+ reg_dev->lvl_ct = ret;
+ reg_dev->lvl = devm_kcalloc(&pdev->dev, reg_dev->lvl_ct,
+ sizeof(*reg_dev->lvl), GFP_KERNEL);
+ if (!reg_dev->lvl)
+ return -ENOMEM;
+ ret = of_property_read_u32_array(np, "regulator-levels",
+ reg_dev->lvl, reg_dev->lvl_ct);
+ if (ret) {
+ dev_err(&pdev->dev, "cdev level fetch err:%d\n", ret);
+ return ret;
+ }
+ /* level count is an index and it depicts the max possible index */
+ reg_dev->lvl_ct--;
+ reg_dev->min_reg_state = reg_dev->lvl_ct;
+ reg_dev->reg_enable = false;
+ strlcpy(reg_dev->reg_name, np->name, THERMAL_NAME_LENGTH);
+
+ reg_dev->cool_dev = thermal_of_cooling_device_register(
+ np, reg_dev->reg_name, reg_dev,
+ ®_device_ops);
+ if (IS_ERR(reg_dev->cool_dev)) {
+ ret = PTR_ERR(reg_dev->cool_dev);
+ dev_err(&pdev->dev, "regulator cdev register err:%d\n",
+ ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+static const struct of_device_id reg_cdev_of_match[] = {
+ {.compatible = "qcom,regulator-cooling-device", },
+ {}
+};
+
+static struct platform_driver reg_cdev_driver = {
+ .driver = {
+ .name = REG_CDEV_DRIVER,
+ .of_match_table = reg_cdev_of_match,
+ },
+ .probe = reg_cdev_probe,
+};
+builtin_platform_driver(reg_cdev_driver);
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 95ef027..2bfe1b5 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -477,6 +477,7 @@
* So, start monitoring again.
*/
monitor_thermal_zone(tz);
+ trace_thermal_handle_trip(tz, trip);
}
/**
@@ -567,6 +568,7 @@
ret = tz->ops->set_trips(tz, low, high);
if (ret)
dev_err(&tz->device, "Failed to set trips: %d\n", ret);
+ trace_thermal_set_trip(tz);
exit:
mutex_unlock(&tz->lock);
@@ -621,6 +623,7 @@
if (!tz->ops->get_temp)
return;
+ trace_thermal_device_update(tz, event);
update_temperature(tz);
thermal_zone_set_trips(tz);
@@ -1934,6 +1937,7 @@
current_target = instance->target;
}
}
+ trace_cdev_update_start(cdev);
cdev->ops->set_cur_state(cdev, current_target);
if (cdev->ops->set_min_state)
cdev->ops->set_min_state(cdev, min_target);
diff --git a/drivers/thermal/tsens.h b/drivers/thermal/tsens.h
index 770b982..a695d57 100644
--- a/drivers/thermal/tsens.h
+++ b/drivers/thermal/tsens.h
@@ -91,6 +91,7 @@
int (*set_trips)(struct tsens_sensor *, int, int);
int (*interrupts_reg)(struct tsens_device *);
int (*dbg)(struct tsens_device *, u32, u32, int *);
+ int (*sensor_en)(struct tsens_device *, u32);
};
struct tsens_irqs {
diff --git a/drivers/thermal/tsens2xxx.c b/drivers/thermal/tsens2xxx.c
index 55be2f9..de9f27f 100644
--- a/drivers/thermal/tsens2xxx.c
+++ b/drivers/thermal/tsens2xxx.c
@@ -61,6 +61,7 @@
#define TSENS_TM_WATCHDOG_LOG(n) ((n) + 0x13c)
#define TSENS_EN BIT(0)
+#define TSENS_CTRL_SENSOR_EN_MASK(n) ((n >> 3) & 0xffff)
static void msm_tsens_convert_temp(int last_temp, int *temp)
{
@@ -499,6 +500,21 @@
return IRQ_HANDLED;
}
+static int tsens2xxx_hw_sensor_en(struct tsens_device *tmdev,
+ u32 sensor_id)
+{
+ void __iomem *srot_addr;
+ unsigned int srot_val, sensor_en;
+
+ srot_addr = TSENS_CTRL_ADDR(tmdev->tsens_srot_addr + 0x4);
+ srot_val = readl_relaxed(srot_addr);
+ srot_val = TSENS_CTRL_SENSOR_EN_MASK(srot_val);
+
+ sensor_en = ((1 << sensor_id) & srot_val);
+
+ return sensor_en;
+}
+
static int tsens2xxx_hw_init(struct tsens_device *tmdev)
{
void __iomem *srot_addr;
@@ -602,6 +618,7 @@
.set_trips = tsens2xxx_set_trip_temp,
.interrupts_reg = tsens2xxx_register_interrupts,
.dbg = tsens2xxx_dbg,
+ .sensor_en = tsens2xxx_hw_sensor_en,
};
const struct tsens_data data_tsens2xxx = {
diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c
index 17cdac4..11b4958 100644
--- a/drivers/tty/serial/msm_geni_serial.c
+++ b/drivers/tty/serial/msm_geni_serial.c
@@ -26,6 +26,7 @@
#include <linux/qcom-geni-se.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
+#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
@@ -107,9 +108,12 @@
#define UART_CORE2X_VOTE (10000)
#define WAKEBYTE_TIMEOUT_MSEC (2000)
-#define IPC_LOG_PWR_PAGES (2)
-#define IPC_LOG_MISC_PAGES (2)
-#define IPC_LOG_TX_RX_PAGES (3)
+#define WAIT_XFER_MAX_ITER (50)
+#define WAIT_XFER_MAX_TIMEOUT_US (10000)
+#define WAIT_XFER_MIN_TIMEOUT_US (9000)
+#define IPC_LOG_PWR_PAGES (6)
+#define IPC_LOG_MISC_PAGES (6)
+#define IPC_LOG_TX_RX_PAGES (8)
#define DATA_BYTES_PER_LINE (32)
#define IPC_LOG_MSG(ctx, x...) do { \
@@ -117,6 +121,7 @@
ipc_log_string(ctx, x); \
} while (0)
+#define DMA_RX_BUF_SIZE (512)
struct msm_geni_serial_port {
struct uart_port uport;
char name[20];
@@ -136,6 +141,10 @@
unsigned int rx_last);
struct device *wrapper_dev;
struct se_geni_rsc serial_rsc;
+ dma_addr_t tx_dma;
+ unsigned int xmit_size;
+ void *rx_buf;
+ dma_addr_t rx_dma;
int loopback;
int wakeup_irq;
unsigned char wakeup_byte;
@@ -146,6 +155,7 @@
void *ipc_log_misc;
unsigned int cur_baud;
int ioctl_count;
+ int edge_count;
};
static const struct uart_ops msm_geni_serial_pops;
@@ -221,27 +231,66 @@
(unsigned int)addr, size, buf);
}
-static bool check_tx_active(struct uart_port *uport)
+static bool check_transfers_inflight(struct uart_port *uport)
{
- /*
- * Poll if the GENI STATUS bit for TX is cleared. If the bit is
- * clear (poll condition met), return false, meaning tx isn't active
- * else return true. So return not of the poll return.
- */
- return !msm_geni_serial_poll_bit(uport, SE_GENI_STATUS,
- M_GENI_CMD_ACTIVE, false);
+ bool xfer_on = false;
+ bool tx_active = false;
+ bool tx_empty = false;
+ bool m_cmd_active = false;
+ bool rx_active = false;
+ u32 rx_fifo_status = 0;
+ u32 geni_status = geni_read_reg_nolog(uport->membase,
+ SE_GENI_STATUS);
+ /* Possible stop tx is called multiple times. */
+ m_cmd_active = geni_status & M_GENI_CMD_ACTIVE;
+ tx_empty = msm_geni_serial_tx_empty(uport);
+ tx_active = m_cmd_active || !tx_empty;
+ rx_fifo_status = geni_read_reg_nolog(uport->membase,
+ SE_GENI_RX_FIFO_STATUS);
+ if (rx_fifo_status)
+ rx_active = true;
+
+ if (rx_active || tx_active)
+ xfer_on = true;
+
+ return xfer_on;
+}
+
+static void wait_for_transfers_inflight(struct uart_port *uport)
+{
+ int iter = 0;
+ struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
+
+ while (iter < WAIT_XFER_MAX_ITER) {
+ if (check_transfers_inflight(uport)) {
+ usleep_range(WAIT_XFER_MIN_TIMEOUT_US,
+ WAIT_XFER_MAX_TIMEOUT_US);
+ iter++;
+ } else {
+ break;
+ }
+ }
+ if (check_transfers_inflight(uport)) {
+ u32 geni_status = geni_read_reg_nolog(uport->membase,
+ SE_GENI_STATUS);
+ u32 geni_ios = geni_read_reg_nolog(uport->membase, SE_GENI_IOS);
+ u32 rx_fifo_status = geni_read_reg_nolog(uport->membase,
+ SE_GENI_RX_FIFO_STATUS);
+
+ IPC_LOG_MSG(port->ipc_log_misc,
+ "%s IOS 0x%x geni status 0x%x rx fifo 0x%x\n",
+ __func__, geni_ios, geni_status, rx_fifo_status);
+ }
}
static int vote_clock_on(struct uart_port *uport)
{
- int ret = 0;
struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
- int usage_count = atomic_read(&uport->dev->power.usage_count);
+ int ret = 0;
if (!pm_runtime_enabled(uport->dev)) {
dev_err(uport->dev, "RPM not available.Can't enable clocks\n");
- ret = -EPERM;
- return ret;
+ return -EPERM;
}
ret = msm_geni_serial_power_on(uport);
if (ret) {
@@ -249,39 +298,31 @@
return ret;
}
port->ioctl_count++;
- __pm_relax(&port->geni_wake);
- IPC_LOG_MSG(port->ipc_log_pwr, "%s rpm %d ioctl %d\n",
- __func__, usage_count, port->ioctl_count);
+ IPC_LOG_MSG(port->ipc_log_pwr, "%s%s ioctl %d\n", __func__,
+ current->comm, port->ioctl_count);
return 0;
}
static int vote_clock_off(struct uart_port *uport)
{
struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
- int ret = 0;
- int usage_count = atomic_read(&uport->dev->power.usage_count);
if (!pm_runtime_enabled(uport->dev)) {
dev_err(uport->dev, "RPM not available.Can't enable clocks\n");
- ret = -EPERM;
- return ret;
+ return -EPERM;
}
- /* Check on going Tx. Don't block on this for now. */
- if (check_tx_active(uport))
- dev_warn(uport->dev, "%s: Vote off called during active Tx",
- __func__);
if (!port->ioctl_count) {
dev_warn(uport->dev, "%s:Imbalanced vote off ioctl %d\n",
- __func__, usage_count);
+ __func__, port->ioctl_count);
IPC_LOG_MSG(port->ipc_log_pwr,
- "%s:Imbalanced vote_off from userspace rpm%d",
- __func__, usage_count);
- return 0;
+ "%s:Imbalanced vote_off from userspace. %d",
+ __func__, port->ioctl_count);
+ return -EPERM;
}
port->ioctl_count--;
msm_geni_serial_power_off(uport);
- IPC_LOG_MSG(port->ipc_log_pwr, "%s rpm %d ioctl %d\n",
- __func__, usage_count, port->ioctl_count);
+ IPC_LOG_MSG(port->ipc_log_pwr, "%s%s ioctl %d\n", __func__,
+ current->comm, port->ioctl_count);
return 0;
};
@@ -311,14 +352,11 @@
static void msm_geni_serial_break_ctl(struct uart_port *uport, int ctl)
{
- if (!uart_console(uport) && pm_runtime_status_suspended(uport->dev)) {
- dev_err(uport->dev, "%s Device suspended,vote clocks on.\n",
- __func__);
+ if (!uart_console(uport) && pm_runtime_status_suspended(uport->dev))
return;
- }
if (ctl) {
- check_tx_active(uport);
+ wait_for_transfers_inflight(uport);
geni_setup_m_cmd(uport->membase, UART_START_BREAK, 0);
} else {
geni_setup_m_cmd(uport->membase, UART_STOP_BREAK, 0);
@@ -357,11 +395,8 @@
{
u32 uart_manual_rfr = 0;
- if (pm_runtime_status_suspended(uport->dev)) {
- dev_info(uport->dev, "%sDevice suspended,vote clocks on\n",
- __func__);
+ if (pm_runtime_status_suspended(uport->dev))
return;
- }
if (!(mctrl & TIOCM_RTS))
uart_manual_rfr |= (UART_MANUAL_RFR_EN | UART_RFR_NOT_READY);
geni_write_reg_nolog(uart_manual_rfr, uport->membase,
@@ -396,9 +431,12 @@
static int msm_geni_serial_power_on(struct uart_port *uport)
{
int ret = 0;
+ struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
ret = pm_runtime_get_sync(uport->dev);
if (ret < 0) {
+ IPC_LOG_MSG(port->ipc_log_pwr, "%s Err\n", __func__);
+ WARN_ON_ONCE(1);
pm_runtime_put_noidle(uport->dev);
pm_runtime_set_suspended(uport->dev);
return ret;
@@ -685,32 +723,98 @@
#endif /* (CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL)) */
+static int msm_geni_serial_prep_dma_tx(struct uart_port *uport)
+{
+ struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport);
+ struct circ_buf *xmit = &uport->state->xmit;
+ unsigned int xmit_size;
+ int ret = 0;
+
+ xmit_size = uart_circ_chars_pending(xmit);
+ if (xmit_size < WAKEUP_CHARS)
+ uart_write_wakeup(uport);
+
+ if (xmit_size > (UART_XMIT_SIZE - xmit->tail))
+ xmit_size = UART_XMIT_SIZE - xmit->tail;
+
+ if (!xmit_size)
+ return ret;
+
+ dump_ipc(msm_port->ipc_log_tx, "DMA Tx",
+ (char *)&xmit->buf[xmit->tail], 0, xmit_size);
+ msm_geni_serial_setup_tx(uport, xmit_size);
+ ret = geni_se_tx_dma_prep(msm_port->wrapper_dev, uport->membase,
+ &xmit->buf[xmit->tail], xmit_size, &msm_port->tx_dma);
+ if (!ret) {
+ msm_port->xmit_size = xmit_size;
+ } else {
+ geni_write_reg_nolog(0, uport->membase,
+ SE_UART_TX_TRANS_LEN);
+ geni_cancel_m_cmd(uport->membase);
+ if (!msm_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
+ M_CMD_CANCEL_EN, true)) {
+ geni_abort_m_cmd(uport->membase);
+ msm_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
+ M_CMD_ABORT_EN, true);
+ geni_write_reg_nolog(M_CMD_ABORT_EN, uport->membase,
+ SE_GENI_M_IRQ_CLEAR);
+ }
+ geni_write_reg_nolog(M_CMD_CANCEL_EN, uport->membase,
+ SE_GENI_M_IRQ_CLEAR);
+ IPC_LOG_MSG(msm_port->ipc_log_tx, "%s: DMA map failure %d\n",
+ __func__, ret);
+ msm_port->tx_dma = (dma_addr_t)NULL;
+ msm_port->xmit_size = 0;
+ }
+ return ret;
+}
+
static void msm_geni_serial_start_tx(struct uart_port *uport)
{
unsigned int geni_m_irq_en;
struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport);
unsigned int geni_status;
+ unsigned int geni_ios;
if (!uart_console(uport) && pm_runtime_status_suspended(uport->dev)) {
dev_err(uport->dev, "%s.Device is suspended.\n", __func__);
+ IPC_LOG_MSG(msm_port->ipc_log_misc,
+ "%s.Device is suspended.\n", __func__);
return;
}
- geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS);
- if (geni_status & M_GENI_CMD_ACTIVE)
- return;
+ if (msm_port->xfer_mode == FIFO_MODE) {
+ geni_status = geni_read_reg_nolog(uport->membase,
+ SE_GENI_STATUS);
+ if (geni_status & M_GENI_CMD_ACTIVE)
+ goto check_flow_ctrl;
- if (!msm_geni_serial_tx_empty(uport))
- return;
+ if (!msm_geni_serial_tx_empty(uport))
+ goto check_flow_ctrl;
- geni_m_irq_en = geni_read_reg_nolog(uport->membase, SE_GENI_M_IRQ_EN);
- geni_m_irq_en |= (M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN);
+ geni_m_irq_en = geni_read_reg_nolog(uport->membase,
+ SE_GENI_M_IRQ_EN);
+ geni_m_irq_en |= (M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN);
- geni_write_reg_nolog(msm_port->tx_wm, uport->membase,
+ geni_write_reg_nolog(msm_port->tx_wm, uport->membase,
SE_GENI_TX_WATERMARK_REG);
- geni_write_reg_nolog(geni_m_irq_en, uport->membase, SE_GENI_M_IRQ_EN);
- /* Geni command setup/irq enables should complete before returning.*/
- mb();
+ geni_write_reg_nolog(geni_m_irq_en, uport->membase,
+ SE_GENI_M_IRQ_EN);
+ /* Geni command setup should complete before returning.*/
+ mb();
+ } else if (msm_port->xfer_mode == SE_DMA) {
+ if (msm_port->tx_dma)
+ goto check_flow_ctrl;
+
+ msm_geni_serial_prep_dma_tx(uport);
+ }
+ IPC_LOG_MSG(msm_port->ipc_log_misc, "%s\n", __func__);
+ return;
+check_flow_ctrl:
+ geni_ios = geni_read_reg_nolog(uport->membase, SE_GENI_IOS);
+ if (!(geni_ios & IO2_DATA_IN))
+ IPC_LOG_MSG(msm_port->ipc_log_misc, "%s: ios: 0x%08x\n",
+ __func__, geni_ios);
}
static void msm_geni_serial_stop_tx(struct uart_port *uport)
@@ -719,12 +823,30 @@
unsigned int geni_status;
struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
- if (!uart_console(uport) && pm_runtime_status_suspended(uport->dev))
+ if (!uart_console(uport) && pm_runtime_status_suspended(uport->dev)) {
+ dev_err(uport->dev, "%s.Device is suspended.\n", __func__);
+ IPC_LOG_MSG(port->ipc_log_misc,
+ "%s.Device is suspended.\n", __func__);
return;
+ }
geni_m_irq_en = geni_read_reg_nolog(uport->membase, SE_GENI_M_IRQ_EN);
- geni_m_irq_en &= ~(M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN);
- geni_write_reg_nolog(0, uport->membase, SE_GENI_TX_WATERMARK_REG);
+ geni_m_irq_en &= ~M_CMD_DONE_EN;
+ if (port->xfer_mode == FIFO_MODE) {
+ geni_m_irq_en &= ~M_TX_FIFO_WATERMARK_EN;
+ geni_write_reg_nolog(0, uport->membase,
+ SE_GENI_TX_WATERMARK_REG);
+ } else if (port->xfer_mode == SE_DMA) {
+ if (port->tx_dma) {
+ geni_write_reg_nolog(1, uport->membase,
+ SE_DMA_TX_FSM_RST);
+ geni_se_tx_dma_unprep(port->wrapper_dev, port->tx_dma,
+ port->xmit_size);
+ port->tx_dma = (dma_addr_t)NULL;
+ }
+ }
+ port->xmit_size = 0;
+
geni_write_reg_nolog(geni_m_irq_en, uport->membase, SE_GENI_M_IRQ_EN);
geni_status = geni_read_reg_nolog(uport->membase,
@@ -754,26 +876,57 @@
unsigned int rxstale = DEFAULT_BITS_PER_CHAR * STALE_TIMEOUT;
unsigned int geni_status;
struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
+ int ret;
- if (!uart_console(uport) && pm_runtime_status_suspended(uport->dev))
+ if (!uart_console(uport) && pm_runtime_status_suspended(uport->dev)) {
+ dev_err(uport->dev, "%s.Device is suspended.\n", __func__);
+ IPC_LOG_MSG(port->ipc_log_misc,
+ "%s.Device is suspended.\n", __func__);
return;
+ }
geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS);
if (geni_status & S_GENI_CMD_ACTIVE)
msm_geni_serial_abort_rx(uport);
- geni_s_irq_en = geni_read_reg_nolog(uport->membase,
- SE_GENI_S_IRQ_EN);
- geni_m_irq_en = geni_read_reg_nolog(uport->membase,
- SE_GENI_M_IRQ_EN);
- geni_s_irq_en |= S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN;
- geni_m_irq_en |= M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN;
+
se_get_packing_config(8, 4, false, &cfg0, &cfg1);
geni_write_reg_nolog(cfg0, uport->membase, SE_GENI_RX_PACKING_CFG0);
geni_write_reg_nolog(cfg1, uport->membase, SE_GENI_RX_PACKING_CFG1);
geni_write_reg_nolog(rxstale, uport->membase, SE_UART_RX_STALE_CNT);
geni_setup_s_cmd(uport->membase, UART_START_READ, 0);
- geni_write_reg_nolog(geni_s_irq_en, uport->membase, SE_GENI_S_IRQ_EN);
- geni_write_reg_nolog(geni_m_irq_en, uport->membase, SE_GENI_M_IRQ_EN);
+
+ if (port->xfer_mode == FIFO_MODE) {
+ geni_s_irq_en = geni_read_reg_nolog(uport->membase,
+ SE_GENI_S_IRQ_EN);
+ geni_m_irq_en = geni_read_reg_nolog(uport->membase,
+ SE_GENI_M_IRQ_EN);
+
+ geni_s_irq_en |= S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN;
+ geni_m_irq_en |= M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN;
+
+ geni_write_reg_nolog(geni_s_irq_en, uport->membase,
+ SE_GENI_S_IRQ_EN);
+ geni_write_reg_nolog(geni_m_irq_en, uport->membase,
+ SE_GENI_M_IRQ_EN);
+ } else if (port->xfer_mode == SE_DMA) {
+ port->rx_buf = kzalloc(DMA_RX_BUF_SIZE, GFP_KERNEL);
+ if (!port->rx_buf) {
+ dev_err(uport->dev, "%s: kzalloc failed\n",
+ __func__);
+ msm_geni_serial_abort_rx(uport);
+ return;
+ }
+
+ ret = geni_se_rx_dma_prep(port->wrapper_dev, uport->membase,
+ port->rx_buf, DMA_RX_BUF_SIZE, &port->rx_dma);
+ if (ret) {
+ dev_err(uport->dev, "%s: RX Prep dma failed %d\n",
+ __func__, ret);
+ kfree(port->rx_buf);
+ msm_geni_serial_abort_rx(uport);
+ return;
+ }
+ }
/*
* Ensure the writes to the secondary sequencer and interrupt enables
* go through.
@@ -787,25 +940,42 @@
unsigned int geni_s_irq_en;
unsigned int geni_m_irq_en;
unsigned int geni_status;
+ struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
- if (!uart_console(uport) && pm_runtime_status_suspended(uport->dev))
+ if (!uart_console(uport) && pm_runtime_status_suspended(uport->dev)) {
+ dev_err(uport->dev, "%s.Device is suspended.\n", __func__);
+ IPC_LOG_MSG(port->ipc_log_misc,
+ "%s.Device is suspended.\n", __func__);
return;
+ }
- geni_s_irq_en = geni_read_reg_nolog(uport->membase,
- SE_GENI_S_IRQ_EN);
- geni_m_irq_en = geni_read_reg_nolog(uport->membase,
- SE_GENI_M_IRQ_EN);
- geni_s_irq_en &= ~(S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN);
- geni_m_irq_en &= ~(M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN);
+ if (port->xfer_mode == FIFO_MODE) {
+ geni_s_irq_en = geni_read_reg_nolog(uport->membase,
+ SE_GENI_S_IRQ_EN);
+ geni_m_irq_en = geni_read_reg_nolog(uport->membase,
+ SE_GENI_M_IRQ_EN);
+ geni_s_irq_en &= ~(S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN);
+ geni_m_irq_en &= ~(M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN);
- geni_write_reg_nolog(geni_s_irq_en, uport->membase, SE_GENI_S_IRQ_EN);
- geni_write_reg_nolog(geni_m_irq_en, uport->membase, SE_GENI_M_IRQ_EN);
+ geni_write_reg_nolog(geni_s_irq_en, uport->membase,
+ SE_GENI_S_IRQ_EN);
+ geni_write_reg_nolog(geni_m_irq_en, uport->membase,
+ SE_GENI_M_IRQ_EN);
+ } else if (port->xfer_mode == SE_DMA && port->rx_dma) {
+ geni_write_reg_nolog(1, uport->membase, SE_DMA_RX_FSM_RST);
+ geni_se_rx_dma_unprep(port->wrapper_dev, port->rx_dma,
+ DMA_RX_BUF_SIZE);
+ kfree(port->rx_buf);
+ port->rx_buf = NULL;
+ port->rx_dma = (dma_addr_t)NULL;
+ }
geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS);
/* Possible stop rx is called multiple times. */
if (!(geni_status & S_GENI_CMD_ACTIVE))
return;
msm_geni_serial_abort_rx(uport);
+ IPC_LOG_MSG(port->ipc_log_misc, "%s\n", __func__);
}
static int handle_rx_hs(struct uart_port *uport,
@@ -878,6 +1048,8 @@
(uart_console(uport) ? 1 : (msm_port->tx_fifo_width >> 3));
unsigned int geni_m_irq_en;
+ xmit->tail = (xmit->tail + msm_port->xmit_size) & (UART_XMIT_SIZE - 1);
+ msm_port->xmit_size = 0;
tx_fifo_status = geni_read_reg_nolog(uport->membase,
SE_GENI_TX_FIFO_STATUS);
if (uart_circ_empty(xmit) && !tx_fifo_status) {
@@ -914,15 +1086,16 @@
while (i < xmit_size) {
unsigned int tx_bytes;
unsigned int buf = 0;
+ int temp_tail;
int c;
tx_bytes = ((bytes_remaining < fifo_width_bytes) ?
bytes_remaining : fifo_width_bytes);
+ temp_tail = (xmit->tail + i) & (UART_XMIT_SIZE - 1);
for (c = 0; c < tx_bytes ; c++)
- buf |= (xmit->buf[xmit->tail + c] << (c * 8));
+ buf |= (xmit->buf[temp_tail + c] << (c * 8));
geni_write_reg_nolog(buf, uport->membase, SE_GENI_TX_FIFOn);
- xmit->tail = (xmit->tail + tx_bytes) & (UART_XMIT_SIZE - 1);
i += tx_bytes;
uport->icount.tx += tx_bytes;
bytes_remaining -= tx_bytes;
@@ -930,48 +1103,137 @@
wmb();
}
msm_geni_serial_poll_cancel_tx(uport);
+ if (uart_console(uport))
+ xmit->tail = (xmit->tail + xmit_size) & (UART_XMIT_SIZE - 1);
+ else
+ msm_port->xmit_size = xmit_size;
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(uport);
exit_handle_tx:
return ret;
}
+static int msm_geni_serial_handle_dma_rx(struct uart_port *uport)
+{
+ struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport);
+ unsigned int rx_bytes = 0;
+ struct tty_port *tport;
+ int ret;
+ unsigned int geni_status;
+
+ geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS);
+ /* Possible stop rx is called */
+ if (!(geni_status & S_GENI_CMD_ACTIVE))
+ return 0;
+
+ geni_se_rx_dma_unprep(msm_port->wrapper_dev, msm_port->rx_dma,
+ DMA_RX_BUF_SIZE);
+ rx_bytes = geni_read_reg_nolog(uport->membase, SE_DMA_RX_LEN_IN);
+ if (unlikely(!msm_port->rx_buf || !rx_bytes)) {
+ IPC_LOG_MSG(msm_port->ipc_log_rx, "%s: Rx_buf %pK Size %d\n",
+ __func__, msm_port->rx_buf, rx_bytes);
+ return 0;
+ }
+
+ tport = &uport->state->port;
+ ret = tty_insert_flip_string(tport, (unsigned char *)(msm_port->rx_buf),
+ rx_bytes);
+ if (ret != rx_bytes) {
+ dev_err(uport->dev, "%s: ret %d rx_bytes %d\n", __func__,
+ ret, rx_bytes);
+ WARN_ON(1);
+ }
+ uport->icount.rx += ret;
+ tty_flip_buffer_push(tport);
+ dump_ipc(msm_port->ipc_log_rx, "DMA Rx", (char *)msm_port->rx_buf, 0,
+ rx_bytes);
+ ret = geni_se_rx_dma_prep(msm_port->wrapper_dev, uport->membase,
+ msm_port->rx_buf, DMA_RX_BUF_SIZE, &msm_port->rx_dma);
+ if (ret)
+ IPC_LOG_MSG(msm_port->ipc_log_rx, "%s: %d\n", __func__, ret);
+ return ret;
+}
+
+static int msm_geni_serial_handle_dma_tx(struct uart_port *uport)
+{
+ struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport);
+ struct circ_buf *xmit = &uport->state->xmit;
+
+ xmit->tail = (xmit->tail + msm_port->xmit_size) & (UART_XMIT_SIZE - 1);
+ geni_se_tx_dma_unprep(msm_port->wrapper_dev, msm_port->tx_dma,
+ msm_port->xmit_size);
+ uport->icount.tx += msm_port->xmit_size;
+ msm_port->tx_dma = (dma_addr_t)NULL;
+ msm_port->xmit_size = 0;
+
+ if (!uart_circ_empty(xmit))
+ msm_geni_serial_prep_dma_tx(uport);
+ else
+ uart_write_wakeup(uport);
+ return 0;
+}
+
static irqreturn_t msm_geni_serial_isr(int isr, void *dev)
{
unsigned int m_irq_status;
unsigned int s_irq_status;
+ unsigned int dma;
+ unsigned int dma_tx_status;
+ unsigned int dma_rx_status;
struct uart_port *uport = dev;
unsigned long flags;
unsigned int m_irq_en;
+ struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport);
spin_lock_irqsave(&uport->lock, flags);
if (uart_console(uport) && uport->suspended)
goto exit_geni_serial_isr;
- if (!uart_console(uport) && pm_runtime_status_suspended(uport->dev))
+ if (!uart_console(uport) && pm_runtime_status_suspended(uport->dev)) {
+ dev_err(uport->dev, "%s.Device is suspended.\n", __func__);
+ IPC_LOG_MSG(msm_port->ipc_log_misc,
+ "%s.Device is suspended.\n", __func__);
goto exit_geni_serial_isr;
+ }
m_irq_status = geni_read_reg_nolog(uport->membase,
SE_GENI_M_IRQ_STATUS);
s_irq_status = geni_read_reg_nolog(uport->membase,
SE_GENI_S_IRQ_STATUS);
- geni_write_reg_nolog(m_irq_status, uport->membase,
- SE_GENI_M_IRQ_CLEAR);
- geni_write_reg_nolog(s_irq_status, uport->membase,
- SE_GENI_S_IRQ_CLEAR);
m_irq_en = geni_read_reg_nolog(uport->membase, SE_GENI_M_IRQ_EN);
+ dma = geni_read_reg_nolog(uport->membase, SE_GENI_DMA_MODE_EN);
+ dma_tx_status = geni_read_reg_nolog(uport->membase, SE_DMA_TX_IRQ_STAT);
+ dma_rx_status = geni_read_reg_nolog(uport->membase, SE_DMA_RX_IRQ_STAT);
+
+ geni_write_reg_nolog(m_irq_status, uport->membase, SE_GENI_M_IRQ_CLEAR);
+ geni_write_reg_nolog(s_irq_status, uport->membase, SE_GENI_S_IRQ_CLEAR);
if ((m_irq_status & M_ILLEGAL_CMD_EN)) {
WARN_ON(1);
goto exit_geni_serial_isr;
}
- if ((s_irq_status & S_RX_FIFO_WATERMARK_EN) ||
- (s_irq_status & S_RX_FIFO_LAST_EN)) {
- msm_geni_serial_handle_rx(uport);
- }
+ if (!dma) {
+ if ((s_irq_status & S_RX_FIFO_WATERMARK_EN) ||
+ (s_irq_status & S_RX_FIFO_LAST_EN))
+ msm_geni_serial_handle_rx(uport);
- if ((m_irq_status & m_irq_en) &
- (M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN))
- msm_geni_serial_handle_tx(uport);
+ if ((m_irq_status & m_irq_en) &
+ (M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN))
+ msm_geni_serial_handle_tx(uport);
+ } else {
+ if (dma_tx_status) {
+ geni_write_reg_nolog(dma_tx_status, uport->membase,
+ SE_DMA_TX_IRQ_CLR);
+ if (dma_tx_status & TX_DMA_DONE)
+ msm_geni_serial_handle_dma_tx(uport);
+ }
+
+ if (dma_rx_status) {
+ geni_write_reg_nolog(dma_rx_status, uport->membase,
+ SE_DMA_RX_IRQ_CLR);
+ if (dma_rx_status & RX_DMA_DONE)
+ msm_geni_serial_handle_dma_rx(uport);
+ }
+ }
exit_geni_serial_isr:
spin_unlock_irqrestore(&uport->lock, flags);
@@ -986,16 +1248,19 @@
unsigned long flags;
spin_lock_irqsave(&uport->lock, flags);
- if (port->wakeup_byte) {
+ IPC_LOG_MSG(port->ipc_log_rx, "%s: Edge-Count %d\n", __func__,
+ port->edge_count);
+ if (port->wakeup_byte && (port->edge_count == 2)) {
tty = uport->state->port.tty;
tty_insert_flip_char(tty->port, port->wakeup_byte, TTY_NORMAL);
IPC_LOG_MSG(port->ipc_log_rx, "%s: Inject 0x%x\n",
__func__, port->wakeup_byte);
+ port->edge_count = 0;
tty_flip_buffer_push(tty->port);
+ __pm_wakeup_event(&port->geni_wake, WAKEBYTE_TIMEOUT_MSEC);
+ } else if (port->edge_count < 2) {
+ port->edge_count++;
}
- __pm_wakeup_event(&port->geni_wake, WAKEBYTE_TIMEOUT_MSEC);
- IPC_LOG_MSG(port->ipc_log_misc, "%s:Holding Wake Lock for %d ms\n",
- __func__, WAKEBYTE_TIMEOUT_MSEC);
spin_unlock_irqrestore(&uport->lock, flags);
return IRQ_HANDLED;
}
@@ -1052,25 +1317,29 @@
unsigned long flags;
/* Stop the console before stopping the current tx */
- if (uart_console(uport))
+ if (uart_console(uport)) {
console_stop(uport->cons);
+ } else {
+ msm_geni_serial_power_on(uport);
+ wait_for_transfers_inflight(uport);
+ }
+ disable_irq(uport->irq);
+ free_irq(uport->irq, msm_port);
spin_lock_irqsave(&uport->lock, flags);
msm_geni_serial_stop_tx(uport);
msm_geni_serial_stop_rx(uport);
spin_unlock_irqrestore(&uport->lock, flags);
- disable_irq(uport->irq);
- free_irq(uport->irq, msm_port);
if (uart_console(uport)) {
se_geni_resources_off(&msm_port->serial_rsc);
} else {
+ msm_geni_serial_power_off(uport);
if (msm_port->wakeup_irq > 0) {
+ irq_set_irq_wake(msm_port->wakeup_irq, 0);
disable_irq(msm_port->wakeup_irq);
free_irq(msm_port->wakeup_irq, msm_port);
}
- __pm_relax(&msm_port->geni_wake);
- msm_geni_serial_power_off(uport);
}
IPC_LOG_MSG(msm_port->ipc_log_misc, "%s\n", __func__);
}
@@ -1085,7 +1354,7 @@
set_rfr_wm(msm_port);
if (!uart_console(uport)) {
/* For now only assume FIFO mode. */
- msm_port->xfer_mode = FIFO_MODE;
+ msm_port->xfer_mode = SE_DMA;
se_get_packing_config(8, 4, false, &cfg0, &cfg1);
geni_write_reg_nolog(cfg0, uport->membase,
SE_GENI_TX_PACKING_CFG0);
@@ -1183,8 +1452,11 @@
if (likely(!uart_console(uport))) {
ret = msm_geni_serial_power_on(&msm_port->uport);
- if (ret)
- goto exit_startup;
+ if (ret) {
+ dev_err(uport->dev, "%s:Failed to power on %d\n",
+ __func__, ret);
+ return ret;
+ }
}
if (unlikely(get_se_proto(uport->membase) != UART)) {
@@ -1217,8 +1489,7 @@
}
if (msm_port->wakeup_irq > 0) {
- ret = request_threaded_irq(msm_port->wakeup_irq, NULL,
- msm_geni_wakeup_isr,
+ ret = request_irq(msm_port->wakeup_irq, msm_geni_wakeup_isr,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
"hs_uart_wakeup", uport);
if (unlikely(ret)) {
@@ -1227,9 +1498,17 @@
goto exit_startup;
}
disable_irq(msm_port->wakeup_irq);
+ ret = irq_set_irq_wake(msm_port->wakeup_irq, 1);
+ if (unlikely(ret)) {
+ dev_err(uport->dev, "%s:Failed to set IRQ wake:%d\n",
+ __func__, ret);
+ goto exit_startup;
+ }
}
IPC_LOG_MSG(msm_port->ipc_log_misc, "%s\n", __func__);
exit_startup:
+ if (likely(!uart_console(uport)))
+ msm_geni_serial_power_off(&msm_port->uport);
return ret;
}
@@ -1316,6 +1595,11 @@
struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
unsigned long clk_rate;
+ if (!uart_console(uport) && pm_runtime_status_suspended(uport->dev)) {
+ IPC_LOG_MSG(port->ipc_log_pwr,
+ "%s Device suspended,vote clocks on.\n", __func__);
+ return;
+ }
/* baud rate */
baud = uart_get_baud_rate(uport, termios, old, 300, 4000000);
port->cur_baud = baud;
@@ -1412,15 +1696,81 @@
{
unsigned int tx_fifo_status;
unsigned int is_tx_empty = 1;
+ struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
- tx_fifo_status = geni_read_reg_nolog(uport->membase,
- SE_GENI_TX_FIFO_STATUS);
+ if (!uart_console(uport) && pm_runtime_status_suspended(uport->dev)) {
+ IPC_LOG_MSG(port->ipc_log_pwr,
+ "%s Device suspended,vote clocks on.\n", __func__);
+ return 1;
+ }
+
+ if (port->xfer_mode == SE_DMA)
+ tx_fifo_status = port->tx_dma ? 1 : 0;
+ else
+ tx_fifo_status = geni_read_reg_nolog(uport->membase,
+ SE_GENI_TX_FIFO_STATUS);
if (tx_fifo_status)
is_tx_empty = 0;
return is_tx_empty;
}
+static ssize_t msm_geni_serial_xfer_mode_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct msm_geni_serial_port *port = platform_get_drvdata(pdev);
+ ssize_t ret = 0;
+
+ if (port->xfer_mode == FIFO_MODE)
+ ret = snprintf(buf, sizeof("FIFO\n"), "FIFO\n");
+ else if (port->xfer_mode == SE_DMA)
+ ret = snprintf(buf, sizeof("SE_DMA\n"), "SE_DMA\n");
+
+ return ret;
+}
+
+static ssize_t msm_geni_serial_xfer_mode_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t size)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct msm_geni_serial_port *port = platform_get_drvdata(pdev);
+ struct uart_port *uport = &port->uport;
+ int xfer_mode = port->xfer_mode;
+ unsigned long flags;
+
+ if (uart_console(uport))
+ return -EOPNOTSUPP;
+
+ if (strnstr(buf, "FIFO", strlen("FIFO"))) {
+ xfer_mode = FIFO_MODE;
+ } else if (strnstr(buf, "SE_DMA", strlen("SE_DMA"))) {
+ xfer_mode = SE_DMA;
+ } else {
+ dev_err(dev, "%s: Invalid input %s\n", __func__, buf);
+ return -EINVAL;
+ }
+
+ if (xfer_mode == port->xfer_mode)
+ return size;
+
+ msm_geni_serial_power_on(uport);
+ spin_lock_irqsave(&uport->lock, flags);
+ msm_geni_serial_stop_tx(uport);
+ msm_geni_serial_stop_rx(uport);
+ port->xfer_mode = xfer_mode;
+ geni_se_select_mode(uport->membase, port->xfer_mode);
+ spin_unlock_irqrestore(&uport->lock, flags);
+ msm_geni_serial_start_rx(uport);
+ msm_geni_serial_power_off(uport);
+
+ return size;
+}
+
+static DEVICE_ATTR(xfer_mode, 0644, msm_geni_serial_xfer_mode_show,
+ msm_geni_serial_xfer_mode_store);
+
#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL)
static int __init msm_geni_console_setup(struct console *co, char *options)
{
@@ -1671,6 +2021,7 @@
bool is_console = false;
struct platform_device *wrapper_pdev;
struct device_node *wrapper_ph_node;
+ u32 wake_char = 0;
id = of_match_device(msm_geni_device_tbl, &pdev->dev);
if (id) {
@@ -1733,9 +2084,14 @@
if (ret)
goto exit_geni_serial_probe;
- if (of_property_read_u8(pdev->dev.of_node, "qcom,wakeup-byte",
- &dev_port->wakeup_byte))
- dev_info(&pdev->dev, "No Wakeup byte specified\n");
+ if (of_property_read_u32(pdev->dev.of_node, "qcom,wakeup-byte",
+ &wake_char)) {
+ dev_dbg(&pdev->dev, "No Wakeup byte specified\n");
+ } else {
+ dev_port->wakeup_byte = (u8)wake_char;
+ dev_info(&pdev->dev, "Wakeup byte 0x%x\n",
+ dev_port->wakeup_byte);
+ }
dev_port->serial_rsc.se_clk = devm_clk_get(&pdev->dev, "se-clk");
if (IS_ERR(dev_port->serial_rsc.se_clk)) {
@@ -1830,6 +2186,7 @@
dev_info(&pdev->dev, "Serial port%d added.FifoSize %d is_console%d\n",
line, uport->fifosize, is_console);
device_create_file(uport->dev, &dev_attr_loopback);
+ device_create_file(uport->dev, &dev_attr_xfer_mode);
msm_geni_serial_debug_init(uport);
dev_port->port_setup = false;
return uart_add_one_port(drv, uport);
@@ -1857,14 +2214,28 @@
struct msm_geni_serial_port *port = platform_get_drvdata(pdev);
int ret = 0;
+ wait_for_transfers_inflight(&port->uport);
ret = se_geni_resources_off(&port->serial_rsc);
if (ret) {
dev_err(dev, "%s: Error ret %d\n", __func__, ret);
goto exit_runtime_suspend;
}
- if (port->wakeup_irq > 0)
+ disable_irq(port->uport.irq);
+ if (port->wakeup_irq > 0) {
+ struct se_geni_rsc *rsc = &port->serial_rsc;
+
+ port->edge_count = 0;
+ ret = pinctrl_select_state(rsc->geni_pinctrl,
+ rsc->geni_gpio_active);
+ if (ret) {
+ dev_err(dev, "%s: Error %d pinctrl_select_state\n",
+ __func__, ret);
+ goto exit_runtime_suspend;
+ }
enable_irq(port->wakeup_irq);
+ }
IPC_LOG_MSG(port->ipc_log_pwr, "%s:\n", __func__);
+ __pm_relax(&port->geni_wake);
exit_runtime_suspend:
return ret;
}
@@ -1875,13 +2246,21 @@
struct msm_geni_serial_port *port = platform_get_drvdata(pdev);
int ret = 0;
+ /*
+ * Do an unconditional relax followed by a stay awake in case the
+ * wake source is activated by the wakeup isr.
+ */
+ __pm_relax(&port->geni_wake);
+ __pm_stay_awake(&port->geni_wake);
if (port->wakeup_irq > 0)
disable_irq(port->wakeup_irq);
ret = se_geni_resources_on(&port->serial_rsc);
if (ret) {
dev_err(dev, "%s: Error ret %d\n", __func__, ret);
+ __pm_relax(&port->geni_wake);
goto exit_runtime_resume;
}
+ enable_irq(port->uport.irq);
IPC_LOG_MSG(port->ipc_log_pwr, "%s:\n", __func__);
exit_runtime_resume:
return ret;
@@ -1897,10 +2276,20 @@
uart_suspend_port((struct uart_driver *)uport->private_data,
uport);
} else {
+ struct uart_state *state = uport->state;
+ struct tty_port *tty_port = &state->port;
+
+ mutex_lock(&tty_port->mutex);
if (!pm_runtime_status_suspended(dev)) {
- dev_info(dev, "%s: Is still active\n", __func__);
+ dev_err(dev, "%s:Active userspace vote; ioctl_cnt %d\n",
+ __func__, port->ioctl_count);
+ IPC_LOG_MSG(port->ipc_log_pwr,
+ "%s:Active userspace vote; ioctl_cnt %d\n",
+ __func__, port->ioctl_count);
+ mutex_unlock(&tty_port->mutex);
return -EBUSY;
}
+ mutex_unlock(&tty_port->mutex);
}
return 0;
}
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
index 701c085..94c3718 100644
--- a/drivers/tty/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -55,10 +55,11 @@
static int __read_mostly sysrq_enabled = CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE;
static bool __read_mostly sysrq_always_enabled;
-static bool sysrq_on(void)
+bool sysrq_on(void)
{
return sysrq_enabled || sysrq_always_enabled;
}
+EXPORT_SYMBOL(sysrq_on);
/*
* A value of 1 means 'all', other nonzero values are an op mask:
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index 8c3bf3d..ce2c3c6 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -2711,13 +2711,13 @@
* related to the kernel should not use this.
*/
data = vt_get_shift_state();
- ret = __put_user(data, p);
+ ret = put_user(data, p);
break;
case TIOCL_GETMOUSEREPORTING:
console_lock(); /* May be overkill */
data = mouse_reporting();
console_unlock();
- ret = __put_user(data, p);
+ ret = put_user(data, p);
break;
case TIOCL_SETVESABLANK:
console_lock();
@@ -2726,7 +2726,7 @@
break;
case TIOCL_GETKMSGREDIRECT:
data = vt_get_kmsg_redirect();
- ret = __put_user(data, p);
+ ret = put_user(data, p);
break;
case TIOCL_SETKMSGREDIRECT:
if (!capable(CAP_SYS_ADMIN)) {
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index a876d47..f16491c 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -1770,6 +1770,9 @@
{ USB_DEVICE(0x1576, 0x03b1), /* Maretron USB100 */
.driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */
},
+ { USB_DEVICE(0xfff0, 0x0100), /* DATECS FP-2000 */
+ .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */
+ },
{ USB_DEVICE(0x2912, 0x0001), /* ATOL FPrint */
.driver_info = CLEAR_HALT_CONDITIONS,
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index eef716b..3fd2b54 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -981,6 +981,15 @@
case USB_PTM_CAP_TYPE:
dev->bos->ptm_cap =
(struct usb_ptm_cap_descriptor *)buffer;
+ break;
+ case USB_CAP_TYPE_CONFIG_SUMMARY:
+ /* one such desc per configuration */
+ if (!dev->bos->num_config_summary_desc)
+ dev->bos->config_summary =
+ (struct usb_config_summary_descriptor *)buffer;
+
+ dev->bos->num_config_summary_desc++;
+ break;
default:
break;
}
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index 358ca8d..0f10ff2 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -19,6 +19,8 @@
#include <linux/usb.h>
#include <linux/usb/hcd.h>
+#include <linux/usb/audio.h>
+#include <linux/usb/audio-v3.h>
#include "usb.h"
static inline const char *plural(int n)
@@ -40,6 +42,34 @@
&& desc->bInterfaceProtocol == 1;
}
+static int usb_audio_max_rev_config(struct usb_host_bos *bos)
+{
+ int desc_cnt, func_cnt, numfunc;
+ int num_cfg_desc;
+ struct usb_config_summary_descriptor *conf_summary;
+
+ if (!bos || !bos->config_summary)
+ goto done;
+
+ conf_summary = bos->config_summary;
+ num_cfg_desc = bos->num_config_summary_desc;
+
+ for (desc_cnt = 0; desc_cnt < num_cfg_desc; desc_cnt++) {
+ numfunc = conf_summary->bNumFunctions;
+ for (func_cnt = 0; func_cnt < numfunc; func_cnt++) {
+ /* honor device preferred config */
+ if (conf_summary->cs_info[func_cnt].bClass ==
+ USB_CLASS_AUDIO &&
+ conf_summary->cs_info[func_cnt].bSubClass !=
+ FULL_ADC_3_0)
+ return conf_summary->bConfigurationValue;
+ }
+ }
+
+done:
+ return -EINVAL;
+}
+
int usb_choose_configuration(struct usb_device *udev)
{
int i;
@@ -130,7 +160,6 @@
best = c;
break;
}
-
/* If all the remaining configs are vendor-specific,
* choose the first one. */
else if (!best)
@@ -143,7 +172,10 @@
insufficient_power, plural(insufficient_power));
if (best) {
- i = best->desc.bConfigurationValue;
+ /* choose usb audio class preferred config if available */
+ i = usb_audio_max_rev_config(udev->bos);
+ if (i < 0)
+ i = best->desc.bConfigurationValue;
dev_dbg(&udev->dev,
"configuration #%d chosen from %d choice%s\n",
i, num_configs, plural(num_configs));
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 3e9d233..aca5d97 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -55,6 +55,8 @@
#include "debug.h"
#include "xhci.h"
+#define SDP_CONNETION_CHECK_TIME 10000 /* in ms */
+
/* time out to wait for USB cable status notification (in ms)*/
#define SM_INIT_TIMEOUT 30000
@@ -250,6 +252,7 @@
struct notifier_block vbus_nb;
struct notifier_block id_nb;
struct notifier_block eud_event_nb;
+ struct notifier_block host_restart_nb;
struct notifier_block host_nb;
@@ -262,6 +265,7 @@
int pm_qos_latency;
struct pm_qos_request pm_qos_req_dma;
struct delayed_work perf_vote_work;
+ struct delayed_work sdp_check;
};
#define USB_HSPHY_3P3_VOL_MIN 3050000 /* uV */
@@ -282,6 +286,8 @@
static void dwc3_pwr_event_handler(struct dwc3_msm *mdwc);
static int dwc3_msm_gadget_vbus_draw(struct dwc3_msm *mdwc, unsigned int mA);
static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned int event);
+static int dwc3_restart_usb_host_mode(struct notifier_block *nb,
+ unsigned long event, void *ptr);
static inline bool is_valid_usb_speed(struct dwc3 *dwc, int speed)
{
@@ -2138,7 +2144,6 @@
static int dwc3_msm_suspend(struct dwc3_msm *mdwc)
{
int ret;
- bool can_suspend_ssphy;
struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
struct dwc3_event_buffer *evt;
struct usb_irq *uirq;
@@ -2195,10 +2200,6 @@
if (ret)
return ret;
- /* Initialize variables here */
- can_suspend_ssphy = !(mdwc->in_host_mode &&
- dwc3_msm_is_host_superspeed(mdwc));
-
/* Disable core irq */
if (dwc->irq)
disable_irq(dwc->irq);
@@ -2214,7 +2215,7 @@
usb_phy_set_suspend(mdwc->hs_phy, 1);
/* Suspend SS PHY */
- if (dwc->maximum_speed == USB_SPEED_SUPER && can_suspend_ssphy) {
+ if (dwc->maximum_speed == USB_SPEED_SUPER) {
/* indicate phy about SS mode */
if (dwc3_msm_is_superspeed(mdwc))
mdwc->ss_phy->flags |= DEVICE_IN_SS_MODE;
@@ -2818,6 +2819,25 @@
return NOTIFY_DONE;
}
+
+static void check_for_sdp_connection(struct work_struct *w)
+{
+ struct dwc3_msm *mdwc =
+ container_of(w, struct dwc3_msm, sdp_check.work);
+ struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
+
+ if (!mdwc->vbus_active)
+ return;
+
+ /* floating D+/D- lines detected */
+ if (dwc->gadget.state < USB_STATE_DEFAULT &&
+ dwc3_gadget_get_link_state(dwc) != DWC3_LINK_STATE_CMPLY) {
+ mdwc->vbus_active = 0;
+ dbg_event(0xFF, "Q RW SPD CHK", mdwc->vbus_active);
+ queue_work(mdwc->dwc3_wq, &mdwc->resume_work);
+ }
+}
+
static int dwc3_msm_vbus_notifier(struct notifier_block *nb,
unsigned long event, void *ptr)
{
@@ -2904,35 +2924,49 @@
if (!IS_ERR(edev)) {
mdwc->extcon_id = edev;
mdwc->id_nb.notifier_call = dwc3_msm_id_notifier;
+ mdwc->host_restart_nb.notifier_call =
+ dwc3_restart_usb_host_mode;
ret = extcon_register_notifier(edev, EXTCON_USB_HOST,
&mdwc->id_nb);
if (ret < 0) {
dev_err(mdwc->dev, "failed to register notifier for USB-HOST\n");
goto err;
}
+
+ ret = extcon_register_blocking_notifier(edev, EXTCON_USB_HOST,
+ &mdwc->host_restart_nb);
+ if (ret < 0) {
+ dev_err(mdwc->dev, "failed to register blocking notifier\n");
+ goto err1;
+ }
}
+ edev = NULL;
/* Use third phandle (optional) for EUD based detach/attach events */
if (of_count_phandle_with_args(node, "extcon", NULL) > 2) {
edev = extcon_get_edev_by_phandle(mdwc->dev, 2);
if (IS_ERR(edev) && PTR_ERR(edev) != -ENODEV) {
ret = PTR_ERR(edev);
- goto err;
+ goto err1;
}
}
- if (!IS_ERR(edev)) {
+ if (!IS_ERR_OR_NULL(edev)) {
mdwc->extcon_eud = edev;
mdwc->eud_event_nb.notifier_call = dwc3_msm_eud_notifier;
ret = extcon_register_notifier(edev, EXTCON_USB,
&mdwc->eud_event_nb);
if (ret < 0) {
dev_err(mdwc->dev, "failed to register notifier for EUD-USB\n");
- goto err1;
+ goto err2;
}
}
return 0;
+err2:
+ if (mdwc->extcon_id)
+ extcon_unregister_blocking_notifier(mdwc->extcon_id,
+ EXTCON_USB_HOST, &mdwc->host_restart_nb);
err1:
if (mdwc->extcon_id)
extcon_unregister_notifier(mdwc->extcon_id, EXTCON_USB_HOST,
@@ -3103,6 +3137,7 @@
INIT_WORK(&mdwc->vbus_draw_work, dwc3_msm_vbus_draw_work);
INIT_DELAYED_WORK(&mdwc->sm_work, dwc3_otg_sm_work);
INIT_DELAYED_WORK(&mdwc->perf_vote_work, msm_dwc3_perf_vote_work);
+ INIT_DELAYED_WORK(&mdwc->sdp_check, check_for_sdp_connection);
mdwc->dwc3_wq = alloc_ordered_workqueue("dwc3_wq", 0);
if (!mdwc->dwc3_wq) {
@@ -3858,34 +3893,83 @@
return 0;
}
-static int dwc3_msm_gadget_vbus_draw(struct dwc3_msm *mdwc, unsigned int mA)
+/* speed: 0 - USB_SPEED_HIGH, 1 - USB_SPEED_SUPER */
+static int dwc3_restart_usb_host_mode(struct notifier_block *nb,
+ unsigned long event, void *ptr)
+{
+ struct dwc3_msm *mdwc;
+ struct dwc3 *dwc;
+ int ret = -EINVAL, usb_speed;
+
+ mdwc = container_of(nb, struct dwc3_msm, host_restart_nb);
+ dwc = platform_get_drvdata(mdwc->dwc3);
+
+ usb_speed = (event == 0 ? USB_SPEED_HIGH : USB_SPEED_SUPER);
+ if (dwc->maximum_speed == usb_speed)
+ goto err;
+
+ dbg_event(0xFF, "stop_host_mode", dwc->maximum_speed);
+ ret = dwc3_otg_start_host(mdwc, 0);
+ if (ret)
+ goto err;
+
+ /*
+ * stop host mode functionality performs autosuspend with mdwc
+ * device, and it may take sometime to call PM runtime suspend.
+ * Hence call pm_runtime_suspend() API to invoke PM runtime
+ * suspend immediately to put USB controller and PHYs into suspend.
+ */
+ ret = pm_runtime_suspend(mdwc->dev);
+ dbg_event(0xFF, "pm_runtime_sus", ret);
+
+ dwc->maximum_speed = usb_speed;
+ mdwc->otg_state = OTG_STATE_B_IDLE;
+ schedule_delayed_work(&mdwc->sm_work, 0);
+ dbg_event(0xFF, "complete_host_change", dwc->maximum_speed);
+err:
+ return ret;
+}
+
+static int get_psy_type(struct dwc3_msm *mdwc)
{
union power_supply_propval pval = {0};
- int ret;
if (mdwc->charging_disabled)
- return 0;
-
- if (mdwc->max_power == mA)
- return 0;
+ return -EINVAL;
if (!mdwc->usb_psy) {
mdwc->usb_psy = power_supply_get_by_name("usb");
if (!mdwc->usb_psy) {
- dev_warn(mdwc->dev, "Could not get usb power_supply\n");
+ dev_err(mdwc->dev, "Could not get usb psy\n");
return -ENODEV;
}
}
- power_supply_get_property(mdwc->usb_psy,
- POWER_SUPPLY_PROP_REAL_TYPE, &pval);
- if (pval.intval != POWER_SUPPLY_TYPE_USB)
+ power_supply_get_property(mdwc->usb_psy, POWER_SUPPLY_PROP_REAL_TYPE,
+ &pval);
+
+ return pval.intval;
+}
+
+static int dwc3_msm_gadget_vbus_draw(struct dwc3_msm *mdwc, unsigned int mA)
+{
+ union power_supply_propval pval = {0};
+ int ret, psy_type;
+
+ if (mdwc->max_power == mA)
return 0;
- dev_info(mdwc->dev, "Avail curr from USB = %u\n", mA);
+ psy_type = get_psy_type(mdwc);
+ if (psy_type == POWER_SUPPLY_TYPE_USB) {
+ dev_info(mdwc->dev, "Avail curr from USB = %u\n", mA);
+ /* Set max current limit in uA */
+ pval.intval = 1000 * mA;
+ } else if (psy_type == POWER_SUPPLY_TYPE_USB_FLOAT) {
+ pval.intval = -ETIMEDOUT;
+ } else {
+ return 0;
+ }
- /* Set max current limit in uA */
- pval.intval = 1000 * mA;
ret = power_supply_set_property(mdwc->usb_psy,
POWER_SUPPLY_PROP_CURRENT_MAX, &pval);
if (ret) {
@@ -3956,6 +4040,10 @@
work = 1;
} else if (test_bit(B_SESS_VLD, &mdwc->inputs)) {
dev_dbg(mdwc->dev, "b_sess_vld\n");
+ if (get_psy_type(mdwc) == POWER_SUPPLY_TYPE_USB_FLOAT)
+ queue_delayed_work(mdwc->dwc3_wq,
+ &mdwc->sdp_check,
+ msecs_to_jiffies(SDP_CONNETION_CHECK_TIME));
/*
* Increment pm usage count upon cable connect. Count
* is decremented in OTG_STATE_B_PERIPHERAL state on
@@ -3978,6 +4066,7 @@
!test_bit(ID, &mdwc->inputs)) {
dev_dbg(mdwc->dev, "!id || !bsv\n");
mdwc->otg_state = OTG_STATE_B_IDLE;
+ cancel_delayed_work_sync(&mdwc->sdp_check);
dwc3_otg_start_peripheral(mdwc, 0);
/*
* Decrement pm usage count upon cable disconnect
@@ -4010,6 +4099,7 @@
if (!test_bit(B_SESS_VLD, &mdwc->inputs)) {
dev_dbg(mdwc->dev, "BSUSP: !bsv\n");
mdwc->otg_state = OTG_STATE_B_IDLE;
+ cancel_delayed_work_sync(&mdwc->sdp_check);
dwc3_otg_start_peripheral(mdwc, 0);
} else if (!test_bit(B_SUSPEND, &mdwc->inputs)) {
dev_dbg(mdwc->dev, "BSUSP !susp\n");
diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c
index 5396557..f910990 100644
--- a/drivers/usb/gadget/configfs.c
+++ b/drivers/usb/gadget/configfs.c
@@ -138,21 +138,28 @@
struct list_head list;
};
+#define MAX_USB_STRING_LEN 126
+#define MAX_USB_STRING_WITH_NULL_LEN (MAX_USB_STRING_LEN+1)
+
static int usb_string_copy(const char *s, char **s_copy)
{
int ret;
char *str;
char *copy = *s_copy;
ret = strlen(s);
- if (ret > 126)
+ if (ret > MAX_USB_STRING_LEN)
return -EOVERFLOW;
- str = kstrdup(s, GFP_KERNEL);
- if (!str)
- return -ENOMEM;
+ if (copy) {
+ str = copy;
+ } else {
+ str = kmalloc(MAX_USB_STRING_WITH_NULL_LEN, GFP_KERNEL);
+ if (!str)
+ return -ENOMEM;
+ }
+ strncpy(str, s, MAX_USB_STRING_WITH_NULL_LEN);
if (str[ret - 1] == '\n')
str[ret - 1] = '\0';
- kfree(copy);
*s_copy = str;
return 0;
}
diff --git a/drivers/usb/gadget/function/f_audio_source.c b/drivers/usb/gadget/function/f_audio_source.c
index 51ab794..1590927 100644
--- a/drivers/usb/gadget/function/f_audio_source.c
+++ b/drivers/usb/gadget/function/f_audio_source.c
@@ -1029,8 +1029,14 @@
config_group_init_type_name(&fi_audio->func_inst.group, "",
&audio_source_func_type);
- snprintf(device_name, AUDIO_SOURCE_DEV_NAME_LENGTH,
+ if (!count) {
+ snprintf(device_name, AUDIO_SOURCE_DEV_NAME_LENGTH,
+ "f_audio_source");
+ count++;
+ } else {
+ snprintf(device_name, AUDIO_SOURCE_DEV_NAME_LENGTH,
"f_audio_source%d", count++);
+ }
dev = create_function_device(device_name);
diff --git a/drivers/usb/gadget/function/f_ccid.c b/drivers/usb/gadget/function/f_ccid.c
index 1801a6c..7817f1c 100644
--- a/drivers/usb/gadget/function/f_ccid.c
+++ b/drivers/usb/gadget/function/f_ccid.c
@@ -26,7 +26,7 @@
#include "f_ccid.h"
#define BULK_IN_BUFFER_SIZE sizeof(struct ccid_bulk_in_header)
-#define BULK_OUT_BUFFER_SIZE sizeof(struct ccid_bulk_out_header)
+#define BULK_OUT_BUFFER_SIZE 1024
#define CTRL_BUF_SIZE 4
#define FUNCTION_NAME "ccid"
#define MAX_INST_NAME_LEN 40
@@ -629,14 +629,14 @@
struct f_ccid *ccid_dev = fp->private_data;
struct ccid_bulk_dev *bulk_dev = &ccid_dev->bulk_dev;
struct usb_request *req;
- int r = count, xfer;
+ int r = count, xfer, len;
int ret;
unsigned long flags;
pr_debug("ccid_bulk_read(%zu)\n", count);
if (count > BULK_OUT_BUFFER_SIZE) {
- pr_err("%s: max_buffer_size:%zu given_pkt_size:%zu\n",
+ pr_err("%s: max_buffer_size:%d given_pkt_size:%zu\n",
__func__, BULK_OUT_BUFFER_SIZE, count);
return -ENOMEM;
}
@@ -647,6 +647,7 @@
goto done;
}
+ len = ALIGN(count, ccid_dev->out->maxpacket);
requeue_req:
spin_lock_irqsave(&ccid_dev->lock, flags);
if (!atomic_read(&ccid_dev->online)) {
@@ -655,7 +656,7 @@
}
/* queue a request */
req = bulk_dev->rx_req;
- req->length = count;
+ req->length = len;
bulk_dev->rx_done = 0;
spin_unlock_irqrestore(&ccid_dev->lock, flags);
ret = usb_ep_queue(ccid_dev->out, req, GFP_KERNEL);
@@ -688,6 +689,9 @@
spin_unlock_irqrestore(&ccid_dev->lock, flags);
goto requeue_req;
}
+ if (req->actual > count)
+ pr_err("%s More data received(%d) than required(%zu)\n",
+ __func__, req->actual, count);
xfer = (req->actual < count) ? req->actual : count;
atomic_set(&bulk_dev->rx_req_busy, 1);
spin_unlock_irqrestore(&ccid_dev->lock, flags);
@@ -875,7 +879,8 @@
count = CTRL_BUF_SIZE;
ret = wait_event_interruptible(ctrl_dev->tx_wait_q,
- ctrl_dev->tx_ctrl_done);
+ ctrl_dev->tx_ctrl_done ||
+ !atomic_read(&ccid_dev->online));
if (ret < 0)
return ret;
ctrl_dev->tx_ctrl_done = 0;
diff --git a/drivers/usb/gadget/function/f_mtp.c b/drivers/usb/gadget/function/f_mtp.c
index 102003d..ca8ed69 100644
--- a/drivers/usb/gadget/function/f_mtp.c
+++ b/drivers/usb/gadget/function/f_mtp.c
@@ -137,6 +137,7 @@
} perf[MAX_ITERATION];
unsigned int dbg_read_index;
unsigned int dbg_write_index;
+ struct mutex read_mutex;
};
static struct usb_interface_descriptor mtp_interface_desc = {
@@ -626,11 +627,18 @@
dev->state = STATE_BUSY;
spin_unlock_irq(&dev->lock);
+ mutex_lock(&dev->read_mutex);
+ if (dev->state == STATE_OFFLINE) {
+ r = -EIO;
+ mutex_unlock(&dev->read_mutex);
+ goto done;
+ }
requeue_req:
/* queue a request */
req = dev->rx_req[0];
req->length = len;
dev->rx_done = 0;
+ mutex_unlock(&dev->read_mutex);
ret = usb_ep_queue(dev->ep_out, req, GFP_KERNEL);
if (ret < 0) {
r = -EIO;
@@ -656,6 +664,7 @@
usb_ep_dequeue(dev->ep_out, req);
goto done;
}
+ mutex_lock(&dev->read_mutex);
if (dev->state == STATE_BUSY) {
/* If we got a 0-len packet, throw it back and try again. */
if (req->actual == 0)
@@ -669,6 +678,7 @@
} else
r = -EIO;
+ mutex_unlock(&dev->read_mutex);
done:
spin_lock_irq(&dev->lock);
if (dev->state == STATE_CANCELED)
@@ -920,6 +930,12 @@
while (count > 0 || write_req) {
if (count > 0) {
+ mutex_lock(&dev->read_mutex);
+ if (dev->state == STATE_OFFLINE) {
+ r = -EIO;
+ mutex_unlock(&dev->read_mutex);
+ break;
+ }
/* queue a request */
read_req = dev->rx_req[cur_buf];
cur_buf = (cur_buf + 1) % RX_REQ_MAX;
@@ -928,6 +944,7 @@
read_req->length = mtp_rx_req_len;
dev->rx_done = 0;
+ mutex_unlock(&dev->read_mutex);
ret = usb_ep_queue(dev->ep_out, read_req, GFP_KERNEL);
if (ret < 0) {
r = -EIO;
@@ -940,15 +957,23 @@
if (write_req) {
DBG(cdev, "rx %p %d\n", write_req, write_req->actual);
start_time = ktime_get();
+ mutex_lock(&dev->read_mutex);
+ if (dev->state == STATE_OFFLINE) {
+ r = -EIO;
+ mutex_unlock(&dev->read_mutex);
+ break;
+ }
ret = vfs_write(filp, write_req->buf, write_req->actual,
&offset);
DBG(cdev, "vfs_write %d\n", ret);
if (ret != write_req->actual) {
r = -EIO;
+ mutex_unlock(&dev->read_mutex);
if (dev->state != STATE_OFFLINE)
dev->state = STATE_ERROR;
break;
}
+ mutex_unlock(&dev->read_mutex);
dev->perf[dev->dbg_write_index].vfs_wtime =
ktime_to_us(ktime_sub(ktime_get(), start_time));
dev->perf[dev->dbg_write_index].vfs_wbytes = ret;
@@ -976,6 +1001,13 @@
r = read_req->status;
break;
}
+
+ mutex_lock(&dev->read_mutex);
+ if (dev->state == STATE_OFFLINE) {
+ r = -EIO;
+ mutex_unlock(&dev->read_mutex);
+ break;
+ }
/* Check if we aligned the size due to MTU constraint */
if (count < read_req->length)
read_req->actual = (read_req->actual > count ?
@@ -996,6 +1028,7 @@
write_req = read_req;
read_req = NULL;
+ mutex_unlock(&dev->read_mutex);
}
}
@@ -1446,12 +1479,14 @@
int i;
mtp_string_defs[INTERFACE_STRING_INDEX].id = 0;
+ mutex_lock(&dev->read_mutex);
while ((req = mtp_req_get(dev, &dev->tx_idle)))
mtp_request_free(req, dev->ep_in);
for (i = 0; i < RX_REQ_MAX; i++)
mtp_request_free(dev->rx_req[i], dev->ep_out);
while ((req = mtp_req_get(dev, &dev->intr_idle)))
mtp_request_free(req, dev->ep_intr);
+ mutex_unlock(&dev->read_mutex);
dev->state = STATE_OFFLINE;
kfree(f->os_desc_table);
f->os_desc_n = 0;
@@ -1791,6 +1826,8 @@
usb_os_desc_prepare_interf_dir(&fi_mtp->func_inst.group, 1,
descs, names, THIS_MODULE);
+ mutex_init(&fi_mtp->dev->read_mutex);
+
return &fi_mtp->func_inst;
}
EXPORT_SYMBOL_GPL(alloc_inst_mtp_ptp);
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index a9a1e4c..c8989c6 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -77,6 +77,16 @@
#define USB_INTEL_USB3_PSSEN 0xD8
#define USB_INTEL_USB3PRM 0xDC
+/* ASMEDIA quirk use */
+#define ASMT_DATA_WRITE0_REG 0xF8
+#define ASMT_DATA_WRITE1_REG 0xFC
+#define ASMT_CONTROL_REG 0xE0
+#define ASMT_CONTROL_WRITE_BIT 0x02
+#define ASMT_WRITEREG_CMD 0x10423
+#define ASMT_FLOWCTL_ADDR 0xFA30
+#define ASMT_FLOWCTL_DATA 0xBA
+#define ASMT_PSEUDO_DATA 0
+
/*
* amd_chipset_gen values represent AMD different chipset generations
*/
@@ -412,6 +422,50 @@
}
EXPORT_SYMBOL_GPL(usb_amd_quirk_pll_disable);
+static int usb_asmedia_wait_write(struct pci_dev *pdev)
+{
+ unsigned long retry_count;
+ unsigned char value;
+
+ for (retry_count = 1000; retry_count > 0; --retry_count) {
+
+ pci_read_config_byte(pdev, ASMT_CONTROL_REG, &value);
+
+ if (value == 0xff) {
+ dev_err(&pdev->dev, "%s: check_ready ERROR", __func__);
+ return -EIO;
+ }
+
+ if ((value & ASMT_CONTROL_WRITE_BIT) == 0)
+ return 0;
+
+ usleep_range(40, 60);
+ }
+
+ dev_warn(&pdev->dev, "%s: check_write_ready timeout", __func__);
+ return -ETIMEDOUT;
+}
+
+void usb_asmedia_modifyflowcontrol(struct pci_dev *pdev)
+{
+ if (usb_asmedia_wait_write(pdev) != 0)
+ return;
+
+ /* send command and address to device */
+ pci_write_config_dword(pdev, ASMT_DATA_WRITE0_REG, ASMT_WRITEREG_CMD);
+ pci_write_config_dword(pdev, ASMT_DATA_WRITE1_REG, ASMT_FLOWCTL_ADDR);
+ pci_write_config_byte(pdev, ASMT_CONTROL_REG, ASMT_CONTROL_WRITE_BIT);
+
+ if (usb_asmedia_wait_write(pdev) != 0)
+ return;
+
+ /* send data to device */
+ pci_write_config_dword(pdev, ASMT_DATA_WRITE0_REG, ASMT_FLOWCTL_DATA);
+ pci_write_config_dword(pdev, ASMT_DATA_WRITE1_REG, ASMT_PSEUDO_DATA);
+ pci_write_config_byte(pdev, ASMT_CONTROL_REG, ASMT_CONTROL_WRITE_BIT);
+}
+EXPORT_SYMBOL_GPL(usb_asmedia_modifyflowcontrol);
+
void usb_amd_quirk_pll_enable(void)
{
usb_amd_quirk_pll(0);
diff --git a/drivers/usb/host/pci-quirks.h b/drivers/usb/host/pci-quirks.h
index c622ddf..6463fdb 100644
--- a/drivers/usb/host/pci-quirks.h
+++ b/drivers/usb/host/pci-quirks.h
@@ -11,6 +11,7 @@
void usb_amd_dev_put(void);
void usb_amd_quirk_pll_disable(void);
void usb_amd_quirk_pll_enable(void);
+void usb_asmedia_modifyflowcontrol(struct pci_dev *pdev);
void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev);
void usb_disable_xhci_ports(struct pci_dev *xhci_pdev);
void sb800_prefetch(struct device *dev, int on);
@@ -18,6 +19,7 @@
struct pci_dev;
static inline void usb_amd_quirk_pll_disable(void) {}
static inline void usb_amd_quirk_pll_enable(void) {}
+static inline void usb_asmedia_modifyflowcontrol(struct pci_dev *pdev) {}
static inline void usb_amd_dev_put(void) {}
static inline void usb_disable_xhci_ports(struct pci_dev *xhci_pdev) {}
static inline void sb800_prefetch(struct device *dev, int on) {}
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index b0c4f12..93aa6a0 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -798,6 +798,9 @@
clear_bit(wIndex, &bus_state->resuming_ports);
set_bit(wIndex, &bus_state->rexit_ports);
+
+ xhci_test_and_clear_bit(xhci, port_array, wIndex,
+ PORT_PLC);
xhci_set_link_state(xhci, port_array, wIndex,
XDEV_U0);
@@ -1210,6 +1213,39 @@
break;
}
+ /*
+ * For xHCI 1.1 according to section 4.19.1.2.4.1 a
+ * root hub port's transition to compliance mode upon
+ * detecting LFPS timeout may be controlled by an
+ * Compliance Transition Enabled (CTE) flag (not
+ * software visible). This flag is set by writing 0xA
+ * to PORTSC PLS field which will allow transition to
+ * compliance mode the next time LFPS timeout is
+ * encountered. A warm reset will clear it.
+ *
+ * The CTE flag is only supported if the HCCPARAMS2 CTC
+ * flag is set, otherwise, the compliance substate is
+ * automatically entered as on 1.0 and prior.
+ */
+ if (link_state == USB_SS_PORT_LS_COMP_MOD) {
+ if (!HCC2_CTC(xhci->hcc_params2)) {
+ xhci_dbg(xhci, "CTC flag is 0, port already supports entering compliance mode\n");
+ break;
+ }
+
+ if ((temp & PORT_CONNECT)) {
+ xhci_warn(xhci, "Can't set compliance mode when port is connected\n");
+ goto error;
+ }
+
+ xhci_dbg(xhci, "Enable compliance mode transition for port %d\n",
+ wIndex);
+ xhci_set_link_state(xhci, port_array, wIndex,
+ link_state);
+ temp = readl(port_array[wIndex]);
+ break;
+ }
+
/* Software should not attempt to set
* port link state above '3' (U3) and the port
* must be enabled.
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 672751e..2383344 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -59,6 +59,8 @@
#define PCI_DEVICE_ID_AMD_PROMONTORYA_2 0x43bb
#define PCI_DEVICE_ID_AMD_PROMONTORYA_1 0x43bc
+#define PCI_DEVICE_ID_ASMEDIA_1042A_XHCI 0x1142
+
static const char hcd_name[] = "xhci_hcd";
static struct hc_driver __read_mostly xhci_pci_hc_driver;
@@ -217,6 +219,10 @@
pdev->device == 0x1142)
xhci->quirks |= XHCI_TRUST_TX_LENGTH;
+ if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
+ pdev->device == PCI_DEVICE_ID_ASMEDIA_1042A_XHCI)
+ xhci->quirks |= XHCI_ASMEDIA_MODIFY_FLOWCONTROL;
+
if (pdev->vendor == PCI_VENDOR_ID_TI && pdev->device == 0x8241)
xhci->quirks |= XHCI_LIMIT_ENDPOINT_INTERVAL_7;
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 5d434e0..e185bbe 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -860,13 +860,16 @@
(ep->ep_state & EP_GETTING_NO_STREAMS)) {
int stream_id;
- for (stream_id = 0; stream_id < ep->stream_info->num_streams;
+ for (stream_id = 1; stream_id < ep->stream_info->num_streams;
stream_id++) {
+ ring = ep->stream_info->stream_rings[stream_id];
+ if (!ring)
+ continue;
+
xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
"Killing URBs for slot ID %u, ep index %u, stream %u",
- slot_id, ep_index, stream_id + 1);
- xhci_kill_ring_urbs(xhci,
- ep->stream_info->stream_rings[stream_id]);
+ slot_id, ep_index, stream_id);
+ xhci_kill_ring_urbs(xhci, ring);
}
} else {
ring = ep->ring;
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index ec9ff3e..15bf308 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -201,6 +201,9 @@
if (ret)
return ret;
+ if (xhci->quirks & XHCI_ASMEDIA_MODIFY_FLOWCONTROL)
+ usb_asmedia_modifyflowcontrol(to_pci_dev(xhci_to_hcd(xhci)->self.controller));
+
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
"Wait for controller to be ready for doorbell rings");
/*
@@ -1134,6 +1137,9 @@
if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) && !comp_timer_running)
compliance_mode_recovery_timer_init(xhci);
+ if (xhci->quirks & XHCI_ASMEDIA_MODIFY_FLOWCONTROL)
+ usb_asmedia_modifyflowcontrol(to_pci_dev(hcd->self.controller));
+
/* Re-enable port polling. */
xhci_dbg(xhci, "%s: starting port polling.\n", __func__);
set_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags);
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 3a7fb29..757d045 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1669,6 +1669,7 @@
#define XHCI_BROKEN_PORT_PED (1 << 25)
#define XHCI_LIMIT_ENDPOINT_INTERVAL_7 (1 << 26)
#define XHCI_U2_DISABLE_WAKE (1 << 27)
+#define XHCI_ASMEDIA_MODIFY_FLOWCONTROL (1 << 28)
unsigned int num_active_eps;
unsigned int limit_active_eps;
diff --git a/drivers/usb/misc/lvstest.c b/drivers/usb/misc/lvstest.c
index d3d1247..2020009 100644
--- a/drivers/usb/misc/lvstest.c
+++ b/drivers/usb/misc/lvstest.c
@@ -178,6 +178,25 @@
}
static DEVICE_ATTR_WO(hot_reset);
+static ssize_t warm_reset_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct usb_device *hdev = interface_to_usbdev(intf);
+ struct lvs_rh *lvs = usb_get_intfdata(intf);
+ int ret;
+
+ ret = lvs_rh_set_port_feature(hdev, lvs->portnum,
+ USB_PORT_FEAT_BH_PORT_RESET);
+ if (ret < 0) {
+ dev_err(dev, "can't issue warm reset %d\n", ret);
+ return ret;
+ }
+
+ return count;
+}
+static DEVICE_ATTR_WO(warm_reset);
+
static ssize_t u2_timeout_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
@@ -274,13 +293,35 @@
}
static DEVICE_ATTR_WO(get_dev_desc);
+static ssize_t enable_compliance_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct usb_device *hdev = interface_to_usbdev(intf);
+ struct lvs_rh *lvs = usb_get_intfdata(intf);
+ int ret;
+
+ ret = lvs_rh_set_port_feature(hdev,
+ lvs->portnum | USB_SS_PORT_LS_COMP_MOD << 3,
+ USB_PORT_FEAT_LINK_STATE);
+ if (ret < 0) {
+ dev_err(dev, "can't enable compliance mode %d\n", ret);
+ return ret;
+ }
+
+ return count;
+}
+static DEVICE_ATTR_WO(enable_compliance);
+
static struct attribute *lvs_attributes[] = {
&dev_attr_get_dev_desc.attr,
&dev_attr_u1_timeout.attr,
&dev_attr_u2_timeout.attr,
&dev_attr_hot_reset.attr,
+ &dev_attr_warm_reset.attr,
&dev_attr_u3_entry.attr,
&dev_attr_u3_exit.attr,
+ &dev_attr_enable_compliance.attr,
NULL
};
diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c
index 1fad512..574ff79 100644
--- a/drivers/usb/pd/policy_engine.c
+++ b/drivers/usb/pd/policy_engine.c
@@ -38,6 +38,10 @@
module_param(disable_usb_pd, bool, 0644);
MODULE_PARM_DESC(disable_usb_pd, "Disable USB PD for USB3.1 compliance testing");
+static bool rev3_sink_only;
+module_param(rev3_sink_only, bool, 0644);
+MODULE_PARM_DESC(rev3_sink_only, "Enable power delivery rev3.0 sink only mode");
+
enum usbpd_state {
PE_UNKNOWN,
PE_ERROR_RECOVERY,
@@ -377,6 +381,8 @@
struct list_head svid_handlers;
struct list_head instance;
+
+ u16 ss_lane_svid;
};
static LIST_HEAD(_usbpd); /* useful for debugging */
@@ -445,6 +451,47 @@
extcon_set_state_sync(pd->extcon, EXTCON_USB, 1);
}
+/**
+ * This API allows client driver to request for releasing SS lanes. It should
+ * not be called from atomic context.
+ *
+ * @pd - USBPD handler
+ * @hdlr - client's handler
+ *
+ * @returns int - Success - 0, else negative error code
+ */
+static int usbpd_release_ss_lane(struct usbpd *pd,
+ struct usbpd_svid_handler *hdlr)
+{
+ int ret = 0;
+
+ if (!hdlr || !pd)
+ return -EINVAL;
+
+ usbpd_dbg(&pd->dev, "hdlr:%pK svid:%d", hdlr, hdlr->svid);
+ /*
+ * If USB SS lanes are already used by one client, and other client is
+ * requesting for same or same client requesting again, return -EBUSY.
+ */
+ if (pd->ss_lane_svid) {
+ usbpd_dbg(&pd->dev, "-EBUSY: ss_lanes are already used by(%d)",
+ pd->ss_lane_svid);
+ ret = -EBUSY;
+ goto err_exit;
+ }
+
+ ret = extcon_blocking_sync(pd->extcon, EXTCON_USB_HOST, 0);
+ if (ret) {
+ usbpd_err(&pd->dev, "err(%d) for releasing ss lane", ret);
+ goto err_exit;
+ }
+
+ pd->ss_lane_svid = hdlr->svid;
+
+err_exit:
+ return ret;
+}
+
static int set_power_role(struct usbpd *pd, enum power_role pr)
{
union power_supply_propval val = {0};
@@ -490,21 +537,18 @@
pd->send_dr_swap = false;
}
-static int pd_send_msg(struct usbpd *pd, u8 hdr_type, const u32 *data,
- size_t num_data, enum pd_msg_type type)
+static int pd_send_msg(struct usbpd *pd, u8 msg_type, const u32 *data,
+ size_t num_data, enum pd_sop_type sop)
{
int ret;
u16 hdr;
- hdr = PD_MSG_HDR(hdr_type, pd->current_dr, pd->current_pr,
+ hdr = PD_MSG_HDR(msg_type, pd->current_dr, pd->current_pr,
pd->tx_msgid, num_data, pd->spec_rev);
- ret = pd_phy_write(hdr, (u8 *)data, num_data * sizeof(u32), type, 15);
- /* TODO figure out timeout. based on tReceive=1.1ms x nRetryCount? */
- if (ret < 0)
+ ret = pd_phy_write(hdr, (u8 *)data, num_data * sizeof(u32), sop);
+ if (ret)
return ret;
- else if (ret != num_data * sizeof(u32))
- return -EIO;
pd->tx_msgid = (pd->tx_msgid + 1) & PD_MAX_MSG_ID;
return 0;
@@ -566,7 +610,7 @@
static int pd_eval_src_caps(struct usbpd *pd)
{
- int obj_cnt;
+ int i;
union power_supply_propval val;
u32 first_pdo = pd->received_pdos[0];
@@ -583,11 +627,20 @@
power_supply_set_property(pd->usb_psy,
POWER_SUPPLY_PROP_PD_USB_SUSPEND_SUPPORTED, &val);
- for (obj_cnt = 1; obj_cnt < PD_MAX_DATA_OBJ; obj_cnt++) {
- if ((PD_SRC_PDO_TYPE(pd->received_pdos[obj_cnt]) ==
+ if (pd->spec_rev == USBPD_REV_30 && !rev3_sink_only) {
+ bool pps_found = false;
+
+ /* downgrade to 2.0 if no PPS */
+ for (i = 1; i < PD_MAX_DATA_OBJ; i++) {
+ if ((PD_SRC_PDO_TYPE(pd->received_pdos[i]) ==
PD_SRC_PDO_TYPE_AUGMENTED) &&
- !PD_APDO_PPS(pd->received_pdos[obj_cnt]))
- pd->spec_rev = USBPD_REV_30;
+ !PD_APDO_PPS(pd->received_pdos[i])) {
+ pps_found = true;
+ break;
+ }
+ }
+ if (!pps_found)
+ pd->spec_rev = USBPD_REV_20;
}
/* Select the first PDO (vSafe5V) immediately. */
@@ -605,7 +658,7 @@
/* Force CC logic to source/sink to keep Rp/Rd unchanged */
set_power_role(pd, pd->current_pr);
pd->hard_reset_count++;
- pd_phy_signal(HARD_RESET_SIG, 5); /* tHardResetComplete */
+ pd_phy_signal(HARD_RESET_SIG);
pd->in_pr_swap = false;
power_supply_set_property(pd->usb_psy, POWER_SUPPLY_PROP_PR_SWAP, &val);
}
@@ -621,12 +674,12 @@
queue_work(pd->wq, &pd->sm_work);
}
-static void phy_sig_received(struct usbpd *pd, enum pd_sig_type type)
+static void phy_sig_received(struct usbpd *pd, enum pd_sig_type sig)
{
union power_supply_propval val = {1};
- if (type != HARD_RESET_SIG) {
- usbpd_err(&pd->dev, "invalid signal (%d) received\n", type);
+ if (sig != HARD_RESET_SIG) {
+ usbpd_err(&pd->dev, "invalid signal (%d) received\n", sig);
return;
}
@@ -641,16 +694,16 @@
kick_sm(pd, 0);
}
-static void phy_msg_received(struct usbpd *pd, enum pd_msg_type type,
+static void phy_msg_received(struct usbpd *pd, enum pd_sop_type sop,
u8 *buf, size_t len)
{
struct rx_msg *rx_msg;
unsigned long flags;
u16 header;
- if (type != SOP_MSG) {
+ if (sop != SOP_MSG) {
usbpd_err(&pd->dev, "invalid msg type (%d) received; only SOP supported\n",
- type);
+ sop);
return;
}
@@ -688,6 +741,10 @@
return;
}
+ /* if spec rev differs (i.e. is older), update PHY */
+ if (PD_MSG_HDR_REV(header) < pd->spec_rev)
+ pd->spec_rev = PD_MSG_HDR_REV(header);
+
rx_msg = kzalloc(sizeof(*rx_msg), GFP_KERNEL);
if (!rx_msg)
return;
@@ -764,6 +821,7 @@
if (pd->current_dr == DR_NONE) {
pd->current_dr = DR_DFP;
start_usb_host(pd, true);
+ pd->ss_lane_svid = 0x0;
}
dual_role_instance_changed(pd->dual_role);
@@ -773,6 +831,8 @@
power_supply_set_property(pd->usb_psy,
POWER_SUPPLY_PROP_TYPEC_POWER_ROLE, &val);
+ /* support only PD 2.0 as a source */
+ pd->spec_rev = USBPD_REV_20;
pd_reset_protocol(pd);
if (!pd->in_pr_swap) {
@@ -926,6 +986,7 @@
if (pd->psy_type == POWER_SUPPLY_TYPE_USB ||
pd->psy_type == POWER_SUPPLY_TYPE_USB_CDP ||
+ pd->psy_type == POWER_SUPPLY_TYPE_USB_FLOAT ||
usb_compliance_mode)
start_usb_peripheral(pd);
}
@@ -943,6 +1004,11 @@
if (!val.intval || disable_usb_pd)
break;
+ /*
+ * support up to PD 3.0 as a sink; if source is 2.0
+ * phy_msg_received() will handle the downgrade.
+ */
+ pd->spec_rev = USBPD_REV_30;
pd_reset_protocol(pd);
if (!pd->in_pr_swap) {
@@ -1083,6 +1149,7 @@
usbpd_dbg(&pd->dev, "registered handler for SVID 0x%04x\n", hdlr->svid);
list_add_tail(&hdlr->entry, &pd->svid_handlers);
+ hdlr->request_usb_ss_lane = usbpd_release_ss_lane;
/* already connected with this SVID discovered? */
if (pd->vdm_state >= DISCOVERED_SVIDS) {
@@ -1432,6 +1499,7 @@
static void dr_swap(struct usbpd *pd)
{
reset_vdm_state(pd);
+ usbpd_dbg(&pd->dev, "dr_swap: current_dr(%d)\n", pd->current_dr);
if (pd->current_dr == DR_DFP) {
stop_usb_host(pd);
@@ -1439,9 +1507,9 @@
pd->current_dr = DR_UFP;
} else if (pd->current_dr == DR_UFP) {
stop_usb_peripheral(pd);
+ start_usb_host(pd, true);
pd->current_dr = DR_DFP;
- /* don't start USB host until after SVDM discovery */
usbpd_send_svdm(pd, USBPD_SID, USBPD_SVDM_DISCOVER_IDENTITY,
SVDM_CMD_TYPE_INITIATOR, 0, NULL, 0);
}
@@ -1628,6 +1696,8 @@
/* set due to dual_role class "mode" change */
if (pd->forced_pr != POWER_SUPPLY_TYPEC_PR_NONE)
val.intval = pd->forced_pr;
+ else if (rev3_sink_only)
+ val.intval = POWER_SUPPLY_TYPEC_PR_SINK;
else
/* Set CC back to DRP toggle */
val.intval = POWER_SUPPLY_TYPEC_PR_DUAL;
@@ -2467,6 +2537,16 @@
if (pd->current_pr == PR_SINK)
return 0;
+ /*
+ * Unexpected if not in PR swap; need to force disconnect from
+ * source so we can turn off VBUS, Vconn, PD PHY etc.
+ */
+ if (pd->current_pr == PR_SRC) {
+ usbpd_info(&pd->dev, "Forcing disconnect from source mode\n");
+ pd->current_pr = PR_NONE;
+ break;
+ }
+
pd->current_pr = PR_SINK;
break;
@@ -3344,8 +3424,6 @@
pd->dual_role->drv_data = pd;
}
- /* default support as PD 2.0 source or sink */
- pd->spec_rev = USBPD_REV_20;
pd->current_pr = PR_NONE;
pd->current_dr = DR_NONE;
list_add_tail(&pd->instance, &_usbpd);
diff --git a/drivers/usb/pd/qpnp-pdphy.c b/drivers/usb/pd/qpnp-pdphy.c
index 1f5306f..735774a 100644
--- a/drivers/usb/pd/qpnp-pdphy.c
+++ b/drivers/usb/pd/qpnp-pdphy.c
@@ -80,6 +80,10 @@
#define VDD_PDPHY_VOL_MAX 3088000 /* uV */
#define VDD_PDPHY_HPM_LOAD 3000 /* uA */
+/* timers */
+#define RECEIVER_RESPONSE_TIME 15 /* tReceiverResponse */
+#define HARD_RESET_COMPLETE_TIME 5 /* tHardResetComplete */
+
struct usb_pdphy {
struct device *dev;
struct regmap *regmap;
@@ -96,8 +100,8 @@
int msg_tx_discarded_irq;
int msg_rx_discarded_irq;
- void (*signal_cb)(struct usbpd *pd, enum pd_sig_type type);
- void (*msg_rx_cb)(struct usbpd *pd, enum pd_msg_type type,
+ void (*signal_cb)(struct usbpd *pd, enum pd_sig_type sig);
+ void (*msg_rx_cb)(struct usbpd *pd, enum pd_sop_type sop,
u8 *buf, size_t len);
void (*shutdown_cb)(struct usbpd *pd);
@@ -401,14 +405,13 @@
}
EXPORT_SYMBOL(pd_phy_open);
-int pd_phy_signal(enum pd_sig_type type, unsigned int timeout_ms)
+int pd_phy_signal(enum pd_sig_type sig)
{
u8 val;
int ret;
struct usb_pdphy *pdphy = __pdphy;
- dev_dbg(pdphy->dev, "%s: type %d timeout %u\n", __func__, type,
- timeout_ms);
+ dev_dbg(pdphy->dev, "%s: type %d\n", __func__, sig);
if (!pdphy) {
pr_err("%s: pdphy not found\n", __func__);
@@ -428,7 +431,7 @@
usleep_range(2, 3);
- val = (type == CABLE_RESET_SIG ? TX_CONTROL_FRAME_TYPE_CABLE_RESET : 0)
+ val = (sig == CABLE_RESET_SIG ? TX_CONTROL_FRAME_TYPE_CABLE_RESET : 0)
| TX_CONTROL_SEND_SIGNAL;
ret = pdphy_reg_write(pdphy, USB_PDPHY_TX_CONTROL, val);
@@ -436,7 +439,8 @@
return ret;
ret = wait_event_interruptible_timeout(pdphy->tx_waitq,
- pdphy->tx_status != -EINPROGRESS, msecs_to_jiffies(timeout_ms));
+ pdphy->tx_status != -EINPROGRESS,
+ msecs_to_jiffies(HARD_RESET_COMPLETE_TIME));
if (ret <= 0) {
dev_err(pdphy->dev, "%s: failed ret %d", __func__, ret);
return ret ? ret : -ETIMEDOUT;
@@ -447,7 +451,7 @@
if (pdphy->tx_status)
return pdphy->tx_status;
- if (type == HARD_RESET_SIG)
+ if (sig == HARD_RESET_SIG)
/* Frame filter is reconfigured in pd_phy_open() */
return pdphy_reg_write(pdphy, USB_PDPHY_FRAME_FILTER, 0);
@@ -455,16 +459,15 @@
}
EXPORT_SYMBOL(pd_phy_signal);
-int pd_phy_write(u16 hdr, const u8 *data, size_t data_len,
- enum pd_msg_type type, unsigned int timeout_ms)
+int pd_phy_write(u16 hdr, const u8 *data, size_t data_len, enum pd_sop_type sop)
{
u8 val;
int ret;
size_t total_len = data_len + USB_PDPHY_MSG_HDR_LEN;
struct usb_pdphy *pdphy = __pdphy;
- dev_dbg(pdphy->dev, "%s: hdr %x frame type %d timeout %u\n",
- __func__, hdr, type, timeout_ms);
+ dev_dbg(pdphy->dev, "%s: hdr %x frame sop_type %d\n",
+ __func__, hdr, sop);
if (data && data_len)
print_hex_dump_debug("tx data obj:", DUMP_PREFIX_NONE, 32, 4,
@@ -518,14 +521,15 @@
usleep_range(2, 3);
- val = TX_CONTROL_RETRY_COUNT | (type << 2) | TX_CONTROL_SEND_MSG;
+ val = TX_CONTROL_RETRY_COUNT | (sop << 2) | TX_CONTROL_SEND_MSG;
ret = pdphy_reg_write(pdphy, USB_PDPHY_TX_CONTROL, val);
if (ret)
return ret;
ret = wait_event_interruptible_timeout(pdphy->tx_waitq,
- pdphy->tx_status != -EINPROGRESS, msecs_to_jiffies(timeout_ms));
+ pdphy->tx_status != -EINPROGRESS,
+ msecs_to_jiffies(RECEIVER_RESPONSE_TIME));
if (ret <= 0) {
dev_err(pdphy->dev, "%s: failed ret %d", __func__, ret);
return ret ? ret : -ETIMEDOUT;
@@ -534,7 +538,7 @@
if (hdr && !pdphy->tx_status)
pdphy->tx_bytes += data_len + USB_PDPHY_MSG_HDR_LEN;
- return pdphy->tx_status ? pdphy->tx_status : data_len;
+ return pdphy->tx_status ? pdphy->tx_status : 0;
}
EXPORT_SYMBOL(pd_phy_write);
diff --git a/drivers/usb/pd/usbpd.h b/drivers/usb/pd/usbpd.h
index 1087017..9b6053e 100644
--- a/drivers/usb/pd/usbpd.h
+++ b/drivers/usb/pd/usbpd.h
@@ -45,7 +45,7 @@
CABLE_RESET_SIG,
};
-enum pd_msg_type {
+enum pd_sop_type {
SOP_MSG = 0,
SOPI_MSG,
SOPII_MSG,
@@ -61,8 +61,8 @@
#define FRAME_FILTER_EN_HARD_RESET BIT(5)
struct pd_phy_params {
- void (*signal_cb)(struct usbpd *pd, enum pd_sig_type type);
- void (*msg_rx_cb)(struct usbpd *pd, enum pd_msg_type type,
+ void (*signal_cb)(struct usbpd *pd, enum pd_sig_type sig);
+ void (*msg_rx_cb)(struct usbpd *pd, enum pd_sop_type sop,
u8 *buf, size_t len);
void (*shutdown_cb)(struct usbpd *pd);
enum data_role data_role;
@@ -72,9 +72,9 @@
#if IS_ENABLED(CONFIG_QPNP_USB_PDPHY)
int pd_phy_open(struct pd_phy_params *params);
-int pd_phy_signal(enum pd_sig_type type, unsigned int timeout_ms);
+int pd_phy_signal(enum pd_sig_type sig);
int pd_phy_write(u16 hdr, const u8 *data, size_t data_len,
- enum pd_msg_type type, unsigned int timeout_ms);
+ enum pd_sop_type sop);
int pd_phy_update_roles(enum data_role dr, enum power_role pr);
void pd_phy_close(void);
#else
@@ -83,13 +83,13 @@
return -ENODEV;
}
-static inline int pd_phy_signal(enum pd_sig_type type, unsigned int timeout_ms)
+static inline int pd_phy_signal(enum pd_sig_type type)
{
return -ENODEV;
}
static inline int pd_phy_write(u16 hdr, const u8 *data, size_t data_len,
- enum pd_msg_type type, unsigned int timeout_ms)
+ enum pd_sop_type sop)
{
return -ENODEV;
}
diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c
index 012a37a..7994208 100644
--- a/drivers/usb/renesas_usbhs/common.c
+++ b/drivers/usb/renesas_usbhs/common.c
@@ -752,8 +752,10 @@
struct usbhs_priv *priv = dev_get_drvdata(dev);
struct platform_device *pdev = usbhs_priv_to_pdev(priv);
- if (!usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL))
+ if (!usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL)) {
usbhsc_power_ctrl(priv, 1);
+ usbhs_mod_autonomy_mode(priv);
+ }
usbhs_platform_call(priv, phy_reset, pdev);
diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c
index 5bc7a61..93fba90 100644
--- a/drivers/usb/renesas_usbhs/mod_gadget.c
+++ b/drivers/usb/renesas_usbhs/mod_gadget.c
@@ -37,6 +37,7 @@
struct usbhsg_uep {
struct usb_ep ep;
struct usbhs_pipe *pipe;
+ spinlock_t lock; /* protect the pipe */
char ep_name[EP_NAME_SIZE];
@@ -636,10 +637,16 @@
static int usbhsg_ep_disable(struct usb_ep *ep)
{
struct usbhsg_uep *uep = usbhsg_ep_to_uep(ep);
- struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep);
+ struct usbhs_pipe *pipe;
+ unsigned long flags;
+ int ret = 0;
- if (!pipe)
- return -EINVAL;
+ spin_lock_irqsave(&uep->lock, flags);
+ pipe = usbhsg_uep_to_pipe(uep);
+ if (!pipe) {
+ ret = -EINVAL;
+ goto out;
+ }
usbhsg_pipe_disable(uep);
usbhs_pipe_free(pipe);
@@ -647,6 +654,9 @@
uep->pipe->mod_private = NULL;
uep->pipe = NULL;
+out:
+ spin_unlock_irqrestore(&uep->lock, flags);
+
return 0;
}
@@ -696,8 +706,11 @@
{
struct usbhsg_uep *uep = usbhsg_ep_to_uep(ep);
struct usbhsg_request *ureq = usbhsg_req_to_ureq(req);
- struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep);
+ struct usbhs_pipe *pipe;
+ unsigned long flags;
+ spin_lock_irqsave(&uep->lock, flags);
+ pipe = usbhsg_uep_to_pipe(uep);
if (pipe)
usbhs_pkt_pop(pipe, usbhsg_ureq_to_pkt(ureq));
@@ -706,6 +719,7 @@
* even if the pipe is NULL.
*/
usbhsg_queue_pop(uep, ureq, -ECONNRESET);
+ spin_unlock_irqrestore(&uep->lock, flags);
return 0;
}
@@ -852,10 +866,10 @@
{
struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv);
struct usbhs_mod *mod = usbhs_mod_get_current(priv);
- struct usbhsg_uep *dcp = usbhsg_gpriv_to_dcp(gpriv);
+ struct usbhsg_uep *uep;
struct device *dev = usbhs_priv_to_dev(priv);
unsigned long flags;
- int ret = 0;
+ int ret = 0, i;
/******************** spin lock ********************/
usbhs_lock(priv, flags);
@@ -887,7 +901,9 @@
usbhs_sys_set_test_mode(priv, 0);
usbhs_sys_function_ctrl(priv, 0);
- usbhsg_ep_disable(&dcp->ep);
+ /* disable all eps */
+ usbhsg_for_each_uep_with_dcp(uep, gpriv, i)
+ usbhsg_ep_disable(&uep->ep);
dev_dbg(dev, "stop gadget\n");
@@ -1069,6 +1085,7 @@
ret = -ENOMEM;
goto usbhs_mod_gadget_probe_err_gpriv;
}
+ spin_lock_init(&uep->lock);
gpriv->transceiver = usb_get_phy(USB_PHY_TYPE_UNDEFINED);
dev_info(dev, "%stransceiver found\n",
diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c
index fba4005..6a7720e 100644
--- a/drivers/usb/storage/isd200.c
+++ b/drivers/usb/storage/isd200.c
@@ -1529,8 +1529,11 @@
/* Make sure driver was initialized */
- if (us->extra == NULL)
+ if (us->extra == NULL) {
usb_stor_dbg(us, "ERROR Driver not initialized\n");
+ srb->result = DID_ERROR << 16;
+ return;
+ }
scsi_set_resid(srb, 0);
/* scsi_bufflen might change in protocol translation to ata */
diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c
index d1d70e0..881fc3a 100644
--- a/drivers/vfio/vfio.c
+++ b/drivers/vfio/vfio.c
@@ -419,6 +419,34 @@
kref_put_mutex(&group->kref, vfio_group_release, &vfio.group_lock);
}
+struct vfio_group_put_work {
+ struct work_struct work;
+ struct vfio_group *group;
+};
+
+static void vfio_group_put_bg(struct work_struct *work)
+{
+ struct vfio_group_put_work *do_work;
+
+ do_work = container_of(work, struct vfio_group_put_work, work);
+
+ vfio_group_put(do_work->group);
+ kfree(do_work);
+}
+
+static void vfio_group_schedule_put(struct vfio_group *group)
+{
+ struct vfio_group_put_work *do_work;
+
+ do_work = kmalloc(sizeof(*do_work), GFP_KERNEL);
+ if (WARN_ON(!do_work))
+ return;
+
+ INIT_WORK(&do_work->work, vfio_group_put_bg);
+ do_work->group = group;
+ schedule_work(&do_work->work);
+}
+
/* Assume group_lock or group reference is held */
static void vfio_group_get(struct vfio_group *group)
{
@@ -743,7 +771,14 @@
break;
}
- vfio_group_put(group);
+ /*
+ * If we're the last reference to the group, the group will be
+ * released, which includes unregistering the iommu group notifier.
+ * We hold a read-lock on that notifier list, unregistering needs
+ * a write-lock... deadlock. Release our reference asynchronously
+ * to avoid that situation.
+ */
+ vfio_group_schedule_put(group);
return NOTIFY_OK;
}
@@ -1716,6 +1751,15 @@
}
EXPORT_SYMBOL_GPL(vfio_group_put_external_user);
+bool vfio_external_group_match_file(struct vfio_group *test_group,
+ struct file *filep)
+{
+ struct vfio_group *group = filep->private_data;
+
+ return (filep->f_op == &vfio_group_fops) && (group == test_group);
+}
+EXPORT_SYMBOL_GPL(vfio_external_group_match_file);
+
int vfio_external_user_iommu_id(struct vfio_group *group)
{
return iommu_group_id(group->iommu_group);
diff --git a/drivers/video/adf/adf_client.c b/drivers/video/adf/adf_client.c
index 8061d8e..75b2f0b 100644
--- a/drivers/video/adf/adf_client.c
+++ b/drivers/video/adf/adf_client.c
@@ -305,8 +305,10 @@
}
done:
- if (ret < 0)
+ if (ret < 0) {
adf_buffer_mapping_cleanup(mapping, buf);
+ memset(mapping, 0, sizeof(*mapping));
+ }
return ret;
}
diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c
index d6950e0..980f328 100644
--- a/drivers/xen/xen-scsiback.c
+++ b/drivers/xen/xen-scsiback.c
@@ -134,9 +134,7 @@
struct page *pages[VSCSI_MAX_GRANTS];
struct se_cmd se_cmd;
-};
-struct scsiback_tmr {
atomic_t tmr_complete;
wait_queue_head_t tmr_wait;
};
@@ -599,26 +597,20 @@
struct scsiback_tpg *tpg = pending_req->v2p->tpg;
struct scsiback_nexus *nexus = tpg->tpg_nexus;
struct se_cmd *se_cmd = &pending_req->se_cmd;
- struct scsiback_tmr *tmr;
u64 unpacked_lun = pending_req->v2p->lun;
int rc, err = FAILED;
- tmr = kzalloc(sizeof(struct scsiback_tmr), GFP_KERNEL);
- if (!tmr) {
- target_put_sess_cmd(se_cmd);
- goto err;
- }
-
- init_waitqueue_head(&tmr->tmr_wait);
+ init_waitqueue_head(&pending_req->tmr_wait);
rc = target_submit_tmr(&pending_req->se_cmd, nexus->tvn_se_sess,
&pending_req->sense_buffer[0],
- unpacked_lun, tmr, act, GFP_KERNEL,
+ unpacked_lun, NULL, act, GFP_KERNEL,
tag, TARGET_SCF_ACK_KREF);
if (rc)
goto err;
- wait_event(tmr->tmr_wait, atomic_read(&tmr->tmr_complete));
+ wait_event(pending_req->tmr_wait,
+ atomic_read(&pending_req->tmr_complete));
err = (se_cmd->se_tmr_req->response == TMR_FUNCTION_COMPLETE) ?
SUCCESS : FAILED;
@@ -626,9 +618,8 @@
scsiback_do_resp_with_sense(NULL, err, 0, pending_req);
transport_generic_free_cmd(&pending_req->se_cmd, 1);
return;
+
err:
- if (tmr)
- kfree(tmr);
scsiback_do_resp_with_sense(NULL, err, 0, pending_req);
}
@@ -1389,12 +1380,6 @@
static void scsiback_release_cmd(struct se_cmd *se_cmd)
{
struct se_session *se_sess = se_cmd->se_sess;
- struct se_tmr_req *se_tmr = se_cmd->se_tmr_req;
-
- if (se_tmr && se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB) {
- struct scsiback_tmr *tmr = se_tmr->fabric_tmr_ptr;
- kfree(tmr);
- }
percpu_ida_free(&se_sess->sess_tag_pool, se_cmd->map_tag);
}
@@ -1455,11 +1440,11 @@
static void scsiback_queue_tm_rsp(struct se_cmd *se_cmd)
{
- struct se_tmr_req *se_tmr = se_cmd->se_tmr_req;
- struct scsiback_tmr *tmr = se_tmr->fabric_tmr_ptr;
+ struct vscsibk_pend *pending_req = container_of(se_cmd,
+ struct vscsibk_pend, se_cmd);
- atomic_set(&tmr->tmr_complete, 1);
- wake_up(&tmr->tmr_wait);
+ atomic_set(&pending_req->tmr_complete, 1);
+ wake_up(&pending_req->tmr_wait);
}
static void scsiback_aborted_task(struct se_cmd *se_cmd)
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index cfd724f..1fdf4e5 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -911,17 +911,60 @@
elf_flags = MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE;
vaddr = elf_ppnt->p_vaddr;
+ /*
+ * If we are loading ET_EXEC or we have already performed
+ * the ET_DYN load_addr calculations, proceed normally.
+ */
if (loc->elf_ex.e_type == ET_EXEC || load_addr_set) {
elf_flags |= MAP_FIXED;
} else if (loc->elf_ex.e_type == ET_DYN) {
- /* Try and get dynamic programs out of the way of the
- * default mmap base, as well as whatever program they
- * might try to exec. This is because the brk will
- * follow the loader, and is not movable. */
- load_bias = ELF_ET_DYN_BASE - vaddr;
- if (current->flags & PF_RANDOMIZE)
- load_bias += arch_mmap_rnd();
- load_bias = ELF_PAGESTART(load_bias);
+ /*
+ * This logic is run once for the first LOAD Program
+ * Header for ET_DYN binaries to calculate the
+ * randomization (load_bias) for all the LOAD
+ * Program Headers, and to calculate the entire
+ * size of the ELF mapping (total_size). (Note that
+ * load_addr_set is set to true later once the
+ * initial mapping is performed.)
+ *
+ * There are effectively two types of ET_DYN
+ * binaries: programs (i.e. PIE: ET_DYN with INTERP)
+ * and loaders (ET_DYN without INTERP, since they
+ * _are_ the ELF interpreter). The loaders must
+ * be loaded away from programs since the program
+ * may otherwise collide with the loader (especially
+ * for ET_EXEC which does not have a randomized
+ * position). For example to handle invocations of
+ * "./ld.so someprog" to test out a new version of
+ * the loader, the subsequent program that the
+ * loader loads must avoid the loader itself, so
+ * they cannot share the same load range. Sufficient
+ * room for the brk must be allocated with the
+ * loader as well, since brk must be available with
+ * the loader.
+ *
+ * Therefore, programs are loaded offset from
+ * ELF_ET_DYN_BASE and loaders are loaded into the
+ * independently randomized mmap region (0 load_bias
+ * without MAP_FIXED).
+ */
+ if (elf_interpreter) {
+ load_bias = ELF_ET_DYN_BASE;
+ if (current->flags & PF_RANDOMIZE)
+ load_bias += arch_mmap_rnd();
+ elf_flags |= MAP_FIXED;
+ } else
+ load_bias = 0;
+
+ /*
+ * Since load_bias is used for all subsequent loading
+ * calculations, we must lower it by the first vaddr
+ * so that the remaining calculations based on the
+ * ELF vaddrs will be correctly offset. The result
+ * is then page aligned.
+ */
+ load_bias = ELF_PAGESTART(load_bias - vaddr);
+
total_size = total_mapping_size(elf_phdata,
loc->elf_ex.e_phnum);
if (!total_size) {
diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c
index 247b8df..8d8370d 100644
--- a/fs/btrfs/acl.c
+++ b/fs/btrfs/acl.c
@@ -78,12 +78,6 @@
switch (type) {
case ACL_TYPE_ACCESS:
name = XATTR_NAME_POSIX_ACL_ACCESS;
- if (acl) {
- ret = posix_acl_update_mode(inode, &inode->i_mode, &acl);
- if (ret)
- return ret;
- }
- ret = 0;
break;
case ACL_TYPE_DEFAULT:
if (!S_ISDIR(inode->i_mode))
@@ -119,6 +113,13 @@
int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
{
+ int ret;
+
+ if (type == ACL_TYPE_ACCESS && acl) {
+ ret = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+ if (ret)
+ return ret;
+ }
return __btrfs_set_acl(NULL, inode, acl, type);
}
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c
index aca0d88..cec2569 100644
--- a/fs/ceph/dir.c
+++ b/fs/ceph/dir.c
@@ -292,6 +292,11 @@
if (ret < 0)
err = ret;
dput(last);
+ /* last_name no longer match cache index */
+ if (fi->readdir_cache_idx >= 0) {
+ fi->readdir_cache_idx = -1;
+ fi->dir_release_count = 0;
+ }
}
return err;
}
diff --git a/fs/dcache.c b/fs/dcache.c
index 362396a..7171f0d 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1133,11 +1133,12 @@
LIST_HEAD(dispose);
freed = list_lru_walk(&sb->s_dentry_lru,
- dentry_lru_isolate_shrink, &dispose, UINT_MAX);
+ dentry_lru_isolate_shrink, &dispose, 1024);
this_cpu_sub(nr_dentry_unused, freed);
shrink_dentry_list(&dispose);
- } while (freed > 0);
+ cond_resched();
+ } while (list_lru_count(&sb->s_dentry_lru) > 0);
}
EXPORT_SYMBOL(shrink_dcache_sb);
diff --git a/fs/exec.c b/fs/exec.c
index 26ab263..3e2de29 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -215,8 +215,7 @@
if (write) {
unsigned long size = bprm->vma->vm_end - bprm->vma->vm_start;
- unsigned long ptr_size;
- struct rlimit *rlim;
+ unsigned long ptr_size, limit;
/*
* Since the stack will hold pointers to the strings, we
@@ -245,14 +244,16 @@
return page;
/*
- * Limit to 1/4-th the stack size for the argv+env strings.
+ * Limit to 1/4 of the max stack size or 3/4 of _STK_LIM
+ * (whichever is smaller) for the argv+env strings.
* This ensures that:
* - the remaining binfmt code will not run out of stack space,
* - the program will have a reasonable amount of stack left
* to work from.
*/
- rlim = current->signal->rlim;
- if (size > READ_ONCE(rlim[RLIMIT_STACK].rlim_cur) / 4)
+ limit = _STK_LIM / 4 * 3;
+ limit = min(limit, rlimit(RLIMIT_STACK) / 4);
+ if (size > limit)
goto fail;
}
diff --git a/fs/ext2/acl.c b/fs/ext2/acl.c
index 79dafa7..069c0dc 100644
--- a/fs/ext2/acl.c
+++ b/fs/ext2/acl.c
@@ -175,11 +175,8 @@
return acl;
}
-/*
- * inode->i_mutex: down
- */
-int
-ext2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
+static int
+__ext2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
{
int name_index;
void *value = NULL;
@@ -189,13 +186,6 @@
switch(type) {
case ACL_TYPE_ACCESS:
name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS;
- if (acl) {
- error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
- if (error)
- return error;
- inode->i_ctime = current_time(inode);
- mark_inode_dirty(inode);
- }
break;
case ACL_TYPE_DEFAULT:
@@ -222,6 +212,24 @@
}
/*
+ * inode->i_mutex: down
+ */
+int
+ext2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
+{
+ int error;
+
+ if (type == ACL_TYPE_ACCESS && acl) {
+ error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+ if (error)
+ return error;
+ inode->i_ctime = current_time(inode);
+ mark_inode_dirty(inode);
+ }
+ return __ext2_set_acl(inode, acl, type);
+}
+
+/*
* Initialize the ACLs of a new inode. Called from ext2_new_inode.
*
* dir->i_mutex: down
@@ -238,12 +246,12 @@
return error;
if (default_acl) {
- error = ext2_set_acl(inode, default_acl, ACL_TYPE_DEFAULT);
+ error = __ext2_set_acl(inode, default_acl, ACL_TYPE_DEFAULT);
posix_acl_release(default_acl);
}
if (acl) {
if (!error)
- error = ext2_set_acl(inode, acl, ACL_TYPE_ACCESS);
+ error = __ext2_set_acl(inode, acl, ACL_TYPE_ACCESS);
posix_acl_release(acl);
}
return error;
diff --git a/fs/f2fs/acl.c b/fs/f2fs/acl.c
index 6fe23af..55aa29c 100644
--- a/fs/f2fs/acl.c
+++ b/fs/f2fs/acl.c
@@ -211,7 +211,7 @@
switch (type) {
case ACL_TYPE_ACCESS:
name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS;
- if (acl) {
+ if (acl && !ipage) {
error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
if (error)
return error;
diff --git a/fs/fuse/Makefile b/fs/fuse/Makefile
index 60da84a..5d75cc4 100644
--- a/fs/fuse/Makefile
+++ b/fs/fuse/Makefile
@@ -5,4 +5,4 @@
obj-$(CONFIG_FUSE_FS) += fuse.o
obj-$(CONFIG_CUSE) += cuse.o
-fuse-objs := dev.o dir.o file.o inode.o control.o xattr.o acl.o
+fuse-objs := dev.o dir.o file.o inode.o control.o xattr.o acl.o passthrough.o
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 83511cb..658fa9e 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -7,6 +7,7 @@
*/
#include "fuse_i.h"
+#include "fuse_passthrough.h"
#include <linux/init.h>
#include <linux/module.h>
@@ -550,9 +551,14 @@
args->out.numargs * sizeof(struct fuse_arg));
fuse_request_send(fc, req);
ret = req->out.h.error;
- if (!ret && args->out.argvar) {
- BUG_ON(args->out.numargs != 1);
- ret = req->out.args[0].size;
+ if (!ret) {
+ if (args->out.argvar) {
+ WARN_ON(args->out.numargs != 1);
+ ret = req->out.args[0].size;
+ }
+
+ if (req->passthrough_filp != NULL)
+ args->out.passthrough_filp = req->passthrough_filp;
}
fuse_put_request(fc, req);
@@ -1890,6 +1896,9 @@
}
fuse_copy_finish(cs);
+ fuse_setup_passthrough(fc, req);
+
+
spin_lock(&fpq->lock);
clear_bit(FR_LOCKED, &req->flags);
if (!fpq->connected)
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index fc8ba62..c7c3c96 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -491,6 +491,7 @@
args.out.args[0].value = &outentry;
args.out.args[1].size = sizeof(outopen);
args.out.args[1].value = &outopen;
+ args.out.passthrough_filp = NULL;
err = fuse_simple_request(fc, &args);
if (err)
goto out_free_ff;
@@ -502,6 +503,8 @@
ff->fh = outopen.fh;
ff->nodeid = outentry.nodeid;
ff->open_flags = outopen.open_flags;
+ if (args.out.passthrough_filp != NULL)
+ ff->passthrough_filp = args.out.passthrough_filp;
inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation,
&outentry.attr, entry_attr_timeout(&outentry), 0);
if (!inode) {
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 5ec5870..75c95659 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -7,6 +7,7 @@
*/
#include "fuse_i.h"
+#include "fuse_passthrough.h"
#include <linux/pagemap.h>
#include <linux/slab.h>
@@ -21,8 +22,10 @@
static const struct file_operations fuse_direct_io_file_operations;
static int fuse_send_open(struct fuse_conn *fc, u64 nodeid, struct file *file,
- int opcode, struct fuse_open_out *outargp)
+ int opcode, struct fuse_open_out *outargp,
+ struct file **passthrough_filpp)
{
+ int ret_val;
struct fuse_open_in inarg;
FUSE_ARGS(args);
@@ -38,8 +41,14 @@
args.out.numargs = 1;
args.out.args[0].size = sizeof(*outargp);
args.out.args[0].value = outargp;
+ args.out.passthrough_filp = NULL;
- return fuse_simple_request(fc, &args);
+ ret_val = fuse_simple_request(fc, &args);
+
+ if (args.out.passthrough_filp != NULL)
+ *passthrough_filpp = args.out.passthrough_filp;
+
+ return ret_val;
}
struct fuse_file *fuse_file_alloc(struct fuse_conn *fc)
@@ -50,6 +59,11 @@
if (unlikely(!ff))
return NULL;
+ ff->passthrough_filp = NULL;
+ ff->passthrough_enabled = 0;
+ if (fc->passthrough)
+ ff->passthrough_enabled = 1;
+
ff->fc = fc;
ff->reserved_req = fuse_request_alloc(0);
if (unlikely(!ff->reserved_req)) {
@@ -118,6 +132,7 @@
bool isdir)
{
struct fuse_file *ff;
+ struct file *passthrough_filp = NULL;
int opcode = isdir ? FUSE_OPENDIR : FUSE_OPEN;
ff = fuse_file_alloc(fc);
@@ -130,11 +145,12 @@
struct fuse_open_out outarg;
int err;
- err = fuse_send_open(fc, nodeid, file, opcode, &outarg);
+ err = fuse_send_open(fc, nodeid, file, opcode, &outarg,
+ &(passthrough_filp));
if (!err) {
ff->fh = outarg.fh;
ff->open_flags = outarg.open_flags;
-
+ ff->passthrough_filp = passthrough_filp;
} else if (err != -ENOSYS || isdir) {
fuse_file_free(ff);
return err;
@@ -253,6 +269,8 @@
if (unlikely(!ff))
return;
+ fuse_passthrough_release(ff);
+
req = ff->reserved_req;
fuse_prepare_release(ff, file->f_flags, opcode);
@@ -917,8 +935,10 @@
static ssize_t fuse_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
{
+ ssize_t ret_val;
struct inode *inode = iocb->ki_filp->f_mapping->host;
struct fuse_conn *fc = get_fuse_conn(inode);
+ struct fuse_file *ff = iocb->ki_filp->private_data;
/*
* In auto invalidate mode, always update attributes on read.
@@ -933,7 +953,12 @@
return err;
}
- return generic_file_read_iter(iocb, to);
+ if (ff && ff->passthrough_enabled && ff->passthrough_filp)
+ ret_val = fuse_passthrough_read_iter(iocb, to);
+ else
+ ret_val = generic_file_read_iter(iocb, to);
+
+ return ret_val;
}
static void fuse_write_fill(struct fuse_req *req, struct fuse_file *ff,
@@ -1165,6 +1190,7 @@
static ssize_t fuse_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
{
struct file *file = iocb->ki_filp;
+ struct fuse_file *ff = file->private_data;
struct address_space *mapping = file->f_mapping;
ssize_t written = 0;
ssize_t written_buffered = 0;
@@ -1198,6 +1224,11 @@
if (err)
goto out;
+ if (ff && ff->passthrough_enabled && ff->passthrough_filp) {
+ written = fuse_passthrough_write_iter(iocb, from);
+ goto out;
+ }
+
if (iocb->ki_flags & IOCB_DIRECT) {
loff_t pos = iocb->ki_pos;
written = generic_file_direct_write(iocb, from);
@@ -2069,6 +2100,9 @@
static int fuse_file_mmap(struct file *file, struct vm_area_struct *vma)
{
+ struct fuse_file *ff = file->private_data;
+
+ ff->passthrough_enabled = 0;
if ((vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_MAYWRITE))
fuse_link_write_file(file);
@@ -2079,6 +2113,9 @@
static int fuse_direct_mmap(struct file *file, struct vm_area_struct *vma)
{
+ struct fuse_file *ff = file->private_data;
+
+ ff->passthrough_enabled = 0;
/* Can't provide the coherency needed for MAP_SHARED */
if (vma->vm_flags & VM_MAYSHARE)
return -ENODEV;
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 6b30a12..cc2c82c 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -153,6 +153,10 @@
/** Has flock been performed on this file? */
bool flock:1;
+
+ /* the read write file */
+ struct file *passthrough_filp;
+ bool passthrough_enabled;
};
/** One input argument of a request */
@@ -232,6 +236,7 @@
unsigned argvar:1;
unsigned numargs;
struct fuse_arg args[2];
+ struct file *passthrough_filp;
} out;
};
@@ -382,6 +387,9 @@
/** Request is stolen from fuse_file->reserved_req */
struct file *stolen_file;
+
+ /** fuse passthrough file */
+ struct file *passthrough_filp;
};
struct fuse_iqueue {
@@ -542,6 +550,9 @@
/** handle fs handles killing suid/sgid/cap on write/chown/trunc */
unsigned handle_killpriv:1;
+ /** passthrough IO. */
+ unsigned passthrough:1;
+
/*
* The following bitfields are only for optimization purposes
* and hence races in setting them will not cause malfunction
diff --git a/fs/fuse/fuse_passthrough.h b/fs/fuse/fuse_passthrough.h
new file mode 100644
index 0000000..12429ac
--- /dev/null
+++ b/fs/fuse/fuse_passthrough.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2015-2017, The Linux Foundation. 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 and
+ * only 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 _FS_FUSE_PASSTHROUGH_H
+#define _FS_FUSE_PASSTHROUGH_H
+
+#include "fuse_i.h"
+
+#include <linux/fuse.h>
+#include <linux/file.h>
+
+void fuse_setup_passthrough(struct fuse_conn *fc, struct fuse_req *req);
+
+ssize_t fuse_passthrough_read_iter(struct kiocb *iocb, struct iov_iter *to);
+
+ssize_t fuse_passthrough_write_iter(struct kiocb *iocb, struct iov_iter *from);
+
+void fuse_passthrough_release(struct fuse_file *ff);
+
+#endif /* _FS_FUSE_PASSTHROUGH_H */
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 6fe6a88..f1512c8 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -915,6 +915,12 @@
fc->parallel_dirops = 1;
if (arg->flags & FUSE_HANDLE_KILLPRIV)
fc->handle_killpriv = 1;
+ if (arg->flags & FUSE_PASSTHROUGH) {
+ fc->passthrough = 1;
+ /* Prevent further stacking */
+ fc->sb->s_stack_depth =
+ FILESYSTEM_MAX_STACK_DEPTH;
+ }
if (arg->time_gran && arg->time_gran <= 1000000000)
fc->sb->s_time_gran = arg->time_gran;
if ((arg->flags & FUSE_POSIX_ACL)) {
diff --git a/fs/fuse/passthrough.c b/fs/fuse/passthrough.c
new file mode 100644
index 0000000..c92c40b
--- /dev/null
+++ b/fs/fuse/passthrough.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2015-2017, The Linux Foundation. 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 and
+ * only 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 "fuse_passthrough.h"
+
+#include <linux/aio.h>
+#include <linux/fs_stack.h>
+
+void fuse_setup_passthrough(struct fuse_conn *fc, struct fuse_req *req)
+{
+ int daemon_fd, fs_stack_depth;
+ unsigned int open_out_index;
+ struct file *passthrough_filp;
+ struct inode *passthrough_inode;
+ struct super_block *passthrough_sb;
+ struct fuse_open_out *open_out;
+
+ req->passthrough_filp = NULL;
+
+ if (!(fc->passthrough))
+ return;
+
+ if ((req->in.h.opcode != FUSE_OPEN) &&
+ (req->in.h.opcode != FUSE_CREATE))
+ return;
+
+ open_out_index = req->in.numargs - 1;
+
+ WARN_ON(open_out_index != 0 && open_out_index != 1);
+ WARN_ON(req->out.args[open_out_index].size != sizeof(*open_out));
+
+ open_out = req->out.args[open_out_index].value;
+
+ daemon_fd = (int)open_out->passthrough_fd;
+ if (daemon_fd < 0)
+ return;
+
+ passthrough_filp = fget_raw(daemon_fd);
+ if (!passthrough_filp)
+ return;
+
+ passthrough_inode = file_inode(passthrough_filp);
+ passthrough_sb = passthrough_inode->i_sb;
+ fs_stack_depth = passthrough_sb->s_stack_depth + 1;
+
+ /* If we reached the stacking limit go through regular io */
+ if (fs_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) {
+ /* Release the passthrough file. */
+ fput(passthrough_filp);
+ pr_err("FUSE: maximum fs stacking depth exceeded, cannot use passthrough for this file\n");
+ return;
+ }
+ req->passthrough_filp = passthrough_filp;
+}
+
+
+static ssize_t fuse_passthrough_read_write_iter(struct kiocb *iocb,
+ struct iov_iter *iter, int do_write)
+{
+ ssize_t ret_val;
+ struct fuse_file *ff;
+ struct file *fuse_file, *passthrough_filp;
+ struct inode *fuse_inode, *passthrough_inode;
+ struct fuse_conn *fc;
+
+ ff = iocb->ki_filp->private_data;
+ fuse_file = iocb->ki_filp;
+ passthrough_filp = ff->passthrough_filp;
+ fc = ff->fc;
+
+ /* lock passthrough file to prevent it from being released */
+ get_file(passthrough_filp);
+ iocb->ki_filp = passthrough_filp;
+ fuse_inode = fuse_file->f_path.dentry->d_inode;
+ passthrough_inode = file_inode(passthrough_filp);
+
+ if (do_write) {
+ if (!passthrough_filp->f_op->write_iter)
+ return -EIO;
+
+ ret_val = passthrough_filp->f_op->write_iter(iocb, iter);
+
+ if (ret_val >= 0 || ret_val == -EIOCBQUEUED) {
+ spin_lock(&fc->lock);
+ fsstack_copy_inode_size(fuse_inode, passthrough_inode);
+ spin_unlock(&fc->lock);
+ fsstack_copy_attr_times(fuse_inode, passthrough_inode);
+ }
+ } else {
+ if (!passthrough_filp->f_op->read_iter)
+ return -EIO;
+
+ ret_val = passthrough_filp->f_op->read_iter(iocb, iter);
+ if (ret_val >= 0 || ret_val == -EIOCBQUEUED)
+ fsstack_copy_attr_atime(fuse_inode, passthrough_inode);
+ }
+
+ iocb->ki_filp = fuse_file;
+
+ /* unlock passthrough file */
+ fput(passthrough_filp);
+
+ return ret_val;
+}
+
+ssize_t fuse_passthrough_read_iter(struct kiocb *iocb, struct iov_iter *to)
+{
+ return fuse_passthrough_read_write_iter(iocb, to, 0);
+}
+
+ssize_t fuse_passthrough_write_iter(struct kiocb *iocb, struct iov_iter *from)
+{
+ return fuse_passthrough_read_write_iter(iocb, from, 1);
+}
+
+void fuse_passthrough_release(struct fuse_file *ff)
+{
+ if (!(ff->passthrough_filp))
+ return;
+
+ /* Release the passthrough file. */
+ fput(ff->passthrough_filp);
+ ff->passthrough_filp = NULL;
+}
diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c
index 2524807..6fa5a66 100644
--- a/fs/gfs2/acl.c
+++ b/fs/gfs2/acl.c
@@ -91,8 +91,11 @@
if (type == ACL_TYPE_ACCESS) {
umode_t mode = inode->i_mode;
-
+ struct posix_acl *old_acl = acl;
error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+
+ if (!acl)
+ posix_acl_release(old_acl);
if (error)
return error;
if (mode != inode->i_mode)
diff --git a/fs/hfsplus/posix_acl.c b/fs/hfsplus/posix_acl.c
index 9b92058..6bb5d7c 100644
--- a/fs/hfsplus/posix_acl.c
+++ b/fs/hfsplus/posix_acl.c
@@ -51,8 +51,8 @@
return acl;
}
-int hfsplus_set_posix_acl(struct inode *inode, struct posix_acl *acl,
- int type)
+static int __hfsplus_set_posix_acl(struct inode *inode, struct posix_acl *acl,
+ int type)
{
int err;
char *xattr_name;
@@ -64,12 +64,6 @@
switch (type) {
case ACL_TYPE_ACCESS:
xattr_name = XATTR_NAME_POSIX_ACL_ACCESS;
- if (acl) {
- err = posix_acl_update_mode(inode, &inode->i_mode, &acl);
- if (err)
- return err;
- }
- err = 0;
break;
case ACL_TYPE_DEFAULT:
@@ -105,6 +99,18 @@
return err;
}
+int hfsplus_set_posix_acl(struct inode *inode, struct posix_acl *acl, int type)
+{
+ int err;
+
+ if (type == ACL_TYPE_ACCESS && acl) {
+ err = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+ if (err)
+ return err;
+ }
+ return __hfsplus_set_posix_acl(inode, acl, type);
+}
+
int hfsplus_init_posix_acl(struct inode *inode, struct inode *dir)
{
int err = 0;
@@ -122,15 +128,15 @@
return err;
if (default_acl) {
- err = hfsplus_set_posix_acl(inode, default_acl,
- ACL_TYPE_DEFAULT);
+ err = __hfsplus_set_posix_acl(inode, default_acl,
+ ACL_TYPE_DEFAULT);
posix_acl_release(default_acl);
}
if (acl) {
if (!err)
- err = hfsplus_set_posix_acl(inode, acl,
- ACL_TYPE_ACCESS);
+ err = __hfsplus_set_posix_acl(inode, acl,
+ ACL_TYPE_ACCESS);
posix_acl_release(acl);
}
return err;
diff --git a/fs/mount.h b/fs/mount.h
index d8295f2..3603884 100644
--- a/fs/mount.h
+++ b/fs/mount.h
@@ -58,6 +58,7 @@
struct mnt_namespace *mnt_ns; /* containing namespace */
struct mountpoint *mnt_mp; /* where is it mounted */
struct hlist_node mnt_mp_list; /* list mounts with the same mountpoint */
+ struct list_head mnt_umounting; /* list entry for umount propagation */
#ifdef CONFIG_FSNOTIFY
struct hlist_head mnt_fsnotify_marks;
__u32 mnt_fsnotify_mask;
diff --git a/fs/namespace.c b/fs/namespace.c
index 5147334..7731f77 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -237,6 +237,7 @@
INIT_LIST_HEAD(&mnt->mnt_slave_list);
INIT_LIST_HEAD(&mnt->mnt_slave);
INIT_HLIST_NODE(&mnt->mnt_mp_list);
+ INIT_LIST_HEAD(&mnt->mnt_umounting);
#ifdef CONFIG_FSNOTIFY
INIT_HLIST_HEAD(&mnt->mnt_fsnotify_marks);
#endif
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 53e02b8..d04ec381 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -1167,11 +1167,13 @@
/* Force a full look up iff the parent directory has changed */
if (!nfs_is_exclusive_create(dir, flags) &&
nfs_check_verifier(dir, dentry, flags & LOOKUP_RCU)) {
-
- if (nfs_lookup_verify_inode(inode, flags)) {
+ error = nfs_lookup_verify_inode(inode, flags);
+ if (error) {
if (flags & LOOKUP_RCU)
return -ECHILD;
- goto out_zap_parent;
+ if (error == -ESTALE)
+ goto out_zap_parent;
+ goto out_error;
}
goto out_valid;
}
@@ -1195,8 +1197,10 @@
trace_nfs_lookup_revalidate_enter(dir, dentry, flags);
error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, label);
trace_nfs_lookup_revalidate_exit(dir, dentry, flags, error);
- if (error)
+ if (error == -ESTALE || error == -ENOENT)
goto out_bad;
+ if (error)
+ goto out_error;
if (nfs_compare_fh(NFS_FH(inode), fhandle))
goto out_bad;
if ((error = nfs_refresh_inode(inode, fattr)) != 0)
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index bf4ec5e..76ae256 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -1278,9 +1278,9 @@
return 0;
/* Has the inode gone and changed behind our back? */
if ((fattr->valid & NFS_ATTR_FATTR_FILEID) && nfsi->fileid != fattr->fileid)
- return -EIO;
+ return -ESTALE;
if ((fattr->valid & NFS_ATTR_FATTR_TYPE) && (inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT))
- return -EIO;
+ return -ESTALE;
if (!nfs_file_has_buffered_writers(nfsi)) {
/* Verify a few of the more important attributes */
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index 0e10085..e7c8ac4 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -1146,6 +1146,7 @@
unsigned int stacklen = 0;
unsigned int i;
bool remote = false;
+ struct cred *cred;
int err;
err = -ENOMEM;
@@ -1309,10 +1310,14 @@
else
sb->s_d_op = &ovl_dentry_operations;
- ufs->creator_cred = prepare_creds();
- if (!ufs->creator_cred)
+ err = -ENOMEM;
+ ufs->creator_cred = cred = prepare_creds();
+ if (!cred)
goto out_put_lower_mnt;
+ /* Never override disk quota limits or use reserved space */
+ cap_lower(cred->cap_effective, CAP_SYS_RESOURCE);
+
err = -ENOMEM;
oe = ovl_alloc_entry(numlower);
if (!oe)
diff --git a/fs/pnode.c b/fs/pnode.c
index e4e428d..ddb846f 100644
--- a/fs/pnode.c
+++ b/fs/pnode.c
@@ -24,6 +24,11 @@
return list_entry(p->mnt_slave_list.next, struct mount, mnt_slave);
}
+static inline struct mount *last_slave(struct mount *p)
+{
+ return list_entry(p->mnt_slave_list.prev, struct mount, mnt_slave);
+}
+
static inline struct mount *next_slave(struct mount *p)
{
return list_entry(p->mnt_slave.next, struct mount, mnt_slave);
@@ -164,6 +169,19 @@
}
}
+static struct mount *skip_propagation_subtree(struct mount *m,
+ struct mount *origin)
+{
+ /*
+ * Advance m such that propagation_next will not return
+ * the slaves of m.
+ */
+ if (!IS_MNT_NEW(m) && !list_empty(&m->mnt_slave_list))
+ m = last_slave(m);
+
+ return m;
+}
+
static struct mount *next_group(struct mount *m, struct mount *origin)
{
while (1) {
@@ -415,68 +433,107 @@
}
}
-/*
- * Mark all mounts that the MNT_LOCKED logic will allow to be unmounted.
- */
-static void mark_umount_candidates(struct mount *mnt)
+static void umount_one(struct mount *mnt, struct list_head *to_umount)
{
- struct mount *parent = mnt->mnt_parent;
- struct mount *m;
-
- BUG_ON(parent == mnt);
-
- for (m = propagation_next(parent, parent); m;
- m = propagation_next(m, parent)) {
- struct mount *child = __lookup_mnt(&m->mnt,
- mnt->mnt_mountpoint);
- if (!child || (child->mnt.mnt_flags & MNT_UMOUNT))
- continue;
- if (!IS_MNT_LOCKED(child) || IS_MNT_MARKED(m)) {
- SET_MNT_MARK(child);
- }
- }
+ CLEAR_MNT_MARK(mnt);
+ mnt->mnt.mnt_flags |= MNT_UMOUNT;
+ list_del_init(&mnt->mnt_child);
+ list_del_init(&mnt->mnt_umounting);
+ list_move_tail(&mnt->mnt_list, to_umount);
}
/*
* NOTE: unmounting 'mnt' naturally propagates to all other mounts its
* parent propagates to.
*/
-static void __propagate_umount(struct mount *mnt)
+static bool __propagate_umount(struct mount *mnt,
+ struct list_head *to_umount,
+ struct list_head *to_restore)
{
- struct mount *parent = mnt->mnt_parent;
- struct mount *m;
+ bool progress = false;
+ struct mount *child;
- BUG_ON(parent == mnt);
+ /*
+ * The state of the parent won't change if this mount is
+ * already unmounted or marked as without children.
+ */
+ if (mnt->mnt.mnt_flags & (MNT_UMOUNT | MNT_MARKED))
+ goto out;
- for (m = propagation_next(parent, parent); m;
- m = propagation_next(m, parent)) {
- struct mount *topper;
- struct mount *child = __lookup_mnt(&m->mnt,
- mnt->mnt_mountpoint);
- /*
- * umount the child only if the child has no children
- * and the child is marked safe to unmount.
- */
- if (!child || !IS_MNT_MARKED(child))
+ /* Verify topper is the only grandchild that has not been
+ * speculatively unmounted.
+ */
+ list_for_each_entry(child, &mnt->mnt_mounts, mnt_child) {
+ if (child->mnt_mountpoint == mnt->mnt.mnt_root)
continue;
- CLEAR_MNT_MARK(child);
+ if (!list_empty(&child->mnt_umounting) && IS_MNT_MARKED(child))
+ continue;
+ /* Found a mounted child */
+ goto children;
+ }
- /* If there is exactly one mount covering all of child
- * replace child with that mount.
- */
- topper = find_topper(child);
- if (topper)
- mnt_change_mountpoint(child->mnt_parent, child->mnt_mp,
- topper);
+ /* Mark mounts that can be unmounted if not locked */
+ SET_MNT_MARK(mnt);
+ progress = true;
- if (list_empty(&child->mnt_mounts)) {
- list_del_init(&child->mnt_child);
- child->mnt.mnt_flags |= MNT_UMOUNT;
- list_move_tail(&child->mnt_list, &mnt->mnt_list);
+ /* If a mount is without children and not locked umount it. */
+ if (!IS_MNT_LOCKED(mnt)) {
+ umount_one(mnt, to_umount);
+ } else {
+children:
+ list_move_tail(&mnt->mnt_umounting, to_restore);
+ }
+out:
+ return progress;
+}
+
+static void umount_list(struct list_head *to_umount,
+ struct list_head *to_restore)
+{
+ struct mount *mnt, *child, *tmp;
+ list_for_each_entry(mnt, to_umount, mnt_list) {
+ list_for_each_entry_safe(child, tmp, &mnt->mnt_mounts, mnt_child) {
+ /* topper? */
+ if (child->mnt_mountpoint == mnt->mnt.mnt_root)
+ list_move_tail(&child->mnt_umounting, to_restore);
+ else
+ umount_one(child, to_umount);
}
}
}
+static void restore_mounts(struct list_head *to_restore)
+{
+ /* Restore mounts to a clean working state */
+ while (!list_empty(to_restore)) {
+ struct mount *mnt, *parent;
+ struct mountpoint *mp;
+
+ mnt = list_first_entry(to_restore, struct mount, mnt_umounting);
+ CLEAR_MNT_MARK(mnt);
+ list_del_init(&mnt->mnt_umounting);
+
+ /* Should this mount be reparented? */
+ mp = mnt->mnt_mp;
+ parent = mnt->mnt_parent;
+ while (parent->mnt.mnt_flags & MNT_UMOUNT) {
+ mp = parent->mnt_mp;
+ parent = parent->mnt_parent;
+ }
+ if (parent != mnt->mnt_parent)
+ mnt_change_mountpoint(parent, mp, mnt);
+ }
+}
+
+static void cleanup_umount_visitations(struct list_head *visited)
+{
+ while (!list_empty(visited)) {
+ struct mount *mnt =
+ list_first_entry(visited, struct mount, mnt_umounting);
+ list_del_init(&mnt->mnt_umounting);
+ }
+}
+
/*
* collect all mounts that receive propagation from the mount in @list,
* and return these additional mounts in the same list.
@@ -487,12 +544,69 @@
int propagate_umount(struct list_head *list)
{
struct mount *mnt;
+ LIST_HEAD(to_restore);
+ LIST_HEAD(to_umount);
+ LIST_HEAD(visited);
- list_for_each_entry_reverse(mnt, list, mnt_list)
- mark_umount_candidates(mnt);
+ /* Find candidates for unmounting */
+ list_for_each_entry_reverse(mnt, list, mnt_list) {
+ struct mount *parent = mnt->mnt_parent;
+ struct mount *m;
- list_for_each_entry(mnt, list, mnt_list)
- __propagate_umount(mnt);
+ /*
+ * If this mount has already been visited it is known that it's
+ * entire peer group and all of their slaves in the propagation
+ * tree for the mountpoint has already been visited and there is
+ * no need to visit them again.
+ */
+ if (!list_empty(&mnt->mnt_umounting))
+ continue;
+
+ list_add_tail(&mnt->mnt_umounting, &visited);
+ for (m = propagation_next(parent, parent); m;
+ m = propagation_next(m, parent)) {
+ struct mount *child = __lookup_mnt(&m->mnt,
+ mnt->mnt_mountpoint);
+ if (!child)
+ continue;
+
+ if (!list_empty(&child->mnt_umounting)) {
+ /*
+ * If the child has already been visited it is
+ * know that it's entire peer group and all of
+ * their slaves in the propgation tree for the
+ * mountpoint has already been visited and there
+ * is no need to visit this subtree again.
+ */
+ m = skip_propagation_subtree(m, parent);
+ continue;
+ } else if (child->mnt.mnt_flags & MNT_UMOUNT) {
+ /*
+ * We have come accross an partially unmounted
+ * mount in list that has not been visited yet.
+ * Remember it has been visited and continue
+ * about our merry way.
+ */
+ list_add_tail(&child->mnt_umounting, &visited);
+ continue;
+ }
+
+ /* Check the child and parents while progress is made */
+ while (__propagate_umount(child,
+ &to_umount, &to_restore)) {
+ /* Is the parent a umount candidate? */
+ child = child->mnt_parent;
+ if (list_empty(&child->mnt_umounting))
+ break;
+ }
+ }
+ }
+
+ umount_list(&to_umount, &to_restore);
+ restore_mounts(&to_restore);
+ cleanup_umount_visitations(&visited);
+ list_splice_tail(&to_umount, list);
+
return 0;
}
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 71b62b8..c585e7e 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -1617,6 +1617,9 @@
if (vma->vm_file)
continue;
+ if (vma->vm_flags & VM_LOCKED)
+ continue;
+
if (!rp.nr_to_reclaim)
break;
diff --git a/fs/reiserfs/xattr_acl.c b/fs/reiserfs/xattr_acl.c
index 3d2256a..d92a1dc 100644
--- a/fs/reiserfs/xattr_acl.c
+++ b/fs/reiserfs/xattr_acl.c
@@ -37,7 +37,14 @@
error = journal_begin(&th, inode->i_sb, jcreate_blocks);
reiserfs_write_unlock(inode->i_sb);
if (error == 0) {
+ if (type == ACL_TYPE_ACCESS && acl) {
+ error = posix_acl_update_mode(inode, &inode->i_mode,
+ &acl);
+ if (error)
+ goto unlock;
+ }
error = __reiserfs_set_acl(&th, inode, type, acl);
+unlock:
reiserfs_write_lock(inode->i_sb);
error2 = journal_end(&th);
reiserfs_write_unlock(inode->i_sb);
@@ -241,11 +248,6 @@
switch (type) {
case ACL_TYPE_ACCESS:
name = XATTR_NAME_POSIX_ACL_ACCESS;
- if (acl) {
- error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
- if (error)
- return error;
- }
break;
case ACL_TYPE_DEFAULT:
name = XATTR_NAME_POSIX_ACL_DEFAULT;
diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c
index d48da41..683b492 100644
--- a/fs/sdcardfs/inode.c
+++ b/fs/sdcardfs/inode.c
@@ -773,13 +773,9 @@
* afterwards in the other cases: we fsstack_copy_inode_size from
* the lower level.
*/
- if (current->mm)
- down_write(¤t->mm->mmap_sem);
if (ia->ia_valid & ATTR_SIZE) {
err = inode_newsize_ok(&tmp, ia->ia_size);
if (err) {
- if (current->mm)
- up_write(¤t->mm->mmap_sem);
goto out;
}
truncate_setsize(inode, ia->ia_size);
@@ -802,8 +798,6 @@
err = notify_change2(lower_mnt, lower_dentry, &lower_ia, /* note: lower_ia */
NULL);
inode_unlock(d_inode(lower_dentry));
- if (current->mm)
- up_write(¤t->mm->mmap_sem);
if (err)
goto out;
diff --git a/fs/ubifs/journal.c b/fs/ubifs/journal.c
index 91bc76dc..7d764e3 100644
--- a/fs/ubifs/journal.c
+++ b/fs/ubifs/journal.c
@@ -576,7 +576,7 @@
/* Make sure to also account for extended attributes */
len += host_ui->data_len;
- dent = kmalloc(len, GFP_NOFS);
+ dent = kzalloc(len, GFP_NOFS);
if (!dent)
return -ENOMEM;
@@ -952,7 +952,7 @@
if (twoparents)
len += plen;
- dent1 = kmalloc(len, GFP_NOFS);
+ dent1 = kzalloc(len, GFP_NOFS);
if (!dent1)
return -ENOMEM;
@@ -1102,7 +1102,7 @@
len = aligned_dlen1 + aligned_dlen2 + ALIGN(ilen, 8) + ALIGN(plen, 8);
if (move)
len += plen;
- dent = kmalloc(len, GFP_NOFS);
+ dent = kzalloc(len, GFP_NOFS);
if (!dent)
return -ENOMEM;
@@ -1466,7 +1466,7 @@
hlen = host_ui->data_len + UBIFS_INO_NODE_SZ;
len = aligned_xlen + UBIFS_INO_NODE_SZ + ALIGN(hlen, 8);
- xent = kmalloc(len, GFP_NOFS);
+ xent = kzalloc(len, GFP_NOFS);
if (!xent)
return -ENOMEM;
@@ -1573,7 +1573,7 @@
aligned_len1 = ALIGN(len1, 8);
aligned_len = aligned_len1 + ALIGN(len2, 8);
- ino = kmalloc(aligned_len, GFP_NOFS);
+ ino = kzalloc(aligned_len, GFP_NOFS);
if (!ino)
return -ENOMEM;
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index 129b18a..0359435 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -1243,8 +1243,8 @@
return err;
}
set_size:
- truncate_setsize(inode, newsize);
up_write(&iinfo->i_data_sem);
+ truncate_setsize(inode, newsize);
} else {
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
down_write(&iinfo->i_data_sem);
@@ -1261,9 +1261,9 @@
udf_get_block);
if (err)
return err;
+ truncate_setsize(inode, newsize);
down_write(&iinfo->i_data_sem);
udf_clear_extent_cache(inode);
- truncate_setsize(inode, newsize);
udf_truncate_extents(inode);
up_write(&iinfo->i_data_sem);
}
diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
index b468e04..b2d55a3 100644
--- a/fs/xfs/xfs_acl.c
+++ b/fs/xfs/xfs_acl.c
@@ -170,8 +170,8 @@
return acl;
}
-STATIC int
-__xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
+int
+__xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
{
struct xfs_inode *ip = XFS_I(inode);
unsigned char *ea_name;
@@ -258,8 +258,10 @@
if (type == ACL_TYPE_ACCESS) {
umode_t mode;
-
+ struct posix_acl *old_acl = acl;
error = posix_acl_update_mode(inode, &mode, &acl);
+ if (!acl)
+ posix_acl_release(old_acl);
if (error)
return error;
error = xfs_set_mode(inode, mode);
@@ -268,5 +270,5 @@
}
set_acl:
- return __xfs_set_acl(inode, type, acl);
+ return __xfs_set_acl(inode, acl, type);
}
diff --git a/fs/xfs/xfs_acl.h b/fs/xfs/xfs_acl.h
index 286fa89..0432731 100644
--- a/fs/xfs/xfs_acl.h
+++ b/fs/xfs/xfs_acl.h
@@ -24,6 +24,7 @@
#ifdef CONFIG_XFS_POSIX_ACL
extern struct posix_acl *xfs_get_acl(struct inode *inode, int type);
extern int xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type);
+extern int __xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type);
#else
static inline struct posix_acl *xfs_get_acl(struct inode *inode, int type)
{
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index f5e0f60..a1247c3 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -190,12 +190,12 @@
#ifdef CONFIG_XFS_POSIX_ACL
if (default_acl) {
- error = xfs_set_acl(inode, default_acl, ACL_TYPE_DEFAULT);
+ error = __xfs_set_acl(inode, default_acl, ACL_TYPE_DEFAULT);
if (error)
goto out_cleanup_inode;
}
if (acl) {
- error = xfs_set_acl(inode, acl, ACL_TYPE_ACCESS);
+ error = __xfs_set_acl(inode, acl, ACL_TYPE_ACCESS);
if (error)
goto out_cleanup_inode;
}
diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h
index 2a79882..55b1a0e 100644
--- a/include/drm/drm_dp_helper.h
+++ b/include/drm/drm_dp_helper.h
@@ -228,6 +228,7 @@
# define DP_LINK_BW_1_62 0x06
# define DP_LINK_BW_2_7 0x0a
# define DP_LINK_BW_5_4 0x14 /* 1.2 */
+# define DP_LINK_BW_8_1 0x1e
#define DP_LANE_COUNT_SET 0x101
# define DP_LANE_COUNT_MASK 0x0f
diff --git a/include/dt-bindings/clock/mdss-10nm-pll-clk.h b/include/dt-bindings/clock/mdss-10nm-pll-clk.h
index 75ddcfa..8108c98 100644
--- a/include/dt-bindings/clock/mdss-10nm-pll-clk.h
+++ b/include/dt-bindings/clock/mdss-10nm-pll-clk.h
@@ -17,23 +17,25 @@
/* DSI PLL clocks */
#define VCO_CLK_0 0
-#define BITCLK_SRC_0_CLK 1
-#define BYTECLK_SRC_0_CLK 2
-#define POST_BIT_DIV_0_CLK 3
-#define POST_VCO_DIV_0_CLK 4
-#define BYTECLK_MUX_0_CLK 5
-#define PCLK_SRC_MUX_0_CLK 6
-#define PCLK_SRC_0_CLK 7
-#define PCLK_MUX_0_CLK 8
-#define VCO_CLK_1 9
-#define BITCLK_SRC_1_CLK 10
-#define BYTECLK_SRC_1_CLK 11
-#define POST_BIT_DIV_1_CLK 12
-#define POST_VCO_DIV_1_CLK 13
-#define BYTECLK_MUX_1_CLK 14
-#define PCLK_SRC_MUX_1_CLK 15
-#define PCLK_SRC_1_CLK 16
-#define PCLK_MUX_1_CLK 17
+#define PLL_OUT_DIV_0_CLK 1
+#define BITCLK_SRC_0_CLK 2
+#define BYTECLK_SRC_0_CLK 3
+#define POST_BIT_DIV_0_CLK 4
+#define POST_VCO_DIV_0_CLK 5
+#define BYTECLK_MUX_0_CLK 6
+#define PCLK_SRC_MUX_0_CLK 7
+#define PCLK_SRC_0_CLK 8
+#define PCLK_MUX_0_CLK 9
+#define VCO_CLK_1 10
+#define PLL_OUT_DIV_1_CLK 11
+#define BITCLK_SRC_1_CLK 12
+#define BYTECLK_SRC_1_CLK 13
+#define POST_BIT_DIV_1_CLK 14
+#define POST_VCO_DIV_1_CLK 15
+#define BYTECLK_MUX_1_CLK 16
+#define PCLK_SRC_MUX_1_CLK 17
+#define PCLK_SRC_1_CLK 18
+#define PCLK_MUX_1_CLK 19
/* DP PLL clocks */
#define DP_VCO_CLK 0
diff --git a/include/dt-bindings/clock/qcom,aop-qmp.h b/include/dt-bindings/clock/qcom,aop-qmp.h
index b88dc36..7898c47 100644
--- a/include/dt-bindings/clock/qcom,aop-qmp.h
+++ b/include/dt-bindings/clock/qcom,aop-qmp.h
@@ -25,5 +25,5 @@
/* clocks id */
#define QDSS_CLK 0
-
+#define QDSS_AO_CLK 1
#endif
diff --git a/include/dt-bindings/clock/qcom,gcc-sdm845.h b/include/dt-bindings/clock/qcom,gcc-sdm845.h
index 3d58645..339d470 100644
--- a/include/dt-bindings/clock/qcom,gcc-sdm845.h
+++ b/include/dt-bindings/clock/qcom,gcc-sdm845.h
@@ -211,6 +211,7 @@
#define GCC_VS_CTRL_CLK 193
#define GCC_VS_CTRL_CLK_SRC 194
#define GCC_VSENSOR_CLK_SRC 195
+#define GPLL4 196
/* GCC reset clocks */
#define GCC_MMSS_BCR 0
diff --git a/include/dt-bindings/clock/qcom,gpucc-sdm845.h b/include/dt-bindings/clock/qcom,gpucc-sdm845.h
index 323beaf..74a742a 100644
--- a/include/dt-bindings/clock/qcom,gpucc-sdm845.h
+++ b/include/dt-bindings/clock/qcom,gpucc-sdm845.h
@@ -44,6 +44,7 @@
#define GPU_CC_GMU_CLK_SRC 26
#define GPU_CC_CX_GFX3D_CLK 27
#define GPU_CC_CX_GFX3D_SLV_CLK 28
+#define GPU_CC_PLL0 29
/* GPUCC reset clock registers */
#define GPUCC_GPU_CC_ACD_BCR 0
@@ -55,7 +56,6 @@
#define GPUCC_GPU_CC_XO_BCR 6
/* GFX3D clock registers */
-#define GPU_CC_PLL0 0
#define GPU_CC_PLL0_OUT_EVEN 1
#define GPU_CC_GX_GFX3D_CLK_SRC 2
#define GPU_CC_GX_GFX3D_CLK 3
diff --git a/include/linux/cma.h b/include/linux/cma.h
index 29f9e77..d04f178 100644
--- a/include/linux/cma.h
+++ b/include/linux/cma.h
@@ -18,13 +18,15 @@
extern unsigned long totalcma_pages;
extern phys_addr_t cma_get_base(const struct cma *cma);
extern unsigned long cma_get_size(const struct cma *cma);
+extern const char *cma_get_name(const struct cma *cma);
extern int __init cma_declare_contiguous(phys_addr_t base,
phys_addr_t size, phys_addr_t limit,
phys_addr_t alignment, unsigned int order_per_bit,
- bool fixed, struct cma **res_cma);
+ bool fixed, const char *name, struct cma **res_cma);
extern int cma_init_reserved_mem(phys_addr_t base, phys_addr_t size,
unsigned int order_per_bit,
+ const char *name,
struct cma **res_cma);
extern struct page *cma_alloc(struct cma *cma, size_t count, unsigned int align);
extern bool cma_release(struct cma *cma, const struct page *pages, unsigned int count);
diff --git a/include/linux/coresight.h b/include/linux/coresight.h
index 0538291..10842bb 100644
--- a/include/linux/coresight.h
+++ b/include/linux/coresight.h
@@ -266,9 +266,13 @@
#ifdef CONFIG_OF
extern struct coresight_platform_data *of_get_coresight_platform_data(
struct device *dev, struct device_node *node);
+extern struct coresight_cti_data *of_get_coresight_cti_data(
+ struct device *dev, struct device_node *node);
#else
static inline struct coresight_platform_data *of_get_coresight_platform_data(
struct device *dev, struct device_node *node) { return NULL; }
+static inlint struct coresight_cti_data *of_get_coresight_cti_data(
+ struct device *dev, struct device_node *node) { return NULL; }
#endif
#ifdef CONFIG_PID_NS
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
index 9f93d18..edf88bd 100644
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -40,6 +40,7 @@
CPUHP_SLAB_PREPARE,
CPUHP_MD_RAID5_PREPARE,
CPUHP_RCUTREE_PREP,
+ CPUHP_CORE_CTL_ISOLATION_DEAD,
CPUHP_CPUIDLE_COUPLED_PREPARE,
CPUHP_POWERPC_PMAC_PREPARE,
CPUHP_POWERPC_MMU_CTX_PREPARE,
diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h
index 4fbc62e..b49f866 100644
--- a/include/linux/cpumask.h
+++ b/include/linux/cpumask.h
@@ -251,6 +251,23 @@
(cpu) = cpumask_next_zero((cpu), (mask)), \
(cpu) < nr_cpu_ids;)
+extern int cpumask_next_wrap(int n, const struct cpumask *mask, int start, bool wrap);
+
+/**
+ * for_each_cpu_wrap - iterate over every cpu in a mask, starting at a specified location
+ * @cpu: the (optionally unsigned) integer iterator
+ * @mask: the cpumask poiter
+ * @start: the start location
+ *
+ * The implementation does not assume any bit in @mask is set (including @start).
+ *
+ * After the loop, cpu is >= nr_cpu_ids.
+ */
+#define for_each_cpu_wrap(cpu, mask, start) \
+ for ((cpu) = cpumask_next_wrap((start)-1, (mask), (start), false); \
+ (cpu) < nr_cpumask_bits; \
+ (cpu) = cpumask_next_wrap((cpu), (mask), (start), true))
+
/**
* for_each_cpu_and - iterate over every cpu in both masks
* @cpu: the (optionally unsigned) integer iterator
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index 1731c3a..95fe239 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -65,6 +65,7 @@
#define DIAG_IOCTL_PERIPHERAL_BUF_DRAIN 36
#define DIAG_IOCTL_REGISTER_CALLBACK 37
#define DIAG_IOCTL_HDLC_TOGGLE 38
+#define DIAG_IOCTL_QUERY_PD_LOGGING 39
/* PC Tools IDs */
#define APQ8060_TOOLS_ID 4062
diff --git a/include/linux/hdcp_qseecom.h b/include/linux/hdcp_qseecom.h
new file mode 100644
index 0000000..20f5cba
--- /dev/null
+++ b/include/linux/hdcp_qseecom.h
@@ -0,0 +1,224 @@
+/* Copyright (c) 2015-2017, The Linux Foundation. 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 and
+ * only 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 __HDCP_QSEECOM_H
+#define __HDCP_QSEECOM_H
+#include <linux/types.h>
+
+#define HDCP_MAX_MESSAGE_PARTS 4
+
+/**
+ * enum hdcp_lib_wakeup_cmd - commands for interacting with HDCP driver
+ * @HDCP_LIB_WKUP_CMD_INVALID: initialization value
+ * @HDCP_LIB_WKUP_CMD_START: start authentication
+ * @HDCP_LIB_WKUP_CMD_STOP: stop authentication
+ * @HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS: sending message to sink succeeded
+ * @HDCP_LIB_WKUP_CMD_MSG_SEND_FAILED: sending message to sink failed
+ * @HDCP_LIB_WKUP_CMD_MSG_RECV_SUCCESS: receiving message from sink succeeded
+ * @HDCP_LIB_WKUP_CMD_MSG_RECV_FAILED: receiving message from sink failed
+ * @HDCP_LIB_WKUP_CMD_MSG_RECV_TIMEOUT: receiving message from sink timed out
+ * @HDCP_LIB_WKUP_CMD_QUERY_STREAM_TYPE: start content stream processing
+ * @HDCP_LIB_WKUP_CMD_LINK_FAILED: link failure notification
+ */
+enum hdcp_lib_wakeup_cmd {
+ HDCP_LIB_WKUP_CMD_INVALID,
+ HDCP_LIB_WKUP_CMD_START,
+ HDCP_LIB_WKUP_CMD_STOP,
+ HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS,
+ HDCP_LIB_WKUP_CMD_MSG_SEND_FAILED,
+ HDCP_LIB_WKUP_CMD_MSG_RECV_SUCCESS,
+ HDCP_LIB_WKUP_CMD_MSG_RECV_FAILED,
+ HDCP_LIB_WKUP_CMD_MSG_RECV_TIMEOUT,
+ HDCP_LIB_WKUP_CMD_QUERY_STREAM_TYPE,
+ HDCP_LIB_WKUP_CMD_LINK_FAILED,
+};
+
+/**
+ * enum hdcp_wakeup_cmd - commands for interacting with display transport layer
+ * @HDCP_WKUP_CMD_INVALID: initialization value
+ * @HDCP_WKUP_CMD_SEND_MESSAGE: send message to sink
+ * @HDCP_WKUP_CMD_RECV_MESSAGE: receive message from sink
+ * @HDCP_WKUP_CMD_STATUS_SUCCESS: successfully communicated with TrustZone
+ * @HDCP_WKUP_CMD_STATUS_FAILED: failed to communicate with TrustZone
+ * @HDCP_WKUP_CMD_LINK_POLL: poll the HDCP link
+ * @HDCP_WKUP_CMD_AUTHENTICATE: start authentication
+ */
+enum hdcp_wakeup_cmd {
+ HDCP_WKUP_CMD_INVALID,
+ HDCP_WKUP_CMD_SEND_MESSAGE,
+ HDCP_WKUP_CMD_RECV_MESSAGE,
+ HDCP_WKUP_CMD_STATUS_SUCCESS,
+ HDCP_WKUP_CMD_STATUS_FAILED,
+ HDCP_WKUP_CMD_LINK_POLL,
+ HDCP_WKUP_CMD_AUTHENTICATE
+};
+
+/**
+ * struct hdcp_lib_wakeup_data - command and data send to HDCP driver
+ * @cmd: command type
+ * @context: void pointer to the HDCP driver instance
+ * @recvd_msg_buf: message received from the sink
+ * @recvd_msg_len: length of message received from the sink
+ * @timeout: time out value for timed transactions
+ */
+struct hdcp_lib_wakeup_data {
+ enum hdcp_lib_wakeup_cmd cmd;
+ void *context;
+ char *recvd_msg_buf;
+ uint32_t recvd_msg_len;
+ uint32_t timeout;
+};
+
+/**
+ * struct hdcp_msg_part - a single part of an HDCP 2.2 message
+ * @name: user readable message name
+ * @offset: message part offset
+ * @length message part length
+ */
+struct hdcp_msg_part {
+ char *name;
+ uint32_t offset;
+ uint32_t length;
+};
+
+/**
+ * struct hdcp_msg_data - a full HDCP 2.2 message containing one or more parts
+ * @num_messages: total number of parts in a full message
+ * @messages: array containing num_messages parts
+ * @rx_status: value of rx_status register
+ */
+struct hdcp_msg_data {
+ uint32_t num_messages;
+ struct hdcp_msg_part messages[HDCP_MAX_MESSAGE_PARTS];
+ uint8_t rx_status;
+};
+
+/**
+ * struct hdcp_wakeup_data - command and data sent to display transport layer
+ * @cmd: command type
+ * @context: void pointer to the display transport layer
+ * @send_msg_buf: buffer containing message to be sent to sink
+ * @send_msg_len: length of the message to be sent to sink
+ * @timeout: timeout value for timed transactions
+ * @abort_mask: mask used to determine whether HDCP link is valid
+ * @message_data: a pointer to the message description
+ */
+struct hdcp_wakeup_data {
+ enum hdcp_wakeup_cmd cmd;
+ void *context;
+ char *send_msg_buf;
+ uint32_t send_msg_len;
+ uint32_t timeout;
+ uint8_t abort_mask;
+ const struct hdcp_msg_data *message_data;
+};
+
+static inline char *hdcp_cmd_to_str(uint32_t cmd)
+{
+ switch (cmd) {
+ case HDCP_WKUP_CMD_SEND_MESSAGE:
+ return "HDCP_WKUP_CMD_SEND_MESSAGE";
+ case HDCP_WKUP_CMD_RECV_MESSAGE:
+ return "HDCP_WKUP_CMD_RECV_MESSAGE";
+ case HDCP_WKUP_CMD_STATUS_SUCCESS:
+ return "HDCP_WKUP_CMD_STATUS_SUCCESS";
+ case HDCP_WKUP_CMD_STATUS_FAILED:
+ return "HDCP_WKUP_CMD_STATUS_FAIL";
+ case HDCP_WKUP_CMD_LINK_POLL:
+ return "HDCP_WKUP_CMD_LINK_POLL";
+ case HDCP_WKUP_CMD_AUTHENTICATE:
+ return "HDCP_WKUP_CMD_AUTHENTICATE";
+ default:
+ return "???";
+ }
+}
+
+static inline char *hdcp_lib_cmd_to_str(uint32_t cmd)
+{
+ switch (cmd) {
+ case HDCP_LIB_WKUP_CMD_START:
+ return "HDCP_LIB_WKUP_CMD_START";
+ case HDCP_LIB_WKUP_CMD_STOP:
+ return "HDCP_LIB_WKUP_CMD_STOP";
+ case HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS:
+ return "HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS";
+ case HDCP_LIB_WKUP_CMD_MSG_SEND_FAILED:
+ return "HDCP_LIB_WKUP_CMD_MSG_SEND_FAILED";
+ case HDCP_LIB_WKUP_CMD_MSG_RECV_SUCCESS:
+ return "HDCP_LIB_WKUP_CMD_MSG_RECV_SUCCESS";
+ case HDCP_LIB_WKUP_CMD_MSG_RECV_FAILED:
+ return "HDCP_LIB_WKUP_CMD_MSG_RECV_FAILED";
+ case HDCP_LIB_WKUP_CMD_MSG_RECV_TIMEOUT:
+ return "HDCP_LIB_WKUP_CMD_MSG_RECV_TIMEOUT";
+ case HDCP_LIB_WKUP_CMD_QUERY_STREAM_TYPE:
+ return "HDCP_LIB_WKUP_CMD_QUERY_STREAM_TYPE";
+ case HDCP_LIB_WKUP_CMD_LINK_FAILED:
+ return "HDCP_LIB_WKUP_CMD_LINK_FAILED";
+ default:
+ return "???";
+ }
+}
+
+/**
+ * struct hdcp_txmtr_ops - interface to HDCP Driver
+ * @wakeup: wake the HDCP driver with a new command
+ * @feature_supported: checks for HDCP support on the target device
+ */
+struct hdcp_txmtr_ops {
+ int (*wakeup)(struct hdcp_lib_wakeup_data *data);
+ bool (*feature_supported)(void *phdcpcontext);
+};
+
+/**
+ * struct hdcp_client_ops - call back functions to display transport layer
+ * @wakeup: wake up display transport layer with a new command
+ * @notify_lvl_change notify of encryption level changes
+ */
+struct hdcp_client_ops {
+ int (*wakeup)(struct hdcp_wakeup_data *data);
+ void (*notify_lvl_change)(void *client_ctx, int min_lvl);
+};
+
+/**
+ * enum hdcp_device_type - display interface types
+ * @HDCP_TXMTR_HDMI: HDMI interface
+ * @HDCP_TXMTR_DP: DisplayPort interface
+ */
+enum hdcp_device_type {
+ HDCP_TXMTR_HDMI = 0x8001,
+ HDCP_TXMTR_DP = 0x8002
+};
+
+/**
+ * struct hdcp_register_data - data used in HDCP driver clients' registration
+ * @client_ops: call back functions from the client
+ * @txmtr_ops: HDCP driver interface
+ * @device_type: display interface type of the client
+ * @client_ctx: void pointer to client data object
+ * @hdcp_ctx: void pointer to HDCP driver reference for client use
+ */
+struct hdcp_register_data {
+ struct hdcp_client_ops *client_ops;
+ struct hdcp_txmtr_ops *txmtr_ops;
+ enum hdcp_device_type device_type;
+ void *client_ctx;
+ void **hdcp_ctx;
+};
+
+int hdcp_library_register(struct hdcp_register_data *data);
+void hdcp_library_deregister(void *phdcpcontext);
+bool hdcp1_check_if_supported_load_app(void);
+int hdcp1_set_keys(uint32_t *aksv_msb, uint32_t *aksv_lsb);
+int hdcp1_set_enc(bool enable);
+void hdcp1_cache_repeater_topology(void *hdcp1_cached_tp);
+void hdcp1_notify_topology(void);
+#endif /* __HDCP_QSEECOM_H */
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index a80516f..aa2b4e4 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1576,6 +1576,9 @@
#define WLAN_AUTH_SHARED_KEY 1
#define WLAN_AUTH_FT 2
#define WLAN_AUTH_SAE 3
+#define WLAN_AUTH_FILS_SK 4
+#define WLAN_AUTH_FILS_SK_PFS 5
+#define WLAN_AUTH_FILS_PK 6
#define WLAN_AUTH_LEAP 128
#define WLAN_AUTH_CHALLENGE_LEN 128
@@ -1715,6 +1718,9 @@
WLAN_STATUS_REJECT_DSE_BAND = 96,
WLAN_STATUS_DENIED_WITH_SUGGESTED_BAND_AND_CHANNEL = 99,
WLAN_STATUS_DENIED_DUE_TO_SPECTRUM_MANAGEMENT = 103,
+ /* 802.11ai */
+ WLAN_STATUS_FILS_AUTHENTICATION_FAILURE = 108,
+ WLAN_STATUS_UNKNOWN_AUTHENTICATION_SERVER = 109,
};
@@ -2073,6 +2079,15 @@
#define IEEE80211_GCMP_MIC_LEN 16
#define IEEE80211_GCMP_PN_LEN 6
+#define FILS_NONCE_LEN 16
+#define FILS_MAX_KEK_LEN 64
+
+#define FILS_ERP_MAX_USERNAME_LEN 16
+#define FILS_ERP_MAX_REALM_LEN 253
+#define FILS_ERP_MAX_RRK_LEN 64
+
+#define PMK_MAX_LEN 48
+
/* Public action codes */
enum ieee80211_pub_actioncode {
WLAN_PUB_ACTION_EXT_CHANSW_ANN = 4,
@@ -2296,31 +2311,37 @@
};
-/* cipher suite selectors */
-#define WLAN_CIPHER_SUITE_USE_GROUP 0x000FAC00
-#define WLAN_CIPHER_SUITE_WEP40 0x000FAC01
-#define WLAN_CIPHER_SUITE_TKIP 0x000FAC02
-/* reserved: 0x000FAC03 */
-#define WLAN_CIPHER_SUITE_CCMP 0x000FAC04
-#define WLAN_CIPHER_SUITE_WEP104 0x000FAC05
-#define WLAN_CIPHER_SUITE_AES_CMAC 0x000FAC06
-#define WLAN_CIPHER_SUITE_GCMP 0x000FAC08
-#define WLAN_CIPHER_SUITE_GCMP_256 0x000FAC09
-#define WLAN_CIPHER_SUITE_CCMP_256 0x000FAC0A
-#define WLAN_CIPHER_SUITE_BIP_GMAC_128 0x000FAC0B
-#define WLAN_CIPHER_SUITE_BIP_GMAC_256 0x000FAC0C
-#define WLAN_CIPHER_SUITE_BIP_CMAC_256 0x000FAC0D
+#define SUITE(oui, id) (((oui) << 8) | (id))
-#define WLAN_CIPHER_SUITE_SMS4 0x00147201
+/* cipher suite selectors */
+#define WLAN_CIPHER_SUITE_USE_GROUP SUITE(0x000FAC, 0)
+#define WLAN_CIPHER_SUITE_WEP40 SUITE(0x000FAC, 1)
+#define WLAN_CIPHER_SUITE_TKIP SUITE(0x000FAC, 2)
+/* reserved: SUITE(0x000FAC, 3) */
+#define WLAN_CIPHER_SUITE_CCMP SUITE(0x000FAC, 4)
+#define WLAN_CIPHER_SUITE_WEP104 SUITE(0x000FAC, 5)
+#define WLAN_CIPHER_SUITE_AES_CMAC SUITE(0x000FAC, 6)
+#define WLAN_CIPHER_SUITE_GCMP SUITE(0x000FAC, 8)
+#define WLAN_CIPHER_SUITE_GCMP_256 SUITE(0x000FAC, 9)
+#define WLAN_CIPHER_SUITE_CCMP_256 SUITE(0x000FAC, 10)
+#define WLAN_CIPHER_SUITE_BIP_GMAC_128 SUITE(0x000FAC, 11)
+#define WLAN_CIPHER_SUITE_BIP_GMAC_256 SUITE(0x000FAC, 12)
+#define WLAN_CIPHER_SUITE_BIP_CMAC_256 SUITE(0x000FAC, 13)
+
+#define WLAN_CIPHER_SUITE_SMS4 SUITE(0x001472, 1)
/* AKM suite selectors */
-#define WLAN_AKM_SUITE_8021X 0x000FAC01
-#define WLAN_AKM_SUITE_PSK 0x000FAC02
-#define WLAN_AKM_SUITE_8021X_SHA256 0x000FAC05
-#define WLAN_AKM_SUITE_PSK_SHA256 0x000FAC06
-#define WLAN_AKM_SUITE_TDLS 0x000FAC07
-#define WLAN_AKM_SUITE_SAE 0x000FAC08
-#define WLAN_AKM_SUITE_FT_OVER_SAE 0x000FAC09
+#define WLAN_AKM_SUITE_8021X SUITE(0x000FAC, 1)
+#define WLAN_AKM_SUITE_PSK SUITE(0x000FAC, 2)
+#define WLAN_AKM_SUITE_8021X_SHA256 SUITE(0x000FAC, 5)
+#define WLAN_AKM_SUITE_PSK_SHA256 SUITE(0x000FAC, 6)
+#define WLAN_AKM_SUITE_TDLS SUITE(0x000FAC, 7)
+#define WLAN_AKM_SUITE_SAE SUITE(0x000FAC, 8)
+#define WLAN_AKM_SUITE_FT_OVER_SAE SUITE(0x000FAC, 9)
+#define WLAN_AKM_SUITE_FILS_SHA256 SUITE(0x000FAC, 14)
+#define WLAN_AKM_SUITE_FILS_SHA384 SUITE(0x000FAC, 15)
+#define WLAN_AKM_SUITE_FT_FILS_SHA256 SUITE(0x000FAC, 16)
+#define WLAN_AKM_SUITE_FT_FILS_SHA384 SUITE(0x000FAC, 17)
#define WLAN_MAX_KEY_LEN 32
diff --git a/include/linux/ipa_odu_bridge.h b/include/linux/ipa_odu_bridge.h
index 5d30a97..e7f75b7 100644
--- a/include/linux/ipa_odu_bridge.h
+++ b/include/linux/ipa_odu_bridge.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, The Linux Foundation. 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 and
@@ -39,7 +39,85 @@
u32 ipa_desc_size;
};
-#if defined CONFIG_IPA || defined CONFIG_IPA3
+/**
+ * struct ipa_bridge_init_params - parameters for IPA bridge initialization API
+ *
+ * @info: structure contains initialization information
+ * @wakeup_request: callback to client to indicate there is downlink data
+ * available. Client is expected to call ipa_bridge_resume() to start
+ * receiving data
+ */
+struct ipa_bridge_init_params {
+ struct odu_bridge_params info;
+ void (*wakeup_request)(void *);
+};
+
+#ifdef CONFIG_IPA3
+
+int ipa_bridge_init(struct ipa_bridge_init_params *params, u32 *hdl);
+
+int ipa_bridge_connect(u32 hdl);
+
+int ipa_bridge_set_perf_profile(u32 hdl, u32 bandwidth);
+
+int ipa_bridge_disconnect(u32 hdl);
+
+int ipa_bridge_suspend(u32 hdl);
+
+int ipa_bridge_resume(u32 hdl);
+
+int ipa_bridge_tx_dp(u32 hdl, struct sk_buff *skb,
+ struct ipa_tx_meta *metadata);
+
+int ipa_bridge_cleanup(u32 hdl);
+
+#else
+
+static inline int ipa_bridge_init(struct odu_bridge_params *params, u32 *hdl)
+{
+ return -EPERM;
+}
+
+static inline int ipa_bridge_connect(u32 hdl)
+{
+ return -EPERM;
+}
+
+static inline int ipa_bridge_set_perf_profile(u32 hdl, u32 bandwidth)
+{
+ return -EPERM;
+}
+
+static inline int ipa_bridge_disconnect(u32 hdl)
+{
+ return -EPERM;
+}
+
+static inline int ipa_bridge_suspend(u32 hdl)
+{
+ return -EPERM;
+}
+
+static inline int ipa_bridge_resume(u32 hdl)
+{
+ return -EPERM;
+}
+
+static inline int ipa_bridge_tx_dp(u32 hdl, struct sk_buff *skb,
+struct ipa_tx_meta *metadata)
+{
+ return -EPERM;
+}
+
+static inline int ipa_bridge_cleanup(u32 hdl)
+{
+ return -EPERM;
+}
+
+#endif /* CONFIG_IPA3 */
+
+/* Below API is deprecated. Please use the API above */
+# if defined CONFIG_IPA || defined CONFIG_IPA3
int odu_bridge_init(struct odu_bridge_params *params);
diff --git a/include/linux/ipc_router.h b/include/linux/ipc_router.h
index 767551e..c18290f 100644
--- a/include/linux/ipc_router.h
+++ b/include/linux/ipc_router.h
@@ -144,6 +144,7 @@
uint32_t num_rx;
unsigned long num_tx_bytes;
unsigned long num_rx_bytes;
+ uint32_t last_served_svc_id;
void *priv;
};
diff --git a/include/linux/libfdt_env.h b/include/linux/libfdt_env.h
index 2a663c6..b01d294 100644
--- a/include/linux/libfdt_env.h
+++ b/include/linux/libfdt_env.h
@@ -1,6 +1,7 @@
#ifndef _LIBFDT_ENV_H
#define _LIBFDT_ENV_H
+#include <linux/kernel.h>
#include <linux/string.h>
#include <asm/byteorder.h>
diff --git a/include/linux/list_lru.h b/include/linux/list_lru.h
index cb0ba9f..fa7fd03 100644
--- a/include/linux/list_lru.h
+++ b/include/linux/list_lru.h
@@ -44,6 +44,7 @@
/* for cgroup aware lrus points to per cgroup lists, otherwise NULL */
struct list_lru_memcg *memcg_lrus;
#endif
+ long nr_items;
} ____cacheline_aligned_in_smp;
struct list_lru {
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 558adfa..8f5af30 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1921,6 +1921,13 @@
}
#endif /* CONFIG_SECURITY_SELINUX_DISABLE */
+/* Currently required to handle SELinux runtime hook disable. */
+#ifdef CONFIG_SECURITY_WRITABLE_HOOKS
+#define __lsm_ro_after_init
+#else
+#define __lsm_ro_after_init __ro_after_init
+#endif /* CONFIG_SECURITY_WRITABLE_HOOKS */
+
extern int __init security_module_enable(const char *module);
extern void __init capability_add_hooks(void);
#ifdef CONFIG_SECURITY_YAMA
diff --git a/include/linux/mfd/wcd9xxx/pdata.h b/include/linux/mfd/wcd9xxx/pdata.h
index f188e85..cfe4724 100644
--- a/include/linux/mfd/wcd9xxx/pdata.h
+++ b/include/linux/mfd/wcd9xxx/pdata.h
@@ -179,6 +179,8 @@
int irq_base;
int num_irqs;
int reset_gpio;
+ bool has_buck_vsel_gpio;
+ struct device_node *buck_vsel_ctl_np;
struct device_node *wcd_rst_np;
struct wcd9xxx_amic amic_settings;
struct slim_device slimbus_slave_device;
diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h
index e1a903a..6a620e0 100644
--- a/include/linux/mlx5/driver.h
+++ b/include/linux/mlx5/driver.h
@@ -788,6 +788,7 @@
void mlx5_start_health_poll(struct mlx5_core_dev *dev);
void mlx5_stop_health_poll(struct mlx5_core_dev *dev);
void mlx5_drain_health_wq(struct mlx5_core_dev *dev);
+void mlx5_drain_health_recovery(struct mlx5_core_dev *dev);
int mlx5_buf_alloc_node(struct mlx5_core_dev *dev, int size,
struct mlx5_buf *buf, int node);
int mlx5_buf_alloc(struct mlx5_core_dev *dev, int size, struct mlx5_buf *buf);
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 2b423f7..9b21e2a 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -76,6 +76,10 @@
#define page_to_virt(x) __va(PFN_PHYS(page_to_pfn(x)))
#endif
+#ifndef lm_alias
+#define lm_alias(x) __va(__pa_symbol(x))
+#endif
+
/*
* To prevent common memory management code establishing
* a zero page mapping on a read fault.
diff --git a/include/linux/msm_ext_display.h b/include/linux/msm_ext_display.h
new file mode 100644
index 0000000..08e0def
--- /dev/null
+++ b/include/linux/msm_ext_display.h
@@ -0,0 +1,182 @@
+/* Copyright (c) 2014-2017, The Linux Foundation. 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 and
+ * only 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 _MSM_EXT_DISPLAY_H_
+#define _MSM_EXT_DISPLAY_H_
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/extcon.h>
+
+#define AUDIO_ACK_SET_ENABLE BIT(5)
+#define AUDIO_ACK_ENABLE BIT(4)
+#define AUDIO_ACK_CONNECT BIT(0)
+
+/*
+ * Flags to be used with the HPD operation of the external display
+ * interface:
+ * MSM_EXT_DISP_HPD_AUDIO: audio will be routed to external display
+ * MSM_EXT_DISP_HPD_VIDEO: video will be routed to external display
+ */
+#define MSM_EXT_DISP_HPD_AUDIO BIT(0)
+#define MSM_EXT_DISP_HPD_VIDEO BIT(1)
+
+/**
+ * struct ext_disp_cable_notify - cable notify handler structure
+ * @link: a link for the linked list
+ * @status: current status of HDMI/DP cable connection
+ * @hpd_notify: callback function to provide cable status
+ */
+struct ext_disp_cable_notify {
+ struct list_head link;
+ int status;
+ void (*hpd_notify)(struct ext_disp_cable_notify *h);
+};
+
+struct msm_ext_disp_audio_edid_blk {
+ u8 *audio_data_blk;
+ unsigned int audio_data_blk_size; /* in bytes */
+ u8 *spk_alloc_data_blk;
+ unsigned int spk_alloc_data_blk_size; /* in bytes */
+};
+
+struct msm_ext_disp_audio_setup_params {
+ u32 sample_rate_hz;
+ u32 num_of_channels;
+ u32 channel_allocation;
+ u32 level_shift;
+ bool down_mix;
+ u32 sample_present;
+};
+
+/*
+ * External Display identifier for use to determine which interface
+ * the audio driver is interacting with.
+ */
+enum msm_ext_disp_type {
+ EXT_DISPLAY_TYPE_HDMI = EXTCON_DISP_HDMI,
+ EXT_DISPLAY_TYPE_DP = EXTCON_DISP_DP,
+ EXT_DISPLAY_TYPE_MAX = 0xFFFFFFFF
+};
+
+/*
+ * External Display cable state used by display interface to indicate
+ * connect/disconnect of interface.
+ */
+enum msm_ext_disp_cable_state {
+ EXT_DISPLAY_CABLE_DISCONNECT,
+ EXT_DISPLAY_CABLE_CONNECT,
+ EXT_DISPLAY_CABLE_STATE_MAX
+};
+
+/**
+ * External Display power state used by display interface to indicate
+ * power on/off of the interface.
+ */
+enum msm_ext_disp_power_state {
+ EXT_DISPLAY_POWER_OFF,
+ EXT_DISPLAY_POWER_ON,
+ EXT_DISPLAY_POWER_MAX
+};
+
+/**
+ * struct msm_ext_disp_intf_ops - operations exposed to display interface
+ * @audio_config: configures the audio operations exposed to codec driver
+ * @audio_notify: notifies the audio connection state to user modules.
+ * @video_notify: notifies the video connection state to user modules.
+ */
+struct msm_ext_disp_intf_ops {
+ int (*audio_config)(struct platform_device *pdev,
+ enum msm_ext_disp_type type,
+ enum msm_ext_disp_cable_state state);
+
+ int (*audio_notify)(struct platform_device *pdev,
+ enum msm_ext_disp_type type,
+ enum msm_ext_disp_cable_state state);
+
+
+ int (*video_notify)(struct platform_device *pdev,
+ enum msm_ext_disp_type type,
+ enum msm_ext_disp_cable_state state);
+};
+
+/**
+ * struct msm_ext_disp_audio_codec_ops - operations exposed to audio codec
+ * @audio_info_setup: configure audio on interface
+ * @get_audio_edid_blk: retrieve audio edid block
+ * @cable_status: cable connected/disconnected
+ * @get_intf_id: id of connected interface
+ * @teardown_done: audio session teardown done by qdsp
+ * @acknowledge: acknowledge audio status received by user modules
+ */
+struct msm_ext_disp_audio_codec_ops {
+ int (*audio_info_setup)(struct platform_device *pdev,
+ struct msm_ext_disp_audio_setup_params *params);
+ int (*get_audio_edid_blk)(struct platform_device *pdev,
+ struct msm_ext_disp_audio_edid_blk *blk);
+ int (*cable_status)(struct platform_device *pdev, u32 vote);
+ int (*get_intf_id)(struct platform_device *pdev);
+ void (*teardown_done)(struct platform_device *pdev);
+ int (*acknowledge)(struct platform_device *pdev, u32 ack);
+};
+
+/**
+ * struct msm_ext_disp_init_data - data needed to register a display interface
+ * @type: external display type
+ * @intf_ops: external display interface operations
+ * @codec_ops: audio codec operations
+ * @pdev: platform device instance of the interface driver
+ * @intf_data: interface specific data
+ */
+struct msm_ext_disp_init_data {
+ enum msm_ext_disp_type type;
+ struct msm_ext_disp_intf_ops intf_ops;
+ struct msm_ext_disp_audio_codec_ops codec_ops;
+ struct platform_device *pdev;
+ void *intf_data;
+};
+
+/**
+ * struct msm_ext_disp_data - data needed by interface modules
+ * @intf_pdev: platform device instance of the interface
+ * @intf_data: data related to interface module
+ */
+struct msm_ext_disp_data {
+ struct platform_device *intf_pdev;
+ void *intf_data;
+};
+
+/**
+ * msm_ext_disp_register_audio_codec() - audio codec registration
+ * @pdev: platform device pointer
+ * @codec_ops: audio codec operations
+ */
+int msm_ext_disp_register_audio_codec(struct platform_device *pdev,
+ struct msm_ext_disp_audio_codec_ops *ops);
+
+/**
+ * msm_hdmi_register_audio_codec() - wrapper for hdmi audio codec
+ * registration
+ * @pdev: platform device pointer
+ * @codec_ops: audio codec operations
+ */
+int msm_hdmi_register_audio_codec(struct platform_device *pdev,
+ struct msm_ext_disp_audio_codec_ops *ops);
+
+/**
+ * msm_ext_disp_register_intf() - display interface registration
+ * @init_data: data needed to register the display interface
+ */
+int msm_ext_disp_register_intf(struct platform_device *pdev,
+ struct msm_ext_disp_init_data *init_data);
+
+#endif /*_MSM_EXT_DISPLAY_H_*/
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 8e7a431..f9cd4f3 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -249,6 +249,8 @@
POWER_SUPPLY_PROP_HW_CURRENT_MAX,
POWER_SUPPLY_PROP_REAL_TYPE,
POWER_SUPPLY_PROP_PR_SWAP,
+ POWER_SUPPLY_PROP_CC_STEP,
+ POWER_SUPPLY_PROP_CC_STEP_SEL,
/* Local extensions of type int64_t */
POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT,
/* Properties of type `const char *' */
diff --git a/include/linux/qcom-geni-se.h b/include/linux/qcom-geni-se.h
index 2938206..aa4c1ed 100644
--- a/include/linux/qcom-geni-se.h
+++ b/include/linux/qcom-geni-se.h
@@ -82,7 +82,7 @@
#define GENI_SER_M_CLK_CFG (0x48)
#define GENI_SER_S_CLK_CFG (0x4C)
#define GENI_CLK_CTRL_RO (0x60)
-#define GENI_IF_DISABLE_RO (0x64)
+#define GENI_IF_FIFO_DISABLE_RO (0x64)
#define GENI_FW_REVISION_RO (0x68)
#define GENI_FW_S_REVISION_RO (0x6C)
#define SE_GENI_CLK_SEL (0x7C)
@@ -147,7 +147,8 @@
/* CLK_CTRL_RO fields */
-/* IF_DISABLE_RO fields */
+/* FIFO_IF_DISABLE_RO fields */
+#define FIFO_IF_DISABLE (BIT(0))
/* FW_REVISION_RO fields */
#define FW_REV_PROTOCOL_MSK (GENMASK(15, 8))
@@ -330,6 +331,12 @@
#define DEFAULT_BUS_WIDTH (4)
#define DEFAULT_SE_CLK (19200000)
+/* GSI TRE fields */
+/* Packing fields */
+#define GSI_TX_PACK_EN (BIT(0))
+#define GSI_RX_PACK_EN (BIT(1))
+#define GSI_PRESERVE_PACK (BIT(2))
+
#define GENI_SE_ERR(log_ctx, print, dev, x...) do { \
if (log_ctx) \
ipc_log_string(log_ctx, x); \
diff --git a/include/linux/qcom_tspp.h b/include/linux/qcom_tspp.h
index 1b34c38..7a9e569 100644
--- a/include/linux/qcom_tspp.h
+++ b/include/linux/qcom_tspp.h
@@ -16,6 +16,7 @@
struct tspp_data_descriptor {
void *virt_base; /* logical address of the actual data */
phys_addr_t phys_base; /* physical address of the actual data */
+ dma_addr_t dma_base; /* DMA address of the actual data */
u32 size; /* size of buffer in bytes */
int id; /* unique identifier */
void *user; /* user-defined data */
@@ -75,9 +76,17 @@
TSIF_TTS_LPASS_TIMER /* Time stamps from AV/Qtimer Timer */
};
+struct tspp_ion_dma_buf_info {
+ struct dma_buf *dbuf;
+ struct dma_buf_attachment *attach;
+ struct sg_table *table;
+ bool smmu_map;
+ dma_addr_t dma_map_base;
+};
+
typedef void (tspp_notifier)(int channel_id, void *user);
typedef void* (tspp_allocator)(int channel_id, u32 size,
- phys_addr_t *phys_base, void *user);
+ phys_addr_t *phys_base, dma_addr_t *dma_base, void *user);
typedef void (tspp_memfree)(int channel_id, u32 size,
void *virt_base, phys_addr_t phys_base, void *user);
@@ -105,4 +114,9 @@
int tspp_get_lpass_time_counter(u32 dev, enum tspp_source source,
u64 *lpass_time_counter);
+int tspp_attach_ion_dma_buff(u32 dev,
+ struct tspp_ion_dma_buf_info *ion_dma_buf);
+
+int tspp_detach_ion_dma_buff(u32 dev,
+ struct tspp_ion_dma_buf_info *ion_dma_buf);
#endif /* _MSM_TSPP_H_ */
diff --git a/include/linux/random.h b/include/linux/random.h
index 16ab429..1fa0dc8 100644
--- a/include/linux/random.h
+++ b/include/linux/random.h
@@ -42,8 +42,42 @@
extern const struct file_operations random_fops, urandom_fops;
#endif
-unsigned int get_random_int(void);
-unsigned long get_random_long(void);
+u32 get_random_u32(void);
+u64 get_random_u64(void);
+static inline unsigned int get_random_int(void)
+{
+ return get_random_u32();
+}
+static inline unsigned long get_random_long(void)
+{
+#if BITS_PER_LONG == 64
+ return get_random_u64();
+#else
+ return get_random_u32();
+#endif
+}
+
+/*
+ * On 64-bit architectures, protect against non-terminated C string overflows
+ * by zeroing out the first byte of the canary; this leaves 56 bits of entropy.
+ */
+#ifdef CONFIG_64BIT
+# ifdef __LITTLE_ENDIAN
+# define CANARY_MASK 0xffffffffffffff00UL
+# else /* big endian, 64 bits: */
+# define CANARY_MASK 0x00ffffffffffffffUL
+# endif
+#else /* 32 bits: */
+# define CANARY_MASK 0xffffffffUL
+#endif
+
+static inline unsigned long get_random_canary(void)
+{
+ unsigned long val = get_random_long();
+
+ return val & CANARY_MASK;
+}
+
unsigned long randomize_page(unsigned long start, unsigned long range);
u32 prandom_u32(void);
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 7627c76..0737cb6 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -183,6 +183,7 @@
unsigned int *max_nr,
unsigned int *big_max_nr);
extern unsigned int sched_get_cpu_util(int cpu);
+extern u64 sched_get_cpu_last_busy_time(int cpu);
#else
static inline void sched_update_nr_prod(int cpu, long delta, bool inc)
{
@@ -196,6 +197,10 @@
{
return 0;
}
+static inline u64 sched_get_cpu_last_busy_time(int cpu)
+{
+ return 0;
+}
#endif
extern void calc_global_load(unsigned long ticks);
@@ -3882,6 +3887,7 @@
#define SCHED_CPUFREQ_IOWAIT (1U << 2)
#define SCHED_CPUFREQ_INTERCLUSTER_MIG (1U << 3)
#define SCHED_CPUFREQ_WALT (1U << 4)
+#define SCHED_CPUFREQ_PL (1U << 5)
#define SCHED_CPUFREQ_RT_DL (SCHED_CPUFREQ_RT | SCHED_CPUFREQ_DL)
diff --git a/include/linux/sched/sysctl.h b/include/linux/sched/sysctl.h
index 322bc23..3597d55 100644
--- a/include/linux/sched/sysctl.h
+++ b/include/linux/sched/sysctl.h
@@ -24,13 +24,9 @@
extern unsigned int sysctl_sched_cstate_aware;
extern unsigned int sysctl_sched_capacity_margin;
extern unsigned int sysctl_sched_capacity_margin_down;
-#ifdef CONFIG_SCHED_WALT
-extern unsigned int sysctl_sched_use_walt_cpu_util;
-extern unsigned int sysctl_sched_use_walt_task_util;
-extern unsigned int sysctl_sched_init_task_load_pct;
-#endif
#ifdef CONFIG_SCHED_WALT
+extern unsigned int sysctl_sched_init_task_load_pct;
extern unsigned int sysctl_sched_cpu_high_irqload;
extern unsigned int sysctl_sched_use_walt_cpu_util;
extern unsigned int sysctl_sched_use_walt_task_util;
@@ -72,9 +68,6 @@
extern int sched_migrate_notify_proc_handler(struct ctl_table *table,
int write, void __user *buffer, size_t *lenp, loff_t *ppos);
-extern int sched_hmp_proc_update_handler(struct ctl_table *table,
- int write, void __user *buffer, size_t *lenp, loff_t *ppos);
-
extern int sched_boost_handler(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp, loff_t *ppos);
diff --git a/include/linux/sde_rsc.h b/include/linux/sde_rsc.h
index 0320210..19e76db 100644
--- a/include/linux/sde_rsc.h
+++ b/include/linux/sde_rsc.h
@@ -21,6 +21,9 @@
#define MAX_RSC_CLIENT_NAME_LEN 128
+/* DRM Object IDs are numbered excluding 0, use 0 to indicate invalid CRTC */
+#define SDE_RSC_INVALID_CRTC_ID 0
+
/**
* event will be triggered before sde core power collapse,
* mdss gdsc is still on
@@ -169,12 +172,29 @@
* @config: fps, vtotal, porches, etc configuration for command mode
* panel
* @crtc_id: current client's crtc id
+ * @wait_vblank_crtc_id: Output parameter. If set to non-zero, rsc hw
+ * state update requires a wait for one vblank on
+ * the primary crtc. In that case, this output
+ * param will be set to the crtc on which to wait.
+ * If SDE_RSC_INVALID_CRTC_ID, no wait necessary
*
* Return: error code.
*/
int sde_rsc_client_state_update(struct sde_rsc_client *client,
enum sde_rsc_state state,
- struct sde_rsc_cmd_config *config, int crtc_id);
+ struct sde_rsc_cmd_config *config, int crtc_id,
+ int *wait_vblank_crtc_id);
+
+/**
+ * sde_rsc_client_is_state_update_complete() - check if state update is complete
+ * RSC state transition is not complete until HW receives VBLANK signal. This
+ * function checks RSC HW to determine whether that signal has been received.
+ * @client: Client pointer provided by sde_rsc_client_create().
+ *
+ * Return: true if the state update has completed.
+ */
+bool sde_rsc_client_is_state_update_complete(
+ struct sde_rsc_client *caller_client);
/**
* sde_rsc_client_vote() - ab/ib vote from rsc client
@@ -244,6 +264,12 @@
return 0;
}
+static inline bool sde_rsc_client_is_state_update_complete(
+ struct sde_rsc_client *caller_client)
+{
+ return false;
+}
+
static inline int sde_rsc_client_vote(struct sde_rsc_client *caller_client,
u32 bus_id, u64 ab_vote, u64 ib_vote)
{
diff --git a/include/linux/seemp_instrumentation.h b/include/linux/seemp_instrumentation.h
index ff09bd2..1db7a44 100644
--- a/include/linux/seemp_instrumentation.h
+++ b/include/linux/seemp_instrumentation.h
@@ -69,7 +69,7 @@
seemp_logk_kernel_end(blck);
}
-static inline void seemp_logk_rtic(__u8 type, __u64 actor, __u8 asset_id[0x20],
+static inline void seemp_logk_rtic(__u8 type, pid_t pid, __u8 asset_id[0x20],
__u8 asset_category, __u8 response)
{
char *buf = NULL;
@@ -80,8 +80,8 @@
return;
SEEMP_LOGK_RECORD(SEEMP_API_kernel__rtic,
- "app_pid=%llu,rtic_type=%u,asset_id=%s,asset_category=%u,response=%u",
- actor, type, asset_id, asset_category, response);
+ "app_pid=%d,rtic_type=%u,asset_id=%s,asset_category=%u,response=%u",
+ pid, type, asset_id, asset_category, response);
seemp_logk_kernel_end(blck);
}
diff --git a/include/linux/string.h b/include/linux/string.h
index 26b6f6a..4e510df 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -169,4 +169,204 @@
return tail ? tail + 1 : path;
}
+#define __FORTIFY_INLINE extern __always_inline __attribute__((gnu_inline))
+#define __RENAME(x) __asm__(#x)
+
+void fortify_panic(const char *name) __noreturn __cold;
+void __read_overflow(void) __compiletime_error("detected read beyond size of object passed as 1st parameter");
+void __read_overflow2(void) __compiletime_error("detected read beyond size of object passed as 2nd parameter");
+void __write_overflow(void) __compiletime_error("detected write beyond size of object passed as 1st parameter");
+
+#if !defined(__NO_FORTIFY) && defined(__OPTIMIZE__) && defined(CONFIG_FORTIFY_SOURCE)
+__FORTIFY_INLINE char *strcpy(char *p, const char *q)
+{
+ size_t p_size = __builtin_object_size(p, 0);
+ size_t q_size = __builtin_object_size(q, 0);
+ if (p_size == (size_t)-1 && q_size == (size_t)-1)
+ return __builtin_strcpy(p, q);
+ if (strscpy(p, q, p_size < q_size ? p_size : q_size) < 0)
+ fortify_panic(__func__);
+ return p;
+}
+
+__FORTIFY_INLINE char *strncpy(char *p, const char *q, __kernel_size_t size)
+{
+ size_t p_size = __builtin_object_size(p, 0);
+ if (__builtin_constant_p(size) && p_size < size)
+ __write_overflow();
+ if (p_size < size)
+ fortify_panic(__func__);
+ return __builtin_strncpy(p, q, size);
+}
+
+__FORTIFY_INLINE char *strcat(char *p, const char *q)
+{
+ size_t p_size = __builtin_object_size(p, 0);
+ if (p_size == (size_t)-1)
+ return __builtin_strcat(p, q);
+ if (strlcat(p, q, p_size) >= p_size)
+ fortify_panic(__func__);
+ return p;
+}
+
+__FORTIFY_INLINE __kernel_size_t strlen(const char *p)
+{
+ __kernel_size_t ret;
+ size_t p_size = __builtin_object_size(p, 0);
+ if (p_size == (size_t)-1)
+ return __builtin_strlen(p);
+ ret = strnlen(p, p_size);
+ if (p_size <= ret)
+ fortify_panic(__func__);
+ return ret;
+}
+
+extern __kernel_size_t __real_strnlen(const char *, __kernel_size_t) __RENAME(strnlen);
+__FORTIFY_INLINE __kernel_size_t strnlen(const char *p, __kernel_size_t maxlen)
+{
+ size_t p_size = __builtin_object_size(p, 0);
+ __kernel_size_t ret = __real_strnlen(p, maxlen < p_size ? maxlen : p_size);
+ if (p_size <= ret && maxlen != ret)
+ fortify_panic(__func__);
+ return ret;
+}
+
+/* defined after fortified strlen to reuse it */
+extern size_t __real_strlcpy(char *, const char *, size_t) __RENAME(strlcpy);
+__FORTIFY_INLINE size_t strlcpy(char *p, const char *q, size_t size)
+{
+ size_t ret;
+ size_t p_size = __builtin_object_size(p, 0);
+ size_t q_size = __builtin_object_size(q, 0);
+ if (p_size == (size_t)-1 && q_size == (size_t)-1)
+ return __real_strlcpy(p, q, size);
+ ret = strlen(q);
+ if (size) {
+ size_t len = (ret >= size) ? size - 1 : ret;
+ if (__builtin_constant_p(len) && len >= p_size)
+ __write_overflow();
+ if (len >= p_size)
+ fortify_panic(__func__);
+ __builtin_memcpy(p, q, len);
+ p[len] = '\0';
+ }
+ return ret;
+}
+
+/* defined after fortified strlen and strnlen to reuse them */
+__FORTIFY_INLINE char *strncat(char *p, const char *q, __kernel_size_t count)
+{
+ size_t p_len, copy_len;
+ size_t p_size = __builtin_object_size(p, 0);
+ size_t q_size = __builtin_object_size(q, 0);
+ if (p_size == (size_t)-1 && q_size == (size_t)-1)
+ return __builtin_strncat(p, q, count);
+ p_len = strlen(p);
+ copy_len = strnlen(q, count);
+ if (p_size < p_len + copy_len + 1)
+ fortify_panic(__func__);
+ __builtin_memcpy(p + p_len, q, copy_len);
+ p[p_len + copy_len] = '\0';
+ return p;
+}
+
+__FORTIFY_INLINE void *memset(void *p, int c, __kernel_size_t size)
+{
+ size_t p_size = __builtin_object_size(p, 0);
+ if (__builtin_constant_p(size) && p_size < size)
+ __write_overflow();
+ if (p_size < size)
+ fortify_panic(__func__);
+ return __builtin_memset(p, c, size);
+}
+
+__FORTIFY_INLINE void *memcpy(void *p, const void *q, __kernel_size_t size)
+{
+ size_t p_size = __builtin_object_size(p, 0);
+ size_t q_size = __builtin_object_size(q, 0);
+ if (__builtin_constant_p(size)) {
+ if (p_size < size)
+ __write_overflow();
+ if (q_size < size)
+ __read_overflow2();
+ }
+ if (p_size < size || q_size < size)
+ fortify_panic(__func__);
+ return __builtin_memcpy(p, q, size);
+}
+
+__FORTIFY_INLINE void *memmove(void *p, const void *q, __kernel_size_t size)
+{
+ size_t p_size = __builtin_object_size(p, 0);
+ size_t q_size = __builtin_object_size(q, 0);
+ if (__builtin_constant_p(size)) {
+ if (p_size < size)
+ __write_overflow();
+ if (q_size < size)
+ __read_overflow2();
+ }
+ if (p_size < size || q_size < size)
+ fortify_panic(__func__);
+ return __builtin_memmove(p, q, size);
+}
+
+extern void *__real_memscan(void *, int, __kernel_size_t) __RENAME(memscan);
+__FORTIFY_INLINE void *memscan(void *p, int c, __kernel_size_t size)
+{
+ size_t p_size = __builtin_object_size(p, 0);
+ if (__builtin_constant_p(size) && p_size < size)
+ __read_overflow();
+ if (p_size < size)
+ fortify_panic(__func__);
+ return __real_memscan(p, c, size);
+}
+
+__FORTIFY_INLINE int memcmp(const void *p, const void *q, __kernel_size_t size)
+{
+ size_t p_size = __builtin_object_size(p, 0);
+ size_t q_size = __builtin_object_size(q, 0);
+ if (__builtin_constant_p(size)) {
+ if (p_size < size)
+ __read_overflow();
+ if (q_size < size)
+ __read_overflow2();
+ }
+ if (p_size < size || q_size < size)
+ fortify_panic(__func__);
+ return __builtin_memcmp(p, q, size);
+}
+
+__FORTIFY_INLINE void *memchr(const void *p, int c, __kernel_size_t size)
+{
+ size_t p_size = __builtin_object_size(p, 0);
+ if (__builtin_constant_p(size) && p_size < size)
+ __read_overflow();
+ if (p_size < size)
+ fortify_panic(__func__);
+ return __builtin_memchr(p, c, size);
+}
+
+void *__real_memchr_inv(const void *s, int c, size_t n) __RENAME(memchr_inv);
+__FORTIFY_INLINE void *memchr_inv(const void *p, int c, size_t size)
+{
+ size_t p_size = __builtin_object_size(p, 0);
+ if (__builtin_constant_p(size) && p_size < size)
+ __read_overflow();
+ if (p_size < size)
+ fortify_panic(__func__);
+ return __real_memchr_inv(p, c, size);
+}
+
+extern void *__real_kmemdup(const void *src, size_t len, gfp_t gfp) __RENAME(kmemdup);
+__FORTIFY_INLINE void *kmemdup(const void *p, size_t size, gfp_t gfp)
+{
+ size_t p_size = __builtin_object_size(p, 0);
+ if (__builtin_constant_p(size) && p_size < size)
+ __read_overflow();
+ if (p_size < size)
+ fortify_panic(__func__);
+ return __real_kmemdup(p, size, gfp);
+}
+#endif
+
#endif /* _LINUX_STRING_H_ */
diff --git a/include/linux/sysrq.h b/include/linux/sysrq.h
index 387fa7d..d802692 100644
--- a/include/linux/sysrq.h
+++ b/include/linux/sysrq.h
@@ -42,6 +42,7 @@
* are available -- else NULL's).
*/
+bool sysrq_on(void);
void handle_sysrq(int key);
void __handle_sysrq(int key, bool check_mask);
int register_sysrq_key(int key, struct sysrq_key_op *op);
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 1f39661..0f9fff3 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -333,6 +333,8 @@
struct usb_ssp_cap_descriptor *ssp_cap;
struct usb_ss_container_id_descriptor *ss_id;
struct usb_ptm_cap_descriptor *ptm_cap;
+ struct usb_config_summary_descriptor *config_summary;
+ unsigned int num_config_summary_desc;
};
int __usb_get_extra_descriptor(char *buffer, unsigned size,
diff --git a/include/linux/usb/audio-v3.h b/include/linux/usb/audio-v3.h
index f2322f3..b6cc17b 100644
--- a/include/linux/usb/audio-v3.h
+++ b/include/linux/usb/audio-v3.h
@@ -50,7 +50,8 @@
#define CLUSTER_ID_MONO 0x0001
#define CLUSTER_ID_STEREO 0x0002
-#define FULL_ADC_PROFILE 0x01
+/* A.2 audio function subclass codes */
+#define FULL_ADC_3_0 0x01
/* BADD Profile IDs */
#define PROF_GENERIC_IO 0x20
diff --git a/include/linux/usb/usbpd.h b/include/linux/usb/usbpd.h
index 3566a7a..4dbd91f 100644
--- a/include/linux/usb/usbpd.h
+++ b/include/linux/usb/usbpd.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, Linux Foundation. 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 and
@@ -46,6 +46,10 @@
void (*connect)(struct usbpd_svid_handler *hdlr);
void (*disconnect)(struct usbpd_svid_handler *hdlr);
+ /* DP driver -> PE driver for requesting USB SS lanes */
+ int (*request_usb_ss_lane)(struct usbpd *pd,
+ struct usbpd_svid_handler *hdlr);
+
/* Unstructured VDM */
void (*vdm_received)(struct usbpd_svid_handler *hdlr, u32 vdm_hdr,
const u32 *vdos, int num_vdos);
diff --git a/include/linux/vfio.h b/include/linux/vfio.h
index 0ecae0b..ed46675 100644
--- a/include/linux/vfio.h
+++ b/include/linux/vfio.h
@@ -88,6 +88,8 @@
*/
extern struct vfio_group *vfio_group_get_external_user(struct file *filep);
extern void vfio_group_put_external_user(struct vfio_group *group);
+extern bool vfio_external_group_match_file(struct vfio_group *group,
+ struct file *filep);
extern int vfio_external_user_iommu_id(struct vfio_group *group);
extern long vfio_external_check_extension(struct vfio_group *group,
unsigned long arg);
diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
index 826eef8..f113e0e 100644
--- a/include/linux/vmalloc.h
+++ b/include/linux/vmalloc.h
@@ -84,6 +84,7 @@
const void *caller);
extern void vfree(const void *addr);
+extern void vfree_atomic(const void *addr);
extern void *vmap(struct page **pages, unsigned int count,
unsigned long flags, pgprot_t prot);
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 45dbffb..82b4b53 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -24,6 +24,30 @@
#include <linux/net.h>
#include <net/regulatory.h>
+/* backport support for new cfg80211 ops "update_connect_params" */
+#define CFG80211_UPDATE_CONNECT_PARAMS 1
+
+/**
+ * backport support for NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA
+ * and NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED.
+ */
+#define CFG80211_RAND_TA_FOR_PUBLIC_ACTION_FRAME 1
+
+/* backport support for NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI */
+#define CFG80211_REPORT_BETTER_BSS_IN_SCHED_SCAN 1
+
+/* backport support for specifying reason for connect timeout */
+#define CFG80211_CONNECT_TIMEOUT_REASON_CODE 1
+
+/* Indicate backport support for the new connect done api */
+#define CFG80211_CONNECT_DONE 1
+
+/* Indicate backport support for FILS SK offload in cfg80211 */
+#define CFG80211_FILS_SK_OFFLOAD_SUPPORT 1
+
+/* Indicate support for including KEK length in rekey data */
+#define CFG80211_REKEY_DATA_KEK_LEN 1
+
/**
* DOC: Introduction
*
@@ -784,19 +808,15 @@
* @iftype_num: array with the number of interfaces of each interface
* type. The index is the interface type as specified in &enum
* nl80211_iftype.
- * @beacon_int_gcd: a value specifying GCD of all beaconing interfaces,
- * the GCD of a single value is considered the value itself, so for
- * a single interface this should be set to that interface's beacon
- * interval
- * @beacon_int_different: a flag indicating whether or not all beacon
- * intervals (of beaconing interfaces) are different or not.
+ * @new_beacon_int: set this to the beacon interval of a new interface
+ * that's not operating yet, if such is to be checked as part of
+ * the verification
*/
struct iface_combination_params {
int num_different_channels;
u8 radar_detect;
int iftype_num[NUM_NL80211_IFTYPES];
- u32 beacon_int_gcd;
- bool beacon_int_different;
+ u32 new_beacon_int;
};
/**
@@ -1596,6 +1616,17 @@
};
/**
+ * struct cfg80211_bss_select_adjust - BSS selection with RSSI adjustment.
+ *
+ * @band: band of BSS which should match for RSSI level adjustment.
+ * @delta: value of RSSI level adjustment.
+ */
+struct cfg80211_bss_select_adjust {
+ enum nl80211_band band;
+ s8 delta;
+};
+
+/**
* struct cfg80211_sched_scan_request - scheduled scan request description
*
* @ssids: SSIDs to scan for (passed in the probe_reqs in active scans)
@@ -1630,6 +1661,16 @@
* cycle. The driver may ignore this parameter and start
* immediately (or at any other time), if this feature is not
* supported.
+ * @relative_rssi_set: Indicates whether @relative_rssi is set or not.
+ * @relative_rssi: Relative RSSI threshold in dB to restrict scan result
+ * reporting in connected state to cases where a matching BSS is determined
+ * to have better or slightly worse RSSI than the current connected BSS.
+ * The relative RSSI threshold values are ignored in disconnected state.
+ * @rssi_adjust: delta dB of RSSI preference to be given to the BSSs that belong
+ * to the specified band while deciding whether a better BSS is reported
+ * using @relative_rssi. If delta is a negative number, the BSSs that
+ * belong to the specified band will be penalized by delta dB in relative
+ * comparisions.
*/
struct cfg80211_sched_scan_request {
struct cfg80211_ssid *ssids;
@@ -1649,6 +1690,10 @@
u8 mac_addr[ETH_ALEN] __aligned(2);
u8 mac_addr_mask[ETH_ALEN] __aligned(2);
+ bool relative_rssi_set;
+ s8 relative_rssi;
+ struct cfg80211_bss_select_adjust rssi_adjust;
+
/* internal */
struct wiphy *wiphy;
struct net_device *dev;
@@ -1789,9 +1834,11 @@
* @key_len: length of WEP key for shared key authentication
* @key_idx: index of WEP key for shared key authentication
* @key: WEP key for shared key authentication
- * @sae_data: Non-IE data to use with SAE or %NULL. This starts with
- * Authentication transaction sequence number field.
- * @sae_data_len: Length of sae_data buffer in octets
+ * @auth_data: Fields and elements in Authentication frames. This contains
+ * the authentication frame body (non-IE and IE data), excluding the
+ * Authentication algorithm number, i.e., starting at the Authentication
+ * transaction sequence number field.
+ * @auth_data_len: Length of auth_data buffer in octets
*/
struct cfg80211_auth_request {
struct cfg80211_bss *bss;
@@ -1800,8 +1847,8 @@
enum nl80211_auth_type auth_type;
const u8 *key;
u8 key_len, key_idx;
- const u8 *sae_data;
- size_t sae_data_len;
+ const u8 *auth_data;
+ size_t auth_data_len;
};
/**
@@ -1842,6 +1889,12 @@
* @ht_capa_mask: The bits of ht_capa which are to be used.
* @vht_capa: VHT capability override
* @vht_capa_mask: VHT capability mask indicating which fields to use
+ * @fils_kek: FILS KEK for protecting (Re)Association Request/Response frame or
+ * %NULL if FILS is not used.
+ * @fils_kek_len: Length of fils_kek in octets
+ * @fils_nonces: FILS nonces (part of AAD) for protecting (Re)Association
+ * Request/Response frame or %NULL if FILS is not used. This field starts
+ * with 16 octets of STA Nonce followed by 16 octets of AP Nonce.
*/
struct cfg80211_assoc_request {
struct cfg80211_bss *bss;
@@ -1853,6 +1906,9 @@
struct ieee80211_ht_cap ht_capa;
struct ieee80211_ht_cap ht_capa_mask;
struct ieee80211_vht_cap vht_capa, vht_capa_mask;
+ const u8 *fils_kek;
+ size_t fils_kek_len;
+ const u8 *fils_nonces;
};
/**
@@ -1946,17 +2002,6 @@
};
/**
- * struct cfg80211_bss_select_adjust - BSS selection with RSSI adjustment.
- *
- * @band: band of BSS which should match for RSSI level adjustment.
- * @delta: value of RSSI level adjustment.
- */
-struct cfg80211_bss_select_adjust {
- enum nl80211_band band;
- s8 delta;
-};
-
-/**
* struct cfg80211_bss_selection - connection parameters for BSS selection.
*
* @behaviour: requested BSS selection behaviour.
@@ -2016,6 +2061,19 @@
* the BSSID of the current association, i.e., to the value that is
* included in the Current AP address field of the Reassociation Request
* frame.
+ * @fils_erp_username: EAP re-authentication protocol (ERP) username part of the
+ * NAI or %NULL if not specified. This is used to construct FILS wrapped
+ * data IE.
+ * @fils_erp_username_len: Length of @fils_erp_username in octets.
+ * @fils_erp_realm: EAP re-authentication protocol (ERP) realm part of NAI or
+ * %NULL if not specified. This specifies the domain name of ER server and
+ * is used to construct FILS wrapped data IE.
+ * @fils_erp_realm_len: Length of @fils_erp_realm in octets.
+ * @fils_erp_next_seq_num: The next sequence number to use in the FILS ERP
+ * messages. This is also used to construct FILS wrapped data IE.
+ * @fils_erp_rrk: ERP re-authentication Root Key (rRK) used to derive additional
+ * keys in FILS or %NULL if not specified.
+ * @fils_erp_rrk_len: Length of @fils_erp_rrk in octets.
*/
struct cfg80211_connect_params {
struct ieee80211_channel *channel;
@@ -2041,6 +2099,30 @@
bool pbss;
struct cfg80211_bss_selection bss_select;
const u8 *prev_bssid;
+ const u8 *fils_erp_username;
+ size_t fils_erp_username_len;
+ const u8 *fils_erp_realm;
+ size_t fils_erp_realm_len;
+ u16 fils_erp_next_seq_num;
+ const u8 *fils_erp_rrk;
+ size_t fils_erp_rrk_len;
+};
+
+/**
+ * enum cfg80211_connect_params_changed - Connection parameters being updated
+ *
+ * This enum provides information of all connect parameters that
+ * have to be updated as part of update_connect_params() call.
+ *
+ * @UPDATE_ASSOC_IES: Indicates whether association request IEs are updated
+ * @UPDATE_FILS_ERP_INFO: Indicates that FILS connection parameters (realm,
+ * username, erp sequence number and rrk) are updated
+ * @UPDATE_AUTH_TYPE: Indicates that Authentication type is updated
+ */
+enum cfg80211_connect_params_changed {
+ UPDATE_ASSOC_IES = BIT(0),
+ UPDATE_FILS_ERP_INFO = BIT(1),
+ UPDATE_AUTH_TYPE = BIT(2),
};
/**
@@ -2067,12 +2149,27 @@
* This structure is passed to the set/del_pmksa() method for PMKSA
* caching.
*
- * @bssid: The AP's BSSID.
- * @pmkid: The PMK material itself.
+ * @bssid: The AP's BSSID (may be %NULL).
+ * @pmkid: The identifier to refer a PMKSA.
+ * @pmk: The PMK for the PMKSA identified by @pmkid. This is used for key
+ * derivation by a FILS STA. Otherwise, %NULL.
+ * @pmk_len: Length of the @pmk. The length of @pmk can differ depending on
+ * the hash algorithm used to generate this.
+ * @ssid: SSID to specify the ESS within which a PMKSA is valid when using FILS
+ * cache identifier (may be %NULL).
+ * @ssid_len: Length of the @ssid in octets.
+ * @cache_id: 2-octet cache identifier advertized by a FILS AP identifying the
+ * scope of PMKSA. This is valid only if @ssid_len is non-zero (may be
+ * %NULL).
*/
struct cfg80211_pmksa {
const u8 *bssid;
const u8 *pmkid;
+ const u8 *pmk;
+ size_t pmk_len;
+ const u8 *ssid;
+ size_t ssid_len;
+ const u8 *cache_id;
};
/**
@@ -2247,12 +2344,14 @@
/**
* struct cfg80211_gtk_rekey_data - rekey data
- * @kek: key encryption key (NL80211_KEK_LEN bytes)
+ * @kek: key encryption key
* @kck: key confirmation key (NL80211_KCK_LEN bytes)
* @replay_ctr: replay counter (NL80211_REPLAY_CTR_LEN bytes)
+ * @kek_len: Length of @kek in octets
*/
struct cfg80211_gtk_rekey_data {
const u8 *kek, *kck, *replay_ctr;
+ size_t kek_len;
};
/**
@@ -2564,10 +2663,17 @@
* cases, the result of roaming is indicated with a call to
* cfg80211_roamed() or cfg80211_roamed_bss().
* (invoked with the wireless_dev mutex held)
+ * @update_connect_params: Update the connect parameters while connected to a
+ * BSS. The updated parameters can be used by driver/firmware for
+ * subsequent BSS selection (roaming) decisions and to form the
+ * Authentication/(Re)Association Request frames. This call does not
+ * request an immediate disassociation or reassociation with the current
+ * BSS, i.e., this impacts only subsequent (re)associations. The bits in
+ * changed are defined in &enum cfg80211_connect_params_changed.
+ * (invoked with the wireless_dev mutex held)
* @disconnect: Disconnect from the BSS/ESS. Once done, call
* cfg80211_disconnected().
* (invoked with the wireless_dev mutex held)
- *
* @join_ibss: Join the specified IBSS (or create if necessary). Once done, call
* cfg80211_ibss_joined(), also call that function when changing BSSID due
* to a merge.
@@ -2734,6 +2840,8 @@
* @nan_change_conf: changes NAN configuration. The changed parameters must
* be specified in @changes (using &enum cfg80211_nan_conf_changes);
* All other parameters must be ignored.
+ *
+ * @set_multicast_to_unicast: configure multicast to unicast conversion for BSS
*/
struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -2848,6 +2956,10 @@
int (*connect)(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_connect_params *sme);
+ int (*update_connect_params)(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct cfg80211_connect_params *sme,
+ u32 changed);
int (*disconnect)(struct wiphy *wiphy, struct net_device *dev,
u16 reason_code);
@@ -3010,6 +3122,10 @@
struct wireless_dev *wdev,
struct cfg80211_nan_conf *conf,
u32 changes);
+
+ int (*set_multicast_to_unicast)(struct wiphy *wiphy,
+ struct net_device *dev,
+ const bool enabled);
};
/*
@@ -4999,6 +5115,78 @@
#endif
/**
+ * struct cfg80211_connect_resp_params - Connection response params
+ * @status: Status code, %WLAN_STATUS_SUCCESS for successful connection, use
+ * %WLAN_STATUS_UNSPECIFIED_FAILURE if your device cannot give you
+ * the real status code for failures. If this call is used to report a
+ * failure due to a timeout (e.g., not receiving an Authentication frame
+ * from the AP) instead of an explicit rejection by the AP, -1 is used to
+ * indicate that this is a failure, but without a status code.
+ * @timeout_reason is used to report the reason for the timeout in that
+ * case.
+ * @bssid: The BSSID of the AP (may be %NULL)
+ * @bss: Entry of bss to which STA got connected to, can be obtained through
+ * cfg80211_get_bss() (may be %NULL). Only one parameter among @bssid and
+ * @bss needs to be specified.
+ * @req_ie: Association request IEs (may be %NULL)
+ * @req_ie_len: Association request IEs length
+ * @resp_ie: Association response IEs (may be %NULL)
+ * @resp_ie_len: Association response IEs length
+ * @fils_kek: KEK derived from a successful FILS connection (may be %NULL)
+ * @fils_kek_len: Length of @fils_kek in octets
+ * @update_erp_next_seq_num: Boolean value to specify whether the value in
+ * @fils_erp_next_seq_num is valid.
+ * @fils_erp_next_seq_num: The next sequence number to use in ERP message in
+ * FILS Authentication. This value should be specified irrespective of the
+ * status for a FILS connection.
+ * @pmk: A new PMK if derived from a successful FILS connection (may be %NULL).
+ * @pmk_len: Length of @pmk in octets
+ * @pmkid: A new PMKID if derived from a successful FILS connection or the PMKID
+ * used for this FILS connection (may be %NULL).
+ * @timeout_reason: Reason for connection timeout. This is used when the
+ * connection fails due to a timeout instead of an explicit rejection from
+ * the AP. %NL80211_TIMEOUT_UNSPECIFIED is used when the timeout reason is
+ * not known. This value is used only if @status < 0 to indicate that the
+ * failure is due to a timeout and not due to explicit rejection by the AP.
+ * This value is ignored in other cases (@status >= 0).
+ */
+struct cfg80211_connect_resp_params {
+ int status;
+ const u8 *bssid;
+ struct cfg80211_bss *bss;
+ const u8 *req_ie;
+ size_t req_ie_len;
+ const u8 *resp_ie;
+ size_t resp_ie_len;
+ const u8 *fils_kek;
+ size_t fils_kek_len;
+ bool update_erp_next_seq_num;
+ u16 fils_erp_next_seq_num;
+ const u8 *pmk;
+ size_t pmk_len;
+ const u8 *pmkid;
+ enum nl80211_timeout_reason timeout_reason;
+};
+
+/**
+ * cfg80211_connect_done - notify cfg80211 of connection result
+ *
+ * @dev: network device
+ * @params: connection response parameters
+ * @gfp: allocation flags
+ *
+ * It should be called by the underlying driver once execution of the connection
+ * request from connect() has been completed. This is similar to
+ * cfg80211_connect_bss(), but takes a structure pointer for connection response
+ * parameters. Only one of the functions among cfg80211_connect_bss(),
+ * cfg80211_connect_result(), cfg80211_connect_timeout(),
+ * and cfg80211_connect_done() should be called.
+ */
+void cfg80211_connect_done(struct net_device *dev,
+ struct cfg80211_connect_resp_params *params,
+ gfp_t gfp);
+
+/**
* cfg80211_connect_bss - notify cfg80211 of connection result
*
* @dev: network device
@@ -5009,20 +5197,50 @@
* @req_ie_len: association request IEs length
* @resp_ie: association response IEs (may be %NULL)
* @resp_ie_len: assoc response IEs length
- * @status: status code, 0 for successful connection, use
- * %WLAN_STATUS_UNSPECIFIED_FAILURE if your device cannot give you
- * the real status code for failures.
+ * @status: status code, %WLAN_STATUS_SUCCESS for successful connection, use
+ * %WLAN_STATUS_UNSPECIFIED_FAILURE if your device cannot give you
+ * the real status code for failures. If this call is used to report a
+ * failure due to a timeout (e.g., not receiving an Authentication frame
+ * from the AP) instead of an explicit rejection by the AP, -1 is used to
+ * indicate that this is a failure, but without a status code.
+ * @timeout_reason is used to report the reason for the timeout in that
+ * case.
* @gfp: allocation flags
+ * @timeout_reason: reason for connection timeout. This is used when the
+ * connection fails due to a timeout instead of an explicit rejection from
+ * the AP. %NL80211_TIMEOUT_UNSPECIFIED is used when the timeout reason is
+ * not known. This value is used only if @status < 0 to indicate that the
+ * failure is due to a timeout and not due to explicit rejection by the AP.
+ * This value is ignored in other cases (@status >= 0).
*
- * It should be called by the underlying driver whenever connect() has
- * succeeded. This is similar to cfg80211_connect_result(), but with the
- * option of identifying the exact bss entry for the connection. Only one of
- * these functions should be called.
+ * It should be called by the underlying driver once execution of the connection
+ * request from connect() has been completed. This is similar to
+ * cfg80211_connect_result(), but with the option of identifying the exact bss
+ * entry for the connection. Only one of the functions among
+ * cfg80211_connect_bss(), cfg80211_connect_result(),
+ * cfg80211_connect_timeout(), and cfg80211_connect_done() should be called.
*/
-void cfg80211_connect_bss(struct net_device *dev, const u8 *bssid,
- struct cfg80211_bss *bss, const u8 *req_ie,
- size_t req_ie_len, const u8 *resp_ie,
- size_t resp_ie_len, int status, gfp_t gfp);
+static inline void
+cfg80211_connect_bss(struct net_device *dev, const u8 *bssid,
+ struct cfg80211_bss *bss, const u8 *req_ie,
+ size_t req_ie_len, const u8 *resp_ie,
+ size_t resp_ie_len, int status, gfp_t gfp,
+ enum nl80211_timeout_reason timeout_reason)
+{
+ struct cfg80211_connect_resp_params params;
+
+ memset(¶ms, 0, sizeof(params));
+ params.status = status;
+ params.bssid = bssid;
+ params.bss = bss;
+ params.req_ie = req_ie;
+ params.req_ie_len = req_ie_len;
+ params.resp_ie = resp_ie;
+ params.resp_ie_len = resp_ie_len;
+ params.timeout_reason = timeout_reason;
+
+ cfg80211_connect_done(dev, ¶ms, gfp);
+}
/**
* cfg80211_connect_result - notify cfg80211 of connection result
@@ -5033,13 +5251,16 @@
* @req_ie_len: association request IEs length
* @resp_ie: association response IEs (may be %NULL)
* @resp_ie_len: assoc response IEs length
- * @status: status code, 0 for successful connection, use
+ * @status: status code, %WLAN_STATUS_SUCCESS for successful connection, use
* %WLAN_STATUS_UNSPECIFIED_FAILURE if your device cannot give you
* the real status code for failures.
* @gfp: allocation flags
*
- * It should be called by the underlying driver whenever connect() has
- * succeeded.
+ * It should be called by the underlying driver once execution of the connection
+ * request from connect() has been completed. This is similar to
+ * cfg80211_connect_bss() which allows the exact bss entry to be specified. Only
+ * one of the functions among cfg80211_connect_bss(), cfg80211_connect_result(),
+ * cfg80211_connect_timeout(), and cfg80211_connect_done() should be called.
*/
static inline void
cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
@@ -5048,7 +5269,8 @@
u16 status, gfp_t gfp)
{
cfg80211_connect_bss(dev, bssid, NULL, req_ie, req_ie_len, resp_ie,
- resp_ie_len, status, gfp);
+ resp_ie_len, status, gfp,
+ NL80211_TIMEOUT_UNSPECIFIED);
}
/**
@@ -5059,19 +5281,23 @@
* @req_ie: association request IEs (maybe be %NULL)
* @req_ie_len: association request IEs length
* @gfp: allocation flags
+ * @timeout_reason: reason for connection timeout.
*
* It should be called by the underlying driver whenever connect() has failed
* in a sequence where no explicit authentication/association rejection was
* received from the AP. This could happen, e.g., due to not being able to send
* out the Authentication or Association Request frame or timing out while
- * waiting for the response.
+ * waiting for the response. Only one of the functions among
+ * cfg80211_connect_bss(), cfg80211_connect_result(),
+ * cfg80211_connect_timeout(), and cfg80211_connect_done() should be called.
*/
static inline void
cfg80211_connect_timeout(struct net_device *dev, const u8 *bssid,
- const u8 *req_ie, size_t req_ie_len, gfp_t gfp)
+ const u8 *req_ie, size_t req_ie_len, gfp_t gfp,
+ enum nl80211_timeout_reason timeout_reason)
{
cfg80211_connect_bss(dev, bssid, NULL, req_ie, req_ie_len, NULL, 0, -1,
- gfp);
+ gfp, timeout_reason);
}
/**
diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
index f5e625f..4341731 100644
--- a/include/net/ip6_route.h
+++ b/include/net/ip6_route.h
@@ -22,6 +22,7 @@
#include <net/flow.h>
#include <net/ip6_fib.h>
#include <net/sock.h>
+#include <net/lwtunnel.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/route.h>
@@ -233,4 +234,11 @@
return daddr;
}
+static inline bool rt6_duplicate_nexthop(struct rt6_info *a, struct rt6_info *b)
+{
+ return a->dst.dev == b->dst.dev &&
+ a->rt6i_idev == b->rt6i_idev &&
+ ipv6_addr_equal(&a->rt6i_gateway, &b->rt6i_gateway) &&
+ !lwtunnel_cmp_encap(a->dst.lwtstate, b->dst.lwtstate);
+}
#endif
diff --git a/include/net/vxlan.h b/include/net/vxlan.h
index 308adc4..9fce47e 100644
--- a/include/net/vxlan.h
+++ b/include/net/vxlan.h
@@ -221,9 +221,17 @@
bool no_share;
};
+struct vxlan_dev_node {
+ struct hlist_node hlist;
+ struct vxlan_dev *vxlan;
+};
+
/* Pseudo network device */
struct vxlan_dev {
- struct hlist_node hlist; /* vni hash table */
+ struct vxlan_dev_node hlist4; /* vni hash table for IPv4 socket */
+#if IS_ENABLED(CONFIG_IPV6)
+ struct vxlan_dev_node hlist6; /* vni hash table for IPv6 socket */
+#endif
struct list_head next; /* vxlan's per namespace list */
struct vxlan_sock __rcu *vn4_sock; /* listening socket for IPv4 */
#if IS_ENABLED(CONFIG_IPV6)
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index 9d249f6..69fa6b3 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -254,6 +254,7 @@
STARGET_CREATED = 1,
STARGET_RUNNING,
STARGET_REMOVE,
+ STARGET_CREATED_REMOVE,
STARGET_DEL,
};
diff --git a/include/soc/qcom/glink.h b/include/soc/qcom/glink.h
index 7b86481..4522b11 100644
--- a/include/soc/qcom/glink.h
+++ b/include/soc/qcom/glink.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017 The Linux Foundation. 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 and
@@ -340,6 +340,22 @@
*/
unsigned long glink_qos_get_ramp_time(void *handle, size_t pkt_size);
+/**
+ * glink_start_rx_rt() - Vote for RT thread priority on RX.
+ * @handle: Channel handle for which transaction are occurring.
+ *
+ * Return: 0 on success, standard Linux error codes on failure
+ */
+int glink_start_rx_rt(void *handle);
+
+/**
+ * glink_end_rx_rt() - Vote for RT thread priority on RX.
+ * @handle: Channel handle for which transaction are occurring.
+ *
+ * Return: 0 on success, standard Linux error codes on failure
+ */
+int glink_end_rx_rt(void *handle);
+
#else /* CONFIG_MSM_GLINK */
static inline void *glink_open(const struct glink_open_config *cfg_ptr)
{
@@ -428,5 +444,16 @@
{
return 0;
}
+
+static inline int glink_start_rx_rt(void *handle)
+{
+ return -ENODEV;
+}
+
+static inline int glink_end_rx_rt(void *handle)
+{
+ return -ENODEV;
+}
+
#endif /* CONFIG_MSM_GLINK */
#endif /* _SOC_QCOM_GLINK_H_ */
diff --git a/include/soc/qcom/msm-core.h b/include/soc/qcom/msm-core.h
index cd44615..f1c06a6 100644
--- a/include/soc/qcom/msm-core.h
+++ b/include/soc/qcom/msm-core.h
@@ -16,9 +16,12 @@
#ifdef CONFIG_APSS_CORE_EA
void set_cpu_throttled(struct cpumask *mask, bool throttling);
struct blocking_notifier_head *get_power_update_notifier(void);
+void trigger_cpu_pwr_stats_calc(void);
+struct cpu_pwr_stats *get_cpu_pwr_stats(void);
#else
static inline void set_cpu_throttled(struct cpumask *mask, bool throttling) {}
struct blocking_notifier_head *get_power_update_notifier(void) {return NULL; }
+static inline void trigger_cpu_pwr_stats_calc(void) {}
+struct cpu_pwr_stats *get_cpu_pwr_stats(void) {return NULL; }
#endif
#endif
-
diff --git a/include/soc/qcom/rpmh.h b/include/soc/qcom/rpmh.h
index 75e6ccd..f0b3d02 100644
--- a/include/soc/qcom/rpmh.h
+++ b/include/soc/qcom/rpmh.h
@@ -40,6 +40,8 @@
int rpmh_invalidate(struct rpmh_client *rc);
+int rpmh_ctrlr_idle(struct rpmh_client *rc);
+
int rpmh_flush(struct rpmh_client *rc);
int rpmh_read(struct rpmh_client *rc, u32 addr, u32 *resp);
@@ -82,6 +84,9 @@
static inline int rpmh_invalidate(struct rpmh_client *rc)
{ return -ENODEV; }
+static inline int rpmh_ctrlr_idle(struct rpmh_client *rc)
+{ return -ENODEV; }
+
static inline int rpmh_flush(struct rpmh_client *rc)
{ return -ENODEV; }
diff --git a/include/soc/qcom/secure_buffer.h b/include/soc/qcom/secure_buffer.h
index 665708d..12fa374 100644
--- a/include/soc/qcom/secure_buffer.h
+++ b/include/soc/qcom/secure_buffer.h
@@ -50,8 +50,6 @@
#define PERM_EXEC 0x1
#ifdef CONFIG_QCOM_SECURE_BUFFER
-int msm_secure_table(struct sg_table *table);
-int msm_unsecure_table(struct sg_table *table);
int hyp_assign_table(struct sg_table *table,
u32 *source_vm_list, int source_nelems,
int *dest_vmids, int *dest_perms,
@@ -59,17 +57,8 @@
extern int hyp_assign_phys(phys_addr_t addr, u64 size,
u32 *source_vmlist, int source_nelems,
int *dest_vmids, int *dest_perms, int dest_nelems);
-bool msm_secure_v2_is_supported(void);
const char *msm_secure_vmid_to_string(int secure_vmid);
#else
-static inline int msm_secure_table(struct sg_table *table)
-{
- return -EINVAL;
-}
-static inline int msm_unsecure_table(struct sg_table *table)
-{
- return -EINVAL;
-}
static inline int hyp_assign_table(struct sg_table *table,
u32 *source_vm_list, int source_nelems,
int *dest_vmids, int *dest_perms,
@@ -85,10 +74,6 @@
return -EINVAL;
}
-static inline bool msm_secure_v2_is_supported(void)
-{
- return false;
-}
static inline const char *msm_secure_vmid_to_string(int secure_vmid)
{
return "N/A";
diff --git a/include/soc/qcom/socinfo.h b/include/soc/qcom/socinfo.h
index dc404e4..f196d40 100644
--- a/include/soc/qcom/socinfo.h
+++ b/include/soc/qcom/socinfo.h
@@ -233,6 +233,7 @@
uint32_t socinfo_get_version(void);
uint32_t socinfo_get_raw_id(void);
char *socinfo_get_build_id(void);
+char *socinfo_get_id_string(void);
uint32_t socinfo_get_platform_type(void);
uint32_t socinfo_get_platform_subtype(void);
uint32_t socinfo_get_platform_version(void);
diff --git a/include/soc/qcom/system_pm.h b/include/soc/qcom/system_pm.h
index 0be089b..6d0993a 100644
--- a/include/soc/qcom/system_pm.h
+++ b/include/soc/qcom/system_pm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, The Linux Foundation. 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 and
@@ -17,12 +17,18 @@
int system_sleep_enter(uint64_t sleep_val);
void system_sleep_exit(void);
+
+bool system_sleep_allowed(void);
#else
static inline int system_sleep_enter(uint64_t sleep_val)
{ return -ENODEV; }
static inline void system_sleep_exit(void)
{ }
+
+static inline bool system_sleep_allowed(void)
+{ return false; }
+
#endif /* CONFIG_QTI_SYSTEM_PM */
#endif /* __SOC_QCOM_SYS_PM_H__ */
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 14f6445..bdab0b8 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -3666,7 +3666,7 @@
#define DEFAULT_POPP_TOPOLOGY 0x00010BE4
#define COMPRESSED_PASSTHROUGH_DEFAULT_TOPOLOGY 0x0001076B
#define COMPRESSED_PASSTHROUGH_NONE_TOPOLOGY 0x00010774
-#define VPM_TX_SM_ECNS_COPP_TOPOLOGY 0x00010F71
+#define VPM_TX_SM_ECNS_V2_COPP_TOPOLOGY 0x00010F89
#define VPM_TX_DM_FLUENCE_COPP_TOPOLOGY 0x00010F72
#define VPM_TX_QMIC_FLUENCE_COPP_TOPOLOGY 0x00010F75
#define VPM_TX_DM_RFECNS_COPP_TOPOLOGY 0x00010F86
@@ -8537,6 +8537,8 @@
#define VSS_ICOMMON_CMD_GET_PARAM_V2 0x0001133E
#define VSS_ICOMMON_RSP_GET_PARAM 0x00011008
+#define VSS_MAX_AVCS_NUM_SERVICES 25
+
/* ID of the Bass Boost module.
* This module supports the following parameter IDs:
* - #AUDPROC_PARAM_ID_BASS_BOOST_ENABLE
@@ -9197,6 +9199,74 @@
*/
} __packed;
+/* Q6Core Specific */
+#define AVCS_CMD_GET_FWK_VERSION (0x0001292C)
+#define AVCS_CMDRSP_GET_FWK_VERSION (0x0001292D)
+
+#define AVCS_SERVICE_ID_ALL (0xFFFFFFFF)
+#define APRV2_IDS_SERVICE_ID_ADSP_CVP_V (0xB)
+
+struct avcs_get_fwk_version {
+ /*
+ * Indicates the major version of the AVS build.
+ * This value is incremented on chipset family boundaries.
+ */
+ uint32_t build_major_version;
+
+ /*
+ * Minor version of the AVS build.
+ * This value represents the mainline to which the AVS build belongs.
+ */
+ uint32_t build_minor_version;
+
+ /* Indicates the AVS branch version to which the image belongs. */
+ uint32_t build_branch_version;
+
+ /* Indicates the AVS sub-branch or customer product line information. */
+ uint32_t build_subbranch_version;
+
+ /* Number of supported AVS services in the current build. */
+ uint32_t num_services;
+};
+
+struct avs_svc_api_info {
+ /*
+ * APRV2 service IDs for the individual static services.
+ *
+ * @values
+ * - APRV2_IDS_SERVICE_ID_ADSP_CORE_V
+ * - APRV2_IDS_SERVICE_ID_ADSP_AFE_V
+ * - APRV2_IDS_SERVICE_ID_ADSP_ASM_V
+ * - APRV2_IDS_SERVICE_ID_ADSP_ADM_V
+ * - APRV2_IDS_SERVICE_ID_ADSP_MVM_V
+ * - APRV2_IDS_SERVICE_ID_ADSP_CVS_V
+ * - APRV2_IDS_SERVICE_ID_ADSP_CVP_V
+ * - APRV2_IDS_SERVICE_ID_ADSP_LSM_V
+ */
+ uint32_t service_id;
+
+ /*
+ * Indicates the API version of the service.
+ *
+ * Each new API update that warrants a change on the HLOS side triggers
+ * an increment in the version.
+ */
+ uint32_t api_version;
+
+ /*
+ * Indicates the API increments on a sub-branch (not on the mainline).
+ *
+ * API branch version numbers can increment independently on different
+ * sub-branches.
+ */
+ uint32_t api_branch_version;
+};
+
+struct avcs_fwk_ver_info {
+ struct avcs_get_fwk_version avcs_fwk_version;
+ struct avs_svc_api_info *services;
+} __packed;
+
/* LSM Specific */
#define VW_FEAT_DIM (39)
diff --git a/include/sound/apr_audio.h b/include/sound/apr_audio.h
index eb35645..795ff56 100644
--- a/include/sound/apr_audio.h
+++ b/include/sound/apr_audio.h
@@ -687,7 +687,7 @@
#define DEFAULT_COPP_TOPOLOGY 0x00010be3
#define DEFAULT_POPP_TOPOLOGY 0x00010be4
-#define VPM_TX_SM_ECNS_COPP_TOPOLOGY 0x00010F71
+#define VPM_TX_SM_ECNS_V2_COPP_TOPOLOGY 0x00010F89
#define VPM_TX_DM_FLUENCE_COPP_TOPOLOGY 0x00010F72
#define VPM_TX_QMIC_FLUENCE_COPP_TOPOLOGY 0x00010F75
diff --git a/include/sound/q6core.h b/include/sound/q6core.h
index 0b8309a..111af67 100644
--- a/include/sound/q6core.h
+++ b/include/sound/q6core.h
@@ -13,6 +13,7 @@
#ifndef __Q6CORE_H__
#define __Q6CORE_H__
#include <linux/qdsp6v2/apr.h>
+#include <sound/apr_audio-v2.h>
@@ -21,6 +22,11 @@
bool q6core_is_adsp_ready(void);
+int q6core_get_service_version(uint32_t service_id,
+ struct avcs_fwk_ver_info *ver_info,
+ size_t size);
+size_t q6core_get_avcs_service_size(uint32_t service_id);
+
#define ADSP_CMD_SET_DTS_EAGLE_DATA_ID 0x00012919
#define DTS_EAGLE_LICENSE_ID 0x00028346
struct adsp_dts_eagle {
diff --git a/include/target/iscsi/iscsi_target_core.h b/include/target/iscsi/iscsi_target_core.h
index 4ac24f5..33b2e75 100644
--- a/include/target/iscsi/iscsi_target_core.h
+++ b/include/target/iscsi/iscsi_target_core.h
@@ -64,6 +64,14 @@
#define TA_DEFAULT_FABRIC_PROT_TYPE 0
/* TPG status needs to be enabled to return sendtargets discovery endpoint info */
#define TA_DEFAULT_TPG_ENABLED_SENDTARGETS 1
+/*
+ * Used to control the sending of keys with optional to respond state bit,
+ * as a workaround for non RFC compliant initiators,that do not propose,
+ * nor respond to specific keys required for login to complete.
+ *
+ * See iscsi_check_proposer_for_optional_reply() for more details.
+ */
+#define TA_DEFAULT_LOGIN_KEYS_WORKAROUND 1
#define ISCSI_IOV_DATA_BUFFER 5
@@ -766,6 +774,7 @@
u8 t10_pi;
u32 fabric_prot_type;
u32 tpg_enabled_sendtargets;
+ u32 login_keys_workaround;
struct iscsi_portal_group *tpg;
};
diff --git a/include/trace/events/msm_vidc.h b/include/trace/events/msm_vidc.h
index ea698bf..c6c446a 100644
--- a/include/trace/events/msm_vidc.h
+++ b/include/trace/events/msm_vidc.h
@@ -310,6 +310,39 @@
TP_ARGS(buffer_op, domain_num, partition_num, align, iova, buffer_size)
);
+DECLARE_EVENT_CLASS(msm_vidc_perf,
+
+ TP_PROTO(const char *name, unsigned long value),
+
+ TP_ARGS(name, value),
+
+ TP_STRUCT__entry(
+ __field(const char *, name)
+ __field(unsigned long, value)
+ ),
+
+ TP_fast_assign(
+ __entry->name = name;
+ __entry->value = value;
+ ),
+
+ TP_printk("%s %lu", __entry->name, __entry->value)
+);
+
+DEFINE_EVENT(msm_vidc_perf, msm_vidc_perf_clock_scale,
+
+ TP_PROTO(const char *clock_name, unsigned long frequency),
+
+ TP_ARGS(clock_name, frequency)
+);
+
+DEFINE_EVENT(msm_vidc_perf, msm_vidc_perf_bus_vote,
+
+ TP_PROTO(const char *governor_mode, unsigned long ab),
+
+ TP_ARGS(governor_mode, ab)
+);
+
#endif
#include <trace/define_trace.h>
diff --git a/include/trace/events/power.h b/include/trace/events/power.h
index 57693e7..cecfb8f 100644
--- a/include/trace/events/power.h
+++ b/include/trace/events/power.h
@@ -769,13 +769,14 @@
TRACE_EVENT(sugov_util_update,
TP_PROTO(int cpu,
- unsigned long util, unsigned long max_cap,
- unsigned long nl, unsigned long pl,
+ unsigned long util, unsigned long avg_cap,
+ unsigned long max_cap, unsigned long nl, unsigned long pl,
unsigned int flags),
- TP_ARGS(cpu, util, max_cap, nl, pl, flags),
+ TP_ARGS(cpu, util, avg_cap, max_cap, nl, pl, flags),
TP_STRUCT__entry(
__field( int, cpu)
__field( unsigned long, util)
+ __field( unsigned long, avg_cap)
__field( unsigned long, max_cap)
__field( unsigned long, nl)
__field( unsigned long, pl)
@@ -784,14 +785,16 @@
TP_fast_assign(
__entry->cpu = cpu;
__entry->util = util;
+ __entry->avg_cap = avg_cap;
__entry->max_cap = max_cap;
__entry->nl = nl;
__entry->pl = pl;
__entry->flags = flags;
),
- TP_printk("cpu=%d util=%lu max_cap=%lu nl=%lu pl=%lu flags=%x",
- __entry->cpu, __entry->util, __entry->max_cap,
- __entry->nl, __entry->pl, __entry->flags)
+ TP_printk("cpu=%d util=%lu avg_cap=%lu max_cap=%lu nl=%lu pl=%lu flags=0x%x",
+ __entry->cpu, __entry->util, __entry->avg_cap,
+ __entry->max_cap, __entry->nl,
+ __entry->pl, __entry->flags)
);
DECLARE_EVENT_CLASS(kpm_module,
diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h
index bbcb3d5..cf3f5e3 100644
--- a/include/trace/events/sched.h
+++ b/include/trace/events/sched.h
@@ -71,10 +71,8 @@
__field(unsigned long, cpu_load )
__field(unsigned int, rt_nr_running )
__field(unsigned int, cpus_allowed )
-#ifdef CONFIG_SCHED_WALT
__field(unsigned int, demand )
__field(unsigned int, pred_demand )
-#endif
),
TP_fast_assign(
@@ -87,24 +85,17 @@
__entry->cpu_load = task_rq(p)->cpu_load[0];
__entry->rt_nr_running = task_rq(p)->rt.rt_nr_running;
__entry->cpus_allowed = cpus_allowed;
-#ifdef CONFIG_SCHED_WALT
- __entry->demand = p->ravg.demand;
- __entry->pred_demand = p->ravg.pred_demand;
-#endif
+ __entry->demand = task_load(p);
+ __entry->pred_demand = task_pl(p);
),
- TP_printk("cpu=%d %s comm=%s pid=%d prio=%d nr_running=%u cpu_load=%lu rt_nr_running=%u affine=%x"
-#ifdef CONFIG_SCHED_WALT
- " demand=%u pred_demand=%u"
-#endif
- , __entry->cpu,
+ TP_printk("cpu=%d %s comm=%s pid=%d prio=%d nr_running=%u cpu_load=%lu rt_nr_running=%u affine=%x demand=%u pred_demand=%u",
+ __entry->cpu,
__entry->enqueue ? "enqueue" : "dequeue",
__entry->comm, __entry->pid,
__entry->prio, __entry->nr_running,
__entry->cpu_load, __entry->rt_nr_running, __entry->cpus_allowed
-#ifdef CONFIG_SCHED_WALT
, __entry->demand, __entry->pred_demand
-#endif
)
);
@@ -254,7 +245,7 @@
__entry->pred_demand = p->ravg.pred_demand;
memcpy(__entry->hist, p->ravg.sum_history,
RAVG_HIST_SIZE_MAX * sizeof(u32));
- __entry->nr_big_tasks = rq->hmp_stats.nr_big_tasks;
+ __entry->nr_big_tasks = rq->walt_stats.nr_big_tasks;
__entry->cpu = rq->cpu;
),
@@ -572,10 +563,10 @@
__entry->cpu = rq->cpu;
__entry->idle = idle;
__entry->nr_running = rq->nr_running;
- __entry->nr_big_tasks = rq->hmp_stats.nr_big_tasks;
+ __entry->nr_big_tasks = rq->walt_stats.nr_big_tasks;
__entry->load_scale_factor = cpu_load_scale_factor(rq->cpu);
__entry->capacity = cpu_capacity(rq->cpu);
- __entry->cumulative_runnable_avg = rq->hmp_stats.cumulative_runnable_avg;
+ __entry->cumulative_runnable_avg = rq->walt_stats.cumulative_runnable_avg;
__entry->irqload = irqload;
__entry->max_freq = cpu_max_freq(rq->cpu);
__entry->power_cost = power_cost;
@@ -627,7 +618,7 @@
__entry->grp_rq_ps = rq->grp_time.prev_runnable_sum;
__entry->nt_ps = rq->nt_prev_runnable_sum;
__entry->grp_nt_ps = rq->grp_time.nt_prev_runnable_sum;
- __entry->pl = rq->hmp_stats.pred_demands_sum;
+ __entry->pl = rq->walt_stats.pred_demands_sum;
__entry->load = load;
),
diff --git a/include/trace/events/thermal.h b/include/trace/events/thermal.h
index 031ae49..c0475a2 100644
--- a/include/trace/events/thermal.h
+++ b/include/trace/events/thermal.h
@@ -45,6 +45,23 @@
__entry->temp)
);
+TRACE_EVENT(cdev_update_start,
+
+ TP_PROTO(struct thermal_cooling_device *cdev),
+
+ TP_ARGS(cdev),
+
+ TP_STRUCT__entry(
+ __string(type, cdev->type)
+ ),
+
+ TP_fast_assign(
+ __assign_str(type, cdev->type);
+ ),
+
+ TP_printk("type=%s update start", __get_str(type))
+);
+
TRACE_EVENT(cdev_update,
TP_PROTO(struct thermal_cooling_device *cdev, unsigned long target,
@@ -98,6 +115,75 @@
show_tzt_type(__entry->trip_type))
);
+TRACE_EVENT(thermal_handle_trip,
+
+ TP_PROTO(struct thermal_zone_device *tz, int trip),
+
+ TP_ARGS(tz, trip),
+
+ TP_STRUCT__entry(
+ __string(thermal_zone, tz->type)
+ __field(int, id)
+ __field(int, trip)
+ ),
+
+ TP_fast_assign(
+ __assign_str(thermal_zone, tz->type);
+ __entry->id = tz->id;
+ __entry->trip = trip;
+ ),
+
+ TP_printk("thermal_zone=%s id=%d handle trip=%d",
+ __get_str(thermal_zone), __entry->id, __entry->trip)
+);
+
+TRACE_EVENT(thermal_device_update,
+
+ TP_PROTO(struct thermal_zone_device *tz, int event),
+
+ TP_ARGS(tz, event),
+
+ TP_STRUCT__entry(
+ __string(thermal_zone, tz->type)
+ __field(int, id)
+ __field(int, event)
+ ),
+
+ TP_fast_assign(
+ __assign_str(thermal_zone, tz->type);
+ __entry->id = tz->id;
+ __entry->event = event;
+ ),
+
+ TP_printk("thermal_zone=%s id=%d received event:%d",
+ __get_str(thermal_zone), __entry->id, __entry->event)
+);
+
+TRACE_EVENT(thermal_set_trip,
+
+ TP_PROTO(struct thermal_zone_device *tz),
+
+ TP_ARGS(tz),
+
+ TP_STRUCT__entry(
+ __string(thermal_zone, tz->type)
+ __field(int, id)
+ __field(int, low)
+ __field(int, high)
+ ),
+
+ TP_fast_assign(
+ __assign_str(thermal_zone, tz->type);
+ __entry->id = tz->id;
+ __entry->low = tz->prev_low_trip;
+ __entry->high = tz->prev_high_trip;
+ ),
+
+ TP_printk("thermal_zone=%s id=%d low trip=%d high trip=%d",
+ __get_str(thermal_zone), __entry->id, __entry->low,
+ __entry->high)
+);
+
TRACE_EVENT(thermal_power_cpu_get_power,
TP_PROTO(const struct cpumask *cpus, unsigned long freq, u32 *load,
size_t load_len, u32 dynamic_power, u32 static_power),
diff --git a/include/uapi/drm/msm_drm_pp.h b/include/uapi/drm/msm_drm_pp.h
index c7f2308..5f70a57 100644
--- a/include/uapi/drm/msm_drm_pp.h
+++ b/include/uapi/drm/msm_drm_pp.h
@@ -104,6 +104,7 @@
#define GAMUT_3D_MODE5_TBL_SZ 32
#define GAMUT_3D_MODE13_TBL_SZ 550
#define GAMUT_3D_SCALE_OFF_SZ 16
+#define GAMUT_3D_SCALEB_OFF_SZ 12
#define GAMUT_3D_TBL_NUM 4
#define GAMUT_3D_SCALE_OFF_TBL_NUM 3
#define GAMUT_3D_MAP_EN (1 << 0)
diff --git a/include/uapi/linux/android/binder.h b/include/uapi/linux/android/binder.h
index 7668b57..5539933 100644
--- a/include/uapi/linux/android/binder.h
+++ b/include/uapi/linux/android/binder.h
@@ -37,9 +37,56 @@
BINDER_TYPE_PTR = B_PACK_CHARS('p', 't', '*', B_TYPE_LARGE),
};
-enum {
+/**
+ * enum flat_binder_object_shifts: shift values for flat_binder_object_flags
+ * @FLAT_BINDER_FLAG_SCHED_POLICY_SHIFT: shift for getting scheduler policy.
+ *
+ */
+enum flat_binder_object_shifts {
+ FLAT_BINDER_FLAG_SCHED_POLICY_SHIFT = 9,
+};
+
+/**
+ * enum flat_binder_object_flags - flags for use in flat_binder_object.flags
+ */
+enum flat_binder_object_flags {
+ /**
+ * @FLAT_BINDER_FLAG_PRIORITY_MASK: bit-mask for min scheduler priority
+ *
+ * These bits can be used to set the minimum scheduler priority
+ * at which transactions into this node should run. Valid values
+ * in these bits depend on the scheduler policy encoded in
+ * @FLAT_BINDER_FLAG_SCHED_POLICY_MASK.
+ *
+ * For SCHED_NORMAL/SCHED_BATCH, the valid range is between [-20..19]
+ * For SCHED_FIFO/SCHED_RR, the value can run between [1..99]
+ */
FLAT_BINDER_FLAG_PRIORITY_MASK = 0xff,
+ /**
+ * @FLAT_BINDER_FLAG_ACCEPTS_FDS: whether the node accepts fds.
+ */
FLAT_BINDER_FLAG_ACCEPTS_FDS = 0x100,
+ /**
+ * @FLAT_BINDER_FLAG_SCHED_POLICY_MASK: bit-mask for scheduling policy
+ *
+ * These two bits can be used to set the min scheduling policy at which
+ * transactions on this node should run. These match the UAPI
+ * scheduler policy values, eg:
+ * 00b: SCHED_NORMAL
+ * 01b: SCHED_FIFO
+ * 10b: SCHED_RR
+ * 11b: SCHED_BATCH
+ */
+ FLAT_BINDER_FLAG_SCHED_POLICY_MASK =
+ 3U << FLAT_BINDER_FLAG_SCHED_POLICY_SHIFT,
+
+ /**
+ * @FLAT_BINDER_FLAG_INHERIT_RT: whether the node inherits RT policy
+ *
+ * Only when set, calls into this node will inherit a real-time
+ * scheduling policy from the caller (for synchronous transactions).
+ */
+ FLAT_BINDER_FLAG_INHERIT_RT = 0x800,
};
#ifdef BINDER_IPC_32BIT
@@ -186,6 +233,19 @@
#define BINDER_CURRENT_PROTOCOL_VERSION 8
#endif
+/*
+ * Use with BINDER_GET_NODE_DEBUG_INFO, driver reads ptr, writes to all fields.
+ * Set ptr to NULL for the first call to get the info for the first node, and
+ * then repeat the call passing the previously returned value to get the next
+ * nodes. ptr will be 0 when there are no more nodes.
+ */
+struct binder_node_debug_info {
+ binder_uintptr_t ptr;
+ binder_uintptr_t cookie;
+ __u32 has_strong_ref;
+ __u32 has_weak_ref;
+};
+
#define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read)
#define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, __s64)
#define BINDER_SET_MAX_THREADS _IOW('b', 5, __u32)
@@ -193,6 +253,7 @@
#define BINDER_SET_CONTEXT_MGR _IOW('b', 7, __s32)
#define BINDER_THREAD_EXIT _IOW('b', 8, __s32)
#define BINDER_VERSION _IOWR('b', 9, struct binder_version)
+#define BINDER_GET_NODE_DEBUG_INFO _IOWR('b', 11, struct binder_node_debug_info)
/*
* NOTE: Two special error codes you should check for when calling
diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h
index 0932378..e645f17 100644
--- a/include/uapi/linux/fuse.h
+++ b/include/uapi/linux/fuse.h
@@ -266,6 +266,7 @@
#define FUSE_PARALLEL_DIROPS (1 << 18)
#define FUSE_HANDLE_KILLPRIV (1 << 19)
#define FUSE_POSIX_ACL (1 << 20)
+#define FUSE_PASSTHROUGH (1 << 21)
/**
* CUSE INIT request/reply flags
@@ -498,7 +499,7 @@
struct fuse_open_out {
uint64_t fh;
uint32_t open_flags;
- uint32_t padding;
+ int32_t passthrough_fd;
};
struct fuse_release_in {
diff --git a/include/uapi/linux/hbtp_input.h b/include/uapi/linux/hbtp_input.h
index 9173c2a..3b124ff 100644
--- a/include/uapi/linux/hbtp_input.h
+++ b/include/uapi/linux/hbtp_input.h
@@ -6,6 +6,8 @@
#define HBTP_MAX_FINGER 20
#define HBTP_ABS_MT_FIRST ABS_MT_TOUCH_MAJOR
#define HBTP_ABS_MT_LAST ABS_MT_TOOL_Y
+#define MAX_ROI_SIZE 144
+#define MAX_ACCEL_SIZE 128
#define HBTP_EVENT_TYPE_DISPLAY "EVENT_TYPE=HBTP_DISPLAY"
@@ -20,6 +22,11 @@
__s32 orientation;
};
+struct hbtp_sensor_data {
+ __s16 accelBuffer[MAX_ACCEL_SIZE];
+ __s16 ROI[MAX_ROI_SIZE];
+};
+
struct hbtp_input_mt {
__s32 num_touches;
struct hbtp_input_touch touches[HBTP_MAX_FINGER];
@@ -68,6 +75,8 @@
enum hbtp_afe_signal)
#define HBTP_SET_POWER_CTRL _IOW(HBTP_INPUT_IOCTL_BASE, 206, \
enum hbtp_afe_power_ctrl)
+#define HBTP_SET_SENSORDATA _IOW(HBTP_INPUT_IOCTL_BASE, 207, \
+ struct hbtp_sensor_data)
#endif /* _UAPI_HBTP_INPUT_H */
diff --git a/include/uapi/linux/msm_ipa.h b/include/uapi/linux/msm_ipa.h
index 939ad08..51c0165 100644
--- a/include/uapi/linux/msm_ipa.h
+++ b/include/uapi/linux/msm_ipa.h
@@ -132,6 +132,8 @@
#define IPA_FLT_MAC_DST_ADDR_802_3 (1ul << 20)
#define IPA_FLT_MAC_ETHER_TYPE (1ul << 21)
#define IPA_FLT_MAC_DST_ADDR_L2TP (1ul << 22)
+#define IPA_FLT_TCP_SYN (1ul << 23)
+#define IPA_FLT_TCP_SYN_L2TP (1ul << 24)
/**
* maximal number of NAT PDNs in the PDN config table
@@ -892,22 +894,37 @@
* @hdr_len_remove: Specifies how much of the header needs to
be removed in bytes
* @eth_hdr_retained: Specifies if Ethernet header is retained or not
+ * @hdr_ofst_pkt_size_valid: Specifies if the Header offset is valid
+ * @hdr_ofst_pkt_size: If hdr_ofst_pkt_size_valid =1, this indicates where the
+ packet size field (2bytes) resides
+ * @hdr_endianness: 0:little endian, 1:big endian
*/
struct ipa_l2tp_header_remove_procparams {
uint32_t hdr_len_remove:8;
uint32_t eth_hdr_retained:1;
- uint32_t reserved:23;
+ /* Following fields are valid if eth_hdr_retained =1 ( bridge mode) */
+ uint32_t hdr_ofst_pkt_size_valid:1;
+ uint32_t hdr_ofst_pkt_size:6;
+ uint32_t hdr_endianness:1;
+ uint32_t reserved:15;
};
/**
- * union ipa_l2tp_hdr_proc_ctx_params -
+ * struct ipa_l2tp_hdr_proc_ctx_params -
* @hdr_add_param: parameters for header add
* @hdr_remove_param: parameters for header remove
+ * @is_dst_pipe_valid: if dst pipe is valid
+ * @dst_pipe: destination pipe
*/
-union ipa_l2tp_hdr_proc_ctx_params {
+struct ipa_l2tp_hdr_proc_ctx_params {
struct ipa_l2tp_header_add_procparams hdr_add_param;
struct ipa_l2tp_header_remove_procparams hdr_remove_param;
+ uint8_t is_dst_pipe_valid;
+ enum ipa_client_type dst_pipe;
};
+
+#define L2TP_USER_SPACE_SPECIFY_DST_PIPE
+
/**
* struct ipa_hdr_proc_ctx_add - processing context descriptor includes
* in and out parameters
@@ -924,7 +941,7 @@
uint32_t hdr_hdl;
uint32_t proc_ctx_hdl;
int status;
- union ipa_l2tp_hdr_proc_ctx_params l2tp_params;
+ struct ipa_l2tp_hdr_proc_ctx_params l2tp_params;
};
#define IPA_L2TP_HDR_PROC_SUPPORT
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 7d1e3b2..8c0fc7b 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -173,6 +173,42 @@
*/
/**
+ * DOC: FILS shared key authentication offload
+ *
+ * FILS shared key authentication offload can be advertized by drivers by
+ * setting @NL80211_EXT_FEATURE_FILS_SK_OFFLOAD flag. The drivers that support
+ * FILS shared key authentication offload should be able to construct the
+ * authentication and association frames for FILS shared key authentication and
+ * eventually do a key derivation as per IEEE 802.11ai. The below additional
+ * parameters should be given to driver in %NL80211_CMD_CONNECT.
+ * %NL80211_ATTR_FILS_ERP_USERNAME - used to construct keyname_nai
+ * %NL80211_ATTR_FILS_ERP_REALM - used to construct keyname_nai
+ * %NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM - used to construct erp message
+ * %NL80211_ATTR_FILS_ERP_RRK - used to generate the rIK and rMSK
+ * rIK should be used to generate an authentication tag on the ERP message and
+ * rMSK should be used to derive a PMKSA.
+ * rIK, rMSK should be generated and keyname_nai, sequence number should be used
+ * as specified in IETF RFC 6696.
+ *
+ * When FILS shared key authentication is completed, driver needs to provide the
+ * below additional parameters to userspace.
+ * %NL80211_ATTR_FILS_KEK - used for key renewal
+ * %NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM - used in further EAP-RP exchanges
+ * %NL80211_ATTR_PMKID - used to identify the PMKSA used/generated
+ * %Nl80211_ATTR_PMK - used to update PMKSA cache in userspace
+ * The PMKSA can be maintained in userspace persistently so that it can be used
+ * later after reboots or wifi turn off/on also.
+ *
+ * %NL80211_ATTR_FILS_CACHE_ID is the cache identifier advertized by a FILS
+ * capable AP supporting PMK caching. It specifies the scope within which the
+ * PMKSAs are cached in an ESS. %NL80211_CMD_SET_PMKSA and
+ * %NL80211_CMD_DEL_PMKSA are enhanced to allow support for PMKSA caching based
+ * on FILS cache identifier. Additionally %NL80211_ATTR_PMK is used with
+ * %NL80211_SET_PMKSA to specify the PMK corresponding to a PMKSA for driver to
+ * use in a FILS shared key connection with PMKSA caching.
+ */
+
+/**
* enum nl80211_commands - supported nl80211 commands
*
* @NL80211_CMD_UNSPEC: unspecified command to catch errors
@@ -370,10 +406,18 @@
* @NL80211_CMD_NEW_SURVEY_RESULTS: survey data notification (as a reply to
* NL80211_CMD_GET_SURVEY and on the "scan" multicast group)
*
- * @NL80211_CMD_SET_PMKSA: Add a PMKSA cache entry, using %NL80211_ATTR_MAC
- * (for the BSSID) and %NL80211_ATTR_PMKID.
+ * @NL80211_CMD_SET_PMKSA: Add a PMKSA cache entry using %NL80211_ATTR_MAC
+ * (for the BSSID), %NL80211_ATTR_PMKID, and optionally %NL80211_ATTR_PMK
+ * (PMK is used for PTKSA derivation in case of FILS shared key offload) or
+ * using %NL80211_ATTR_SSID, %NL80211_ATTR_FILS_CACHE_ID,
+ * %NL80211_ATTR_PMKID, and %NL80211_ATTR_PMK in case of FILS
+ * authentication where %NL80211_ATTR_FILS_CACHE_ID is the identifier
+ * advertized by a FILS capable AP identifying the scope of PMKSA in an
+ * ESS.
* @NL80211_CMD_DEL_PMKSA: Delete a PMKSA cache entry, using %NL80211_ATTR_MAC
- * (for the BSSID) and %NL80211_ATTR_PMKID.
+ * (for the BSSID) and %NL80211_ATTR_PMKID or using %NL80211_ATTR_SSID,
+ * %NL80211_ATTR_FILS_CACHE_ID, and %NL80211_ATTR_PMKID in case of FILS
+ * authentication.
* @NL80211_CMD_FLUSH_PMKSA: Flush all PMKSA cache entries.
*
* @NL80211_CMD_REG_CHANGE: indicates to userspace the regulatory domain
@@ -600,6 +644,20 @@
*
* @NL80211_CMD_SET_WDS_PEER: Set the MAC address of the peer on a WDS interface.
*
+ * @NL80211_CMD_SET_MULTICAST_TO_UNICAST: Configure if this AP should perform
+ * multicast to unicast conversion. When enabled, all multicast packets
+ * with ethertype ARP, IPv4 or IPv6 (possibly within an 802.1Q header)
+ * will be sent out to each station once with the destination (multicast)
+ * MAC address replaced by the station's MAC address. Note that this may
+ * break certain expectations of the receiver, e.g. the ability to drop
+ * unicast IP packets encapsulated in multicast L2 frames, or the ability
+ * to not send destination unreachable messages in such cases.
+ * This can only be toggled per BSS. Configure this on an interface of
+ * type %NL80211_IFTYPE_AP. It applies to all its VLAN interfaces
+ * (%NL80211_IFTYPE_AP_VLAN), except for those in 4addr (WDS) mode.
+ * If %NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED is not present with this
+ * command, the feature is disabled.
+ *
* @NL80211_CMD_JOIN_MESH: Join a mesh. The mesh ID must be given, and initial
* mesh config parameters may be given.
* @NL80211_CMD_LEAVE_MESH: Leave the mesh network -- no special arguments, the
@@ -874,6 +932,12 @@
* This will contain a %NL80211_ATTR_NAN_MATCH nested attribute and
* %NL80211_ATTR_COOKIE.
*
+ * @NL80211_CMD_UPDATE_CONNECT_PARAMS: Update one or more connect parameters
+ * for subsequent roaming cases if the driver or firmware uses internal
+ * BSS selection. This command can be issued only while connected and it
+ * does not result in a change for the current association. Currently,
+ * only the %NL80211_ATTR_IE data is used and updated with this command.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -1069,6 +1133,10 @@
NL80211_CMD_CHANGE_NAN_CONFIG,
NL80211_CMD_NAN_MATCH,
+ NL80211_CMD_SET_MULTICAST_TO_UNICAST,
+
+ NL80211_CMD_UPDATE_CONNECT_PARAMS,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -1638,8 +1706,16 @@
* the connection request from a station. nl80211_connect_failed_reason
* enum has different reasons of connection failure.
*
- * @NL80211_ATTR_SAE_DATA: SAE elements in Authentication frames. This starts
- * with the Authentication transaction sequence number field.
+ * @NL80211_ATTR_AUTH_DATA: Fields and elements in Authentication frames.
+ * This contains the authentication frame body (non-IE and IE data),
+ * excluding the Authentication algorithm number, i.e., starting at the
+ * Authentication transaction sequence number field. It is used with
+ * authentication algorithms that need special fields to be added into
+ * the frames (SAE and FILS). Currently, only the SAE cases use the
+ * initial two fields (Authentication transaction sequence number and
+ * Status code). However, those fields are included in the attribute data
+ * for all authentication algorithms to keep the attribute definition
+ * consistent.
*
* @NL80211_ATTR_VHT_CAPABILITY: VHT Capability information element (from
* association request when used with NL80211_CMD_NEW_STATION)
@@ -1936,10 +2012,61 @@
* attribute.
* @NL80211_ATTR_NAN_MATCH: used to report a match. This is a nested attribute.
* See &enum nl80211_nan_match_attributes.
+ * @NL80211_ATTR_FILS_KEK: KEK for FILS (Re)Association Request/Response frame
+ * protection.
+ * @NL80211_ATTR_FILS_NONCES: Nonces (part of AAD) for FILS (Re)Association
+ * Request/Response frame protection. This attribute contains the 16 octet
+ * STA Nonce followed by 16 octets of AP Nonce.
+ *
+ * @NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED: Indicates whether or not multicast
+ * packets should be send out as unicast to all stations (flag attribute).
*
* @NL80211_ATTR_BSSID: The BSSID of the AP. Note that %NL80211_ATTR_MAC is also
* used in various commands/events for specifying the BSSID.
*
+ * @NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI: Relative RSSI threshold by which
+ * other BSSs has to be better or slightly worse than the current
+ * connected BSS so that they get reported to user space.
+ * This will give an opportunity to userspace to consider connecting to
+ * other matching BSSs which have better or slightly worse RSSI than
+ * the current connected BSS by using an offloaded operation to avoid
+ * unnecessary wakeups.
+ *
+ * @NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST: When present the RSSI level for BSSs in
+ * the specified band is to be adjusted before doing
+ * %NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI based comparision to figure out
+ * better BSSs. The attribute value is a packed structure
+ * value as specified by &struct nl80211_bss_select_rssi_adjust.
+ *
+ * @NL80211_ATTR_TIMEOUT_REASON: The reason for which an operation timed out.
+ * u32 attribute with an &enum nl80211_timeout_reason value. This is used,
+ * e.g., with %NL80211_CMD_CONNECT event.
+ *
+ * @NL80211_ATTR_FILS_ERP_USERNAME: EAP Re-authentication Protocol (ERP)
+ * username part of NAI used to refer keys rRK and rIK. This is used with
+ * %NL80211_CMD_CONNECT.
+ *
+ * @NL80211_ATTR_FILS_ERP_REALM: EAP Re-authentication Protocol (ERP) realm part
+ * of NAI specifying the domain name of the ER server. This is used with
+ * %NL80211_CMD_CONNECT.
+ *
+ * @NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM: Unsigned 16-bit ERP next sequence number
+ * to use in ERP messages. This is used in generating the FILS wrapped data
+ * for FILS authentication and is used with %NL80211_CMD_CONNECT.
+ *
+ * @NL80211_ATTR_FILS_ERP_RRK: ERP re-authentication Root Key (rRK) for the
+ * NAI specified by %NL80211_ATTR_FILS_ERP_USERNAME and
+ * %NL80211_ATTR_FILS_ERP_REALM. This is used for generating rIK and rMSK
+ * from successful FILS authentication and is used with
+ * %NL80211_CMD_CONNECT.
+ *
+ * @NL80211_ATTR_FILS_CACHE_ID: A 2-octet identifier advertized by a FILS AP
+ * identifying the scope of PMKSAs. This is used with
+ * @NL80211_CMD_SET_PMKSA and @NL80211_CMD_DEL_PMKSA.
+ *
+ * @NL80211_ATTR_PMK: PMK for the PMKSA identified by %NL80211_ATTR_PMKID.
+ * This is used with @NL80211_CMD_SET_PMKSA.
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2198,7 +2325,7 @@
NL80211_ATTR_CONN_FAILED_REASON,
- NL80211_ATTR_SAE_DATA,
+ NL80211_ATTR_AUTH_DATA,
NL80211_ATTR_VHT_CAPABILITY,
@@ -2339,8 +2466,26 @@
NL80211_ATTR_NAN_FUNC,
NL80211_ATTR_NAN_MATCH,
+ NL80211_ATTR_FILS_KEK,
+ NL80211_ATTR_FILS_NONCES,
+
+ NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED,
+
NL80211_ATTR_BSSID,
+ NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI,
+ NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST,
+
+ NL80211_ATTR_TIMEOUT_REASON,
+
+ NL80211_ATTR_FILS_ERP_USERNAME,
+ NL80211_ATTR_FILS_ERP_REALM,
+ NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM,
+ NL80211_ATTR_FILS_ERP_RRK,
+ NL80211_ATTR_FILS_CACHE_ID,
+
+ NL80211_ATTR_PMK,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -2352,6 +2497,7 @@
#define NL80211_ATTR_SCAN_GENERATION NL80211_ATTR_GENERATION
#define NL80211_ATTR_MESH_PARAMS NL80211_ATTR_MESH_CONFIG
#define NL80211_ATTR_IFACE_SOCKET_OWNER NL80211_ATTR_SOCKET_OWNER
+#define NL80211_ATTR_SAE_DATA NL80211_ATTR_AUTH_DATA
/*
* Allow user space programs to use #ifdef on new attributes by defining them
@@ -3032,6 +3178,13 @@
* how this API was implemented in the past. Also, due to the same problem,
* the only way to create a matchset with only an RSSI filter (with this
* attribute) is if there's only a single matchset with the RSSI attribute.
+ * @NL80211_SCHED_SCAN_MATCH_ATTR_RELATIVE_RSSI: Flag indicating whether
+ * %NL80211_SCHED_SCAN_MATCH_ATTR_RSSI to be used as absolute RSSI or
+ * relative to current bss's RSSI.
+ * @NL80211_SCHED_SCAN_MATCH_ATTR_RSSI_ADJUST: When present the RSSI level for
+ * BSS-es in the specified band is to be adjusted before doing
+ * RSSI-based BSS selection. The attribute value is a packed structure
+ * value as specified by &struct nl80211_bss_select_rssi_adjust.
* @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter
* attribute number currently defined
* @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use
@@ -3041,6 +3194,8 @@
NL80211_SCHED_SCAN_MATCH_ATTR_SSID,
NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
+ NL80211_SCHED_SCAN_MATCH_ATTR_RELATIVE_RSSI,
+ NL80211_SCHED_SCAN_MATCH_ATTR_RSSI_ADJUST,
/* keep last */
__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST,
@@ -3665,6 +3820,9 @@
* @NL80211_AUTHTYPE_FT: Fast BSS Transition (IEEE 802.11r)
* @NL80211_AUTHTYPE_NETWORK_EAP: Network EAP (some Cisco APs and mainly LEAP)
* @NL80211_AUTHTYPE_SAE: Simultaneous authentication of equals
+ * @NL80211_AUTHTYPE_FILS_SK: Fast Initial Link Setup shared key
+ * @NL80211_AUTHTYPE_FILS_SK_PFS: Fast Initial Link Setup shared key with PFS
+ * @NL80211_AUTHTYPE_FILS_PK: Fast Initial Link Setup public key
* @__NL80211_AUTHTYPE_NUM: internal
* @NL80211_AUTHTYPE_MAX: maximum valid auth algorithm
* @NL80211_AUTHTYPE_AUTOMATIC: determine automatically (if necessary by
@@ -3677,6 +3835,9 @@
NL80211_AUTHTYPE_FT,
NL80211_AUTHTYPE_NETWORK_EAP,
NL80211_AUTHTYPE_SAE,
+ NL80211_AUTHTYPE_FILS_SK,
+ NL80211_AUTHTYPE_FILS_SK_PFS,
+ NL80211_AUTHTYPE_FILS_PK,
/* keep last */
__NL80211_AUTHTYPE_NUM,
@@ -4643,6 +4804,20 @@
* configuration (AP/mesh) with HT rates.
* @NL80211_EXT_FEATURE_BEACON_RATE_VHT: Driver supports beacon rate
* configuration (AP/mesh) with VHT rates.
+ * @NL80211_EXT_FEATURE_FILS_STA: This driver supports Fast Initial Link Setup
+ * with user space SME (NL80211_CMD_AUTHENTICATE) in station mode.
+ * @NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA: This driver supports randomized TA
+ * in @NL80211_CMD_FRAME while not associated.
+ * @NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED: This driver supports
+ * randomized TA in @NL80211_CMD_FRAME while associated.
+ * @NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI: The driver supports sched_scan
+ * for reporting BSSs with better RSSI than the current connected BSS
+ * (%NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI).
+ * @NL80211_EXT_FEATURE_CQM_RSSI_LIST: With this driver the
+ * %NL80211_ATTR_CQM_RSSI_THOLD attribute accepts a list of zero or more
+ * RSSI threshold values to monitor rather than exactly one threshold.
+ * @NL80211_EXT_FEATURE_FILS_SK_OFFLOAD: Driver SME supports FILS shared key
+ * authentication with %NL80211_CMD_CONNECT.
*
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
@@ -4657,6 +4832,12 @@
NL80211_EXT_FEATURE_BEACON_RATE_LEGACY,
NL80211_EXT_FEATURE_BEACON_RATE_HT,
NL80211_EXT_FEATURE_BEACON_RATE_VHT,
+ NL80211_EXT_FEATURE_FILS_STA,
+ NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA,
+ NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED,
+ NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI,
+ NL80211_EXT_FEATURE_CQM_RSSI_LIST,
+ NL80211_EXT_FEATURE_FILS_SK_OFFLOAD,
/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
@@ -4696,6 +4877,21 @@
};
/**
+ * enum nl80211_timeout_reason - timeout reasons
+ *
+ * @NL80211_TIMEOUT_UNSPECIFIED: Timeout reason unspecified.
+ * @NL80211_TIMEOUT_SCAN: Scan (AP discovery) timed out.
+ * @NL80211_TIMEOUT_AUTH: Authentication timed out.
+ * @NL80211_TIMEOUT_ASSOC: Association timed out.
+ */
+enum nl80211_timeout_reason {
+ NL80211_TIMEOUT_UNSPECIFIED,
+ NL80211_TIMEOUT_SCAN,
+ NL80211_TIMEOUT_AUTH,
+ NL80211_TIMEOUT_ASSOC,
+};
+
+/**
* enum nl80211_scan_flags - scan request control flags
*
* Scan request control flags are used to control the handling
diff --git a/include/uapi/linux/spcom.h b/include/uapi/linux/spcom.h
index 9b6b9b7..39b1be0 100644
--- a/include/uapi/linux/spcom.h
+++ b/include/uapi/linux/spcom.h
@@ -30,6 +30,12 @@
* with special size SPCOM_GET_NEXT_REQUEST_SIZE.
*/
+/*
+ * Maximum number of channel between Secure Processor and HLOS.
+ * including predefined channels, like "sp_kernel".
+ */
+#define SPCOM_MAX_CHANNELS 0x20
+
/* Maximum size (including null) for channel names */
#define SPCOM_CHANNEL_NAME_SIZE 32
diff --git a/include/uapi/linux/usb/ch9.h b/include/uapi/linux/usb/ch9.h
index a8acc24..0e5ce0d 100644
--- a/include/uapi/linux/usb/ch9.h
+++ b/include/uapi/linux/usb/ch9.h
@@ -1051,6 +1051,30 @@
*/
#define USB_DT_USB_SSP_CAP_SIZE(ssac) (16 + ssac * 4)
+/*
+ * Configuration Summary descriptors: Defines a list of functions in the
+ * configuration. This descriptor may be used by Host software to decide
+ * which Configuration to use to obtain the desired functionality.
+ */
+#define USB_CAP_TYPE_CONFIG_SUMMARY 0x10
+
+struct function_class_info {
+ __u8 bClass;
+ __u8 bSubClass;
+ __u8 bProtocol;
+};
+
+struct usb_config_summary_descriptor {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDevCapabilityType;
+ __u16 bcdVersion;
+ __u8 bConfigurationValue;
+ __u8 bMaxPower;
+ __u8 bNumFunctions;
+ struct function_class_info cs_info[];
+} __attribute__((packed));
+
/*-------------------------------------------------------------------------*/
/* USB_DT_WIRELESS_ENDPOINT_COMP: companion descriptor associated with
diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
index 731b2f0..5183111 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -1079,6 +1079,26 @@
#define V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR_10BIT \
(V4L2_CID_MPEG_MSM_VIDC_BASE + 110)
+#define V4L2_CID_MPEG_VIDC_VIDEO_TME_PROFILE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 111)
+
+enum v4l2_mpeg_vidc_video_tme_profile {
+ V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_0 = 0,
+ V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_1 = 1,
+ V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_2 = 2,
+ V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_3 = 3,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_TME_LEVEL \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 112)
+
+enum v4l2_mpeg_vidc_video_tme_level {
+ V4L2_MPEG_VIDC_VIDEO_TME_LEVEL_INTEGER = 0,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_TME_PAYLOAD_VERSION \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 113)
+
/* Camera class control IDs */
#define V4L2_CID_CAMERA_CLASS_BASE (V4L2_CTRL_CLASS_CAMERA | 0x900)
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 4f1f9e9..85b7e87 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -613,6 +613,7 @@
#define V4L2_PIX_FMT_VP8 v4l2_fourcc('V', 'P', '8', '0') /* VP8 */
#define V4L2_PIX_FMT_VP9 v4l2_fourcc('V', 'P', '9', '0') /* VP9 */
#define V4L2_PIX_FMT_HEVC v4l2_fourcc('H', 'E', 'V', 'C') /* for HEVC stream */
+#define V4L2_PIX_FMT_TME v4l2_fourcc('T', 'M', 'E', '0') /* for TME stream */
/* Vendor-specific formats */
#define V4L2_PIX_FMT_CPIA1 v4l2_fourcc('C', 'P', 'I', 'A') /* cpia1 YUV */
diff --git a/include/uapi/media/msm_media_info.h b/include/uapi/media/msm_media_info.h
index be87b1e..4f12e5c 100644
--- a/include/uapi/media/msm_media_info.h
+++ b/include/uapi/media/msm_media_info.h
@@ -769,11 +769,49 @@
* + max(Extradata, Y_Stride * 48), 4096)
*/
COLOR_FMT_P010_UBWC,
+ /* Venus P010:
+ * YUV 4:2:0 image with a plane of 10 bit Y samples followed
+ * by an interleaved U/V plane containing 10 bit 2x2 subsampled
+ * colour difference samples.
+ *
+ * <-------- Y/UV_Stride -------->
+ * <------- Width ------->
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . ^ ^
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | |
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . Height |
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | Y_Scanlines
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | |
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | |
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | |
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . V |
+ * . . . . . . . . . . . . . . . . |
+ * . . . . . . . . . . . . . . . . |
+ * . . . . . . . . . . . . . . . . |
+ * . . . . . . . . . . . . . . . . V
+ * U V U V U V U V U V U V . . . . ^
+ * U V U V U V U V U V U V . . . . |
+ * U V U V U V U V U V U V . . . . |
+ * U V U V U V U V U V U V . . . . UV_Scanlines
+ * . . . . . . . . . . . . . . . . |
+ * . . . . . . . . . . . . . . . . V
+ * . . . . . . . . . . . . . . . . --> Buffer size alignment
+ *
+ * Y_Stride : Width * 2 aligned to 128
+ * UV_Stride : Width * 2 aligned to 128
+ * Y_Scanlines: Height aligned to 32
+ * UV_Scanlines: Height/2 aligned to 16
+ * Extradata: Arbitrary (software-imposed) padding
+ * Total size = align((Y_Stride * Y_Scanlines
+ * + UV_Stride * UV_Scanlines
+ * + max(Extradata, Y_Stride * 8), 4096)
+ */
+ COLOR_FMT_P010,
};
#define COLOR_FMT_RGBA1010102_UBWC COLOR_FMT_RGBA1010102_UBWC
#define COLOR_FMT_RGB565_UBWC COLOR_FMT_RGB565_UBWC
#define COLOR_FMT_P010_UBWC COLOR_FMT_P010_UBWC
+#define COLOR_FMT_P010 COLOR_FMT_P010
static inline unsigned int VENUS_EXTRADATA_SIZE(int width, int height)
{
@@ -818,6 +856,10 @@
alignment = 256;
stride = MSM_MEDIA_ALIGN(width * 2, alignment);
break;
+ case COLOR_FMT_P010:
+ alignment = 128;
+ stride = MSM_MEDIA_ALIGN(width*2, alignment);
+ break;
default:
break;
}
@@ -856,6 +898,10 @@
alignment = 256;
stride = MSM_MEDIA_ALIGN(width * 2, alignment);
break;
+ case COLOR_FMT_P010:
+ alignment = 128;
+ stride = MSM_MEDIA_ALIGN(width*2, alignment);
+ break;
default:
break;
}
@@ -882,6 +928,7 @@
case COLOR_FMT_NV12:
case COLOR_FMT_NV12_MVTB:
case COLOR_FMT_NV12_UBWC:
+ case COLOR_FMT_P010:
alignment = 32;
break;
case COLOR_FMT_NV12_BPP10_UBWC:
@@ -916,6 +963,7 @@
case COLOR_FMT_NV12_MVTB:
case COLOR_FMT_NV12_BPP10_UBWC:
case COLOR_FMT_P010_UBWC:
+ case COLOR_FMT_P010:
alignment = 16;
break;
case COLOR_FMT_NV12_UBWC:
@@ -1204,6 +1252,7 @@
switch (color_fmt) {
case COLOR_FMT_NV21:
case COLOR_FMT_NV12:
+ case COLOR_FMT_P010:
uv_alignment = 4096;
y_plane = y_stride * y_sclines;
uv_plane = uv_stride * uv_sclines + uv_alignment;
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 44c17f4..8ce679d 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -885,6 +885,11 @@
if (err)
return err;
+ if (is_pointer_value(env, insn->src_reg)) {
+ verbose("R%d leaks addr into mem\n", insn->src_reg);
+ return -EACCES;
+ }
+
/* check whether atomic_add can read the memory */
err = check_mem_access(env, insn->dst_reg, insn->off,
BPF_SIZE(insn->code), BPF_READ, -1);
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index c0644f4..7bb21fd 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -6616,7 +6616,7 @@
struct task_struct *task;
int count = 0;
- seq_printf(seq, "css_set %p\n", cset);
+ seq_printf(seq, "css_set %pK\n", cset);
list_for_each_entry(task, &cset->tasks, cg_list) {
if (count++ > MAX_TASKS_SHOWN_PER_CSS)
diff --git a/kernel/events/core.c b/kernel/events/core.c
index e2ac135..d1bed63 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -358,6 +358,32 @@
EVENT_ALL = EVENT_FLEXIBLE | EVENT_PINNED,
};
+/* The shared events struct. */
+#define SHARED_EVENTS_MAX 7
+
+struct shared_events_str {
+ /*
+ * Mutex to serialize access to shared list. Needed for the
+ * read/modify/write sequences.
+ */
+ struct mutex list_mutex;
+
+ /*
+ * A 1 bit for an index indicates that the slot is being used for
+ * an event. A 0 means that the slot can be used.
+ */
+ DECLARE_BITMAP(used_mask, SHARED_EVENTS_MAX);
+
+ /*
+ * The kernel events that are shared for a cpu;
+ */
+ struct perf_event *events[SHARED_EVENTS_MAX];
+ struct perf_event_attr attr[SHARED_EVENTS_MAX];
+ atomic_t refcount[SHARED_EVENTS_MAX];
+};
+
+static struct shared_events_str __percpu *shared_events;
+
/*
* perf_sched_events : >0 events exist
* perf_cgroup_events: >0 per-cpu cgroup events exist on this cpu
@@ -4079,6 +4105,35 @@
static void perf_addr_filters_splice(struct perf_event *event,
struct list_head *head);
+static int
+perf_event_delete_kernel_shared(struct perf_event *event)
+{
+ int rc = -1, cpu = event->cpu;
+ struct shared_events_str *shrd_events;
+ unsigned long idx;
+
+ if (!shared_events || (u32)cpu >= nr_cpu_ids)
+ return 0;
+
+ shrd_events = per_cpu_ptr(shared_events, cpu);
+
+ mutex_lock(&shrd_events->list_mutex);
+
+ for_each_set_bit(idx, shrd_events->used_mask, SHARED_EVENTS_MAX) {
+ if (shrd_events->events[idx] == event) {
+ if (atomic_dec_and_test(&shrd_events->refcount[idx])) {
+ clear_bit(idx, shrd_events->used_mask);
+ shrd_events->events[idx] = NULL;
+ }
+ rc = (int)atomic_read(&shrd_events->refcount[idx]);
+ break;
+ }
+ }
+
+ mutex_unlock(&shrd_events->list_mutex);
+ return rc;
+}
+
static void _free_event(struct perf_event *event)
{
irq_work_sync(&event->pending);
@@ -4216,8 +4271,12 @@
goto no_ctx;
}
- if (!is_kernel_event(event))
+ if (!is_kernel_event(event)) {
perf_remove_from_owner(event);
+ } else {
+ if (perf_event_delete_kernel_shared(event) > 0)
+ return 0;
+ }
ctx = perf_event_ctx_lock(event);
WARN_ON_ONCE(ctx->parent_ctx);
@@ -7112,21 +7171,6 @@
perf_output_end(&handle);
}
-static bool sample_is_allowed(struct perf_event *event, struct pt_regs *regs)
-{
- /*
- * Due to interrupt latency (AKA "skid"), we may enter the
- * kernel before taking an overflow, even if the PMU is only
- * counting user events.
- * To avoid leaking information to userspace, we must always
- * reject kernel samples when exclude_kernel is set.
- */
- if (event->attr.exclude_kernel && !user_mode(regs))
- return false;
-
- return true;
-}
-
/*
* Generic event overflow handling, sampling.
*/
@@ -7174,12 +7218,6 @@
}
/*
- * For security, drop the skid kernel samples if necessary.
- */
- if (!sample_is_allowed(event, regs))
- return ret;
-
- /*
* XXX event_limit might not quite work as expected on inherited
* events
*/
@@ -10064,6 +10102,103 @@
return err;
}
+static struct perf_event *
+perf_event_create_kernel_shared_check(struct perf_event_attr *attr, int cpu,
+ struct task_struct *task,
+ perf_overflow_handler_t overflow_handler,
+ void *context)
+{
+ unsigned long idx;
+ struct perf_event *event;
+ struct shared_events_str *shrd_events;
+
+ /*
+ * Have to be per cpu events for sharing
+ */
+ if (!shared_events || (u32)cpu >= nr_cpu_ids)
+ return NULL;
+
+ /*
+ * Can't handle these type requests for sharing right now.
+ */
+ if (task || context || overflow_handler ||
+ (attr->type != PERF_TYPE_HARDWARE &&
+ attr->type != PERF_TYPE_RAW))
+ return NULL;
+
+ /*
+ * Using per_cpu_ptr (or could do cross cpu call which is what most of
+ * perf does to access per cpu data structures
+ */
+ shrd_events = per_cpu_ptr(shared_events, cpu);
+
+ mutex_lock(&shrd_events->list_mutex);
+
+ event = NULL;
+ for_each_set_bit(idx, shrd_events->used_mask, SHARED_EVENTS_MAX) {
+ if (memcmp(attr, &shrd_events->attr[idx],
+ sizeof(shrd_events->attr[idx])) == 0) {
+ atomic_inc(&shrd_events->refcount[idx]);
+ event = shrd_events->events[idx];
+ break;
+ }
+ }
+ mutex_unlock(&shrd_events->list_mutex);
+ return event;
+}
+
+static void
+perf_event_create_kernel_shared_add(struct perf_event_attr *attr, int cpu,
+ struct task_struct *task,
+ perf_overflow_handler_t overflow_handler,
+ void *context,
+ struct perf_event *event)
+{
+ unsigned long idx;
+ struct shared_events_str *shrd_events;
+
+ /*
+ * Have to be per cpu events for sharing
+ */
+ if (!shared_events || (u32)cpu >= nr_cpu_ids)
+ return;
+
+ /*
+ * Can't handle these type requests for sharing right now.
+ */
+ if (task || context || overflow_handler ||
+ (attr->type != PERF_TYPE_HARDWARE &&
+ attr->type != PERF_TYPE_RAW))
+ return;
+
+ /*
+ * Using per_cpu_ptr (or could do cross cpu call which is what most of
+ * perf does to access per cpu data structures
+ */
+ shrd_events = per_cpu_ptr(shared_events, cpu);
+
+ mutex_lock(&shrd_events->list_mutex);
+
+ /*
+ * If we are in this routine, we know that this event isn't already in
+ * the shared list. Check if slot available in shared list
+ */
+ idx = find_first_zero_bit(shrd_events->used_mask, SHARED_EVENTS_MAX);
+
+ if (idx >= SHARED_EVENTS_MAX)
+ goto out;
+
+ /*
+ * The event isn't in the list and there is an empty slot so add it.
+ */
+ shrd_events->attr[idx] = *attr;
+ shrd_events->events[idx] = event;
+ set_bit(idx, shrd_events->used_mask);
+ atomic_set(&shrd_events->refcount[idx], 1);
+out:
+ mutex_unlock(&shrd_events->list_mutex);
+}
+
/**
* perf_event_create_kernel_counter
*
@@ -10082,6 +10217,14 @@
int err;
/*
+ * Check if the requested attributes match a shared event
+ */
+ event = perf_event_create_kernel_shared_check(attr, cpu,
+ task, overflow_handler, context);
+ if (event)
+ return event;
+
+ /*
* Get the target context (task or percpu):
*/
@@ -10117,6 +10260,11 @@
perf_unpin_context(ctx);
mutex_unlock(&ctx->mutex);
+ /*
+ * Check if can add event to shared list
+ */
+ perf_event_create_kernel_shared_add(attr, cpu,
+ task, overflow_handler, context, event);
return event;
err_unlock:
@@ -10940,10 +11088,21 @@
void __init perf_event_init(void)
{
- int ret;
+ int ret, cpu;
idr_init(&pmu_idr);
+ shared_events = alloc_percpu(struct shared_events_str);
+ if (!shared_events) {
+ WARN(1, "alloc_percpu failed for shared_events struct");
+ } else {
+ for_each_possible_cpu(cpu) {
+ struct shared_events_str *shrd_events =
+ per_cpu_ptr(shared_events, cpu);
+
+ mutex_init(&shrd_events->list_mutex);
+ }
+ }
perf_event_init_all_cpus();
init_srcu_struct(&pmus_srcu);
perf_pmu_register(&perf_swevent, "software", PERF_TYPE_SOFTWARE);
diff --git a/kernel/extable.c b/kernel/extable.c
index e820cce..4f06fc3 100644
--- a/kernel/extable.c
+++ b/kernel/extable.c
@@ -66,7 +66,7 @@
return 0;
}
-int core_kernel_text(unsigned long addr)
+int notrace core_kernel_text(unsigned long addr)
{
if (addr >= (unsigned long)_stext &&
addr < (unsigned long)_etext)
diff --git a/kernel/fork.c b/kernel/fork.c
index f90327b..39c0709 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1015,8 +1015,7 @@
mm = get_task_mm(task);
if (mm && mm != current->mm &&
- !ptrace_may_access(task, mode) &&
- !capable(CAP_SYS_RESOURCE)) {
+ !ptrace_may_access(task, mode)) {
mmput(mm);
mm = ERR_PTR(-EACCES);
}
@@ -1518,6 +1517,18 @@
if (!p)
goto fork_out;
+ /*
+ * This _must_ happen before we call free_task(), i.e. before we jump
+ * to any of the bad_fork_* labels. This is to avoid freeing
+ * p->set_child_tid which is (ab)used as a kthread's data pointer for
+ * kernel threads (PF_KTHREAD).
+ */
+ p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL;
+ /*
+ * Clear TID on mm_release()?
+ */
+ p->clear_child_tid = (clone_flags & CLONE_CHILD_CLEARTID) ? child_tidptr : NULL;
+
ftrace_graph_init_task(p);
rt_mutex_init_task(p);
@@ -1679,11 +1690,6 @@
}
}
- p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL;
- /*
- * Clear TID on mm_release()?
- */
- p->clear_child_tid = (clone_flags & CLONE_CHILD_CLEARTID) ? child_tidptr : NULL;
#ifdef CONFIG_BLOCK
p->plug = NULL;
#endif
diff --git a/kernel/irq/cpuhotplug.c b/kernel/irq/cpuhotplug.c
index 007482b..4684b75 100644
--- a/kernel/irq/cpuhotplug.c
+++ b/kernel/irq/cpuhotplug.c
@@ -69,7 +69,7 @@
if (!c->irq_set_affinity) {
pr_debug("IRQ%u: unable to set affinity\n", d->irq);
} else {
- int r = irq_do_set_affinity(d, affinity, false);
+ int r = irq_set_affinity_locked(d, affinity, false);
if (r)
pr_warn_ratelimited("IRQ%u: set affinity failed(%d).\n",
d->irq, r);
diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c
index 037c321..38f7665 100644
--- a/kernel/kexec_file.c
+++ b/kernel/kexec_file.c
@@ -25,13 +25,6 @@
#include <linux/vmalloc.h>
#include "kexec_internal.h"
-/*
- * Declare these symbols weak so that if architecture provides a purgatory,
- * these will be overridden.
- */
-char __weak kexec_purgatory[0];
-size_t __weak kexec_purgatory_size = 0;
-
static int kexec_calculate_store_digests(struct kimage *image);
/* Architectures can provide this probe function */
diff --git a/kernel/kexec_internal.h b/kernel/kexec_internal.h
index 0a52315..f95fd2c 100644
--- a/kernel/kexec_internal.h
+++ b/kernel/kexec_internal.h
@@ -37,6 +37,8 @@
};
void kimage_file_post_load_cleanup(struct kimage *image);
+extern char kexec_purgatory[];
+extern size_t kexec_purgatory_size;
#else /* CONFIG_KEXEC_FILE */
static inline void kimage_file_post_load_cleanup(struct kimage *image) { }
#endif /* CONFIG_KEXEC_FILE */
diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h
index 56583e7..e3944c4 100644
--- a/kernel/rcu/tree_plugin.h
+++ b/kernel/rcu/tree_plugin.h
@@ -1767,6 +1767,7 @@
if (READ_ONCE(rdp_leader->nocb_leader_sleep) || force) {
/* Prior smp_mb__after_atomic() orders against prior enqueue. */
WRITE_ONCE(rdp_leader->nocb_leader_sleep, false);
+ smp_mb(); /* ->nocb_leader_sleep before swake_up(). */
swake_up(&rdp_leader->nocb_wq);
}
}
@@ -2021,6 +2022,7 @@
* nocb_gp_head, where they await a grace period.
*/
gotcbs = false;
+ smp_mb(); /* wakeup before ->nocb_head reads. */
for (rdp = my_rdp; rdp; rdp = rdp->nocb_next_follower) {
rdp->nocb_gp_head = READ_ONCE(rdp->nocb_head);
if (!rdp->nocb_gp_head)
diff --git a/kernel/resource.c b/kernel/resource.c
index 9b5f044..89778a3 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -172,7 +172,7 @@
static int __init ioresources_init(void)
{
proc_create("ioports", 0, NULL, &proc_ioports_operations);
- proc_create("iomem", 0, NULL, &proc_iomem_operations);
+ proc_create("iomem", 0400, NULL, &proc_iomem_operations);
return 0;
}
__initcall(ioresources_init);
diff --git a/kernel/sched/boost.c b/kernel/sched/boost.c
index 1a3309b..1ccd19d 100644
--- a/kernel/sched/boost.c
+++ b/kernel/sched/boost.c
@@ -32,7 +32,7 @@
{
struct rq *rq = cpu_rq(cpu);
- if (!test_and_set_bit(BOOST_KICK, &rq->hmp_flags))
+ if (!test_and_set_bit(BOOST_KICK, &rq->walt_flags))
smp_send_reschedule(cpu);
}
@@ -57,14 +57,14 @@
int cpu = smp_processor_id();
struct rq *rq = cpu_rq(cpu);
- return test_bit(BOOST_KICK, &rq->hmp_flags);
+ return test_bit(BOOST_KICK, &rq->walt_flags);
}
void clear_boost_kick(int cpu)
{
struct rq *rq = cpu_rq(cpu);
- clear_bit(BOOST_KICK, &rq->hmp_flags);
+ clear_bit(BOOST_KICK, &rq->walt_flags);
}
/*
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 46e4643..7722ade 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -1283,6 +1283,8 @@
#endif
#endif
+ trace_sched_migrate_task(p, new_cpu, task_util(p));
+
if (task_cpu(p) != new_cpu) {
if (p->sched_class->migrate_task_rq)
p->sched_class->migrate_task_rq(p);
@@ -1679,7 +1681,7 @@
return cpu;
}
-void update_avg(u64 *avg, u64 sample)
+static void update_avg(u64 *avg, u64 sample)
{
s64 diff = sample - *avg;
*avg += diff >> 3;
@@ -2187,9 +2189,6 @@
notif_required = true;
}
- if (!__task_in_cum_window_demand(cpu_rq(cpu), p))
- inc_cum_window_demand(cpu_rq(cpu), p, task_load(p));
-
note_task_waking(p, wallclock);
#endif /* CONFIG_SMP */
@@ -2199,6 +2198,15 @@
out:
raw_spin_unlock_irqrestore(&p->pi_lock, flags);
+ if (success && sched_predl) {
+ raw_spin_lock_irqsave(&cpu_rq(cpu)->lock, flags);
+ if (do_pl_notif(cpu_rq(cpu)))
+ cpufreq_update_util(cpu_rq(cpu),
+ SCHED_CPUFREQ_WALT |
+ SCHED_CPUFREQ_PL);
+ raw_spin_unlock_irqrestore(&cpu_rq(cpu)->lock, flags);
+ }
+
return success;
}
@@ -2249,8 +2257,6 @@
update_task_ravg(rq->curr, rq, TASK_UPDATE, wallclock, 0);
update_task_ravg(p, rq, TASK_WAKE, wallclock, 0);
- if (!__task_in_cum_window_demand(rq, p))
- inc_cum_window_demand(rq, p, task_load(p));
cpufreq_update_util(rq, 0);
ttwu_activate(rq, p, ENQUEUE_WAKEUP);
note_task_waking(p, wallclock);
@@ -5952,13 +5958,7 @@
set_rq_online(rq);
raw_spin_unlock(&rq->lock);
- /*
- * We might have been in tickless state. Clear NOHZ flags to avoid
- * us being kicked for helping out with balancing
- */
- nohz_balance_clear_nohz_mask(cpu);
-
- clear_hmp_request(cpu);
+ clear_walt_request(cpu);
local_irq_enable();
return 0;
}
@@ -6691,6 +6691,9 @@
* Build an iteration mask that can exclude certain CPUs from the upwards
* domain traversal.
*
+ * Only CPUs that can arrive at this group should be considered to continue
+ * balancing.
+ *
* Asymmetric node setups can result in situations where the domain tree is of
* unequal depth, make sure to skip domains that already cover the entire
* range.
@@ -6702,18 +6705,31 @@
*/
static void build_group_mask(struct sched_domain *sd, struct sched_group *sg)
{
- const struct cpumask *span = sched_domain_span(sd);
+ const struct cpumask *sg_span = sched_group_cpus(sg);
struct sd_data *sdd = sd->private;
struct sched_domain *sibling;
int i;
- for_each_cpu(i, span) {
+ for_each_cpu(i, sg_span) {
sibling = *per_cpu_ptr(sdd->sd, i);
- if (!cpumask_test_cpu(i, sched_domain_span(sibling)))
+
+ /*
+ * Can happen in the asymmetric case, where these siblings are
+ * unused. The mask will not be empty because those CPUs that
+ * do have the top domain _should_ span the domain.
+ */
+ if (!sibling->child)
+ continue;
+
+ /* If we would not end up here, we can't continue from here */
+ if (!cpumask_equal(sg_span, sched_domain_span(sibling->child)))
continue;
cpumask_set_cpu(i, sched_group_mask(sg));
}
+
+ /* We must not have empty masks here */
+ WARN_ON_ONCE(cpumask_empty(sched_group_mask(sg)));
}
/*
@@ -6737,7 +6753,7 @@
cpumask_clear(covered);
- for_each_cpu(i, span) {
+ for_each_cpu_wrap(i, span, cpu) {
struct cpumask *sg_span;
if (cpumask_test_cpu(i, covered))
@@ -8068,7 +8084,7 @@
BUG_ON(rq->nr_running != 1);
raw_spin_unlock_irqrestore(&rq->lock, flags);
- clear_hmp_request(cpu);
+ clear_walt_request(cpu);
calc_load_migrate(rq);
update_max_interval();
@@ -8078,22 +8094,6 @@
}
#endif
-#ifdef CONFIG_SCHED_SMT
-DEFINE_STATIC_KEY_FALSE(sched_smt_present);
-
-static void sched_init_smt(void)
-{
- /*
- * We've enumerated all CPUs and will assume that if any CPU
- * has SMT siblings, CPU0 will too.
- */
- if (cpumask_weight(cpu_smt_mask(0)) > 1)
- static_branch_enable(&sched_smt_present);
-}
-#else
-static inline void sched_init_smt(void) { }
-#endif
-
void __init sched_init_smp(void)
{
cpumask_var_t non_isolated_cpus;
@@ -8125,9 +8125,6 @@
init_sched_rt_class();
init_sched_dl_class();
-
- sched_init_smt();
-
sched_smp_initialized = true;
}
@@ -8308,7 +8305,6 @@
rq->avg_idle = 2*sysctl_sched_migration_cost;
rq->max_idle_balance_cost = sysctl_sched_migration_cost;
rq->push_task = NULL;
-
walt_sched_init(rq);
INIT_LIST_HEAD(&rq->cfs_tasks);
@@ -9578,8 +9574,13 @@
wallclock = sched_ktime_clock();
update_task_ravg(rq->curr, rq, TASK_UPDATE, wallclock, 0);
dequeue_task(rq, p, 0);
+ /*
+ * task's contribution is already removed from the
+ * cumulative window demand in dequeue. As the
+ * task's stats are reset, the next enqueue does
+ * not change the cumulative window demand.
+ */
reset_task_stats(p);
- dec_cum_window_demand(rq, p);
p->ravg.mark_start = wallclock;
p->ravg.sum_history[0] = EXITING_TASK_MARKER;
free_task_load_ptrs(p);
@@ -9589,3 +9590,5 @@
task_rq_unlock(rq, p, &rf);
}
#endif /* CONFIG_SCHED_WALT */
+
+__read_mostly bool sched_predl;
diff --git a/kernel/sched/core_ctl.c b/kernel/sched/core_ctl.c
index 4c3bf526..e56af41 100644
--- a/kernel/sched/core_ctl.c
+++ b/kernel/sched/core_ctl.c
@@ -13,7 +13,6 @@
#define pr_fmt(fmt) "core_ctl: " fmt
#include <linux/init.h>
-#include <linux/notifier.h>
#include <linux/cpu.h>
#include <linux/cpumask.h>
#include <linux/cpufreq.h>
@@ -877,21 +876,18 @@
return 0;
}
-static int __ref cpu_callback(struct notifier_block *nfb,
- unsigned long action, void *hcpu)
+static int isolation_cpuhp_state(unsigned int cpu, bool online)
{
- uint32_t cpu = (uintptr_t)hcpu;
struct cpu_data *state = &per_cpu(cpu_state, cpu);
struct cluster_data *cluster = state->cluster;
unsigned int need;
- bool do_wakeup, unisolated = false;
+ bool do_wakeup = false, unisolated = false;
unsigned long flags;
if (unlikely(!cluster || !cluster->inited))
- return NOTIFY_DONE;
+ return 0;
- switch (action & ~CPU_TASKS_FROZEN) {
- case CPU_ONLINE:
+ if (online) {
cluster->active_cpus = get_active_cpu_count(cluster);
/*
@@ -901,9 +897,7 @@
* reject trying to online CPUs.
*/
move_cpu_lru(state);
- break;
-
- case CPU_DEAD:
+ } else {
/*
* We don't want to have a CPU both offline and isolated.
* So unisolate a CPU that went down if it was isolated by us.
@@ -919,9 +913,6 @@
state->busy = 0;
cluster->active_cpus = get_active_cpu_count(cluster);
- break;
- default:
- return NOTIFY_DONE;
}
need = apply_limits(cluster, cluster->need_cpus);
@@ -933,12 +924,18 @@
if (do_wakeup)
wake_up_core_ctl_thread(cluster);
- return NOTIFY_OK;
+ return 0;
}
-static struct notifier_block __refdata cpu_notifier = {
- .notifier_call = cpu_callback,
-};
+static int core_ctl_isolation_online_cpu(unsigned int cpu)
+{
+ return isolation_cpuhp_state(cpu, true);
+}
+
+static int core_ctl_isolation_dead_cpu(unsigned int cpu)
+{
+ return isolation_cpuhp_state(cpu, false);
+}
/* ============================ init code ============================== */
@@ -1068,7 +1065,13 @@
if (should_skip(cpu_possible_mask))
return 0;
- register_cpu_notifier(&cpu_notifier);
+ cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
+ "core_ctl/isolation:online",
+ core_ctl_isolation_online_cpu, NULL);
+
+ cpuhp_setup_state_nocalls(CPUHP_CORE_CTL_ISOLATION_DEAD,
+ "core_ctl/isolation:dead",
+ NULL, core_ctl_isolation_dead_cpu);
for_each_cpu(cpu, &cpus) {
int ret;
diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c
index dce76d1..0afd701 100644
--- a/kernel/sched/cpufreq_schedutil.c
+++ b/kernel/sched/cpufreq_schedutil.c
@@ -15,7 +15,7 @@
#include <linux/kthread.h>
#include <linux/slab.h>
#include <trace/events/power.h>
-
+#include <linux/sched/sysctl.h>
#include "sched.h"
#define SUGOV_KTHREAD_PRIORITY 50
@@ -216,6 +216,10 @@
u64 upto)
{
u64 delta_ns, cycles;
+
+ if (unlikely(!sysctl_sched_use_walt_cpu_util))
+ return;
+
/* Track cycles in current window */
delta_ns = upto - sg_policy->last_cyc_update_time;
cycles = (prev_freq * delta_ns) / (NSEC_PER_SEC / KHZ);
@@ -229,6 +233,9 @@
u64 last_ws = sg_policy->last_ws;
unsigned int avg_freq;
+ if (unlikely(!sysctl_sched_use_walt_cpu_util))
+ return;
+
WARN_ON(curr_ws < last_ws);
if (curr_ws <= last_ws)
return;
@@ -259,6 +266,9 @@
unsigned long cpu_util = sg_cpu->util;
bool is_hiload;
+ if (unlikely(!sysctl_sched_use_walt_cpu_util))
+ return;
+
is_hiload = (cpu_util >= mult_frac(sg_policy->avg_cap,
HISPEED_LOAD,
100));
@@ -389,8 +399,8 @@
sugov_calc_avg_cap(sg_policy, sg_cpu->walt_load.ws,
sg_policy->policy->cur);
- trace_sugov_util_update(sg_cpu->cpu, sg_cpu->util, max,
- sg_cpu->walt_load.nl,
+ trace_sugov_util_update(sg_cpu->cpu, sg_cpu->util, sg_policy->avg_cap,
+ max, sg_cpu->walt_load.nl,
sg_cpu->walt_load.pl, flags);
if (sugov_should_update_freq(sg_policy, time)) {
diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c
index 10a807c..08d4511 100644
--- a/kernel/sched/deadline.c
+++ b/kernel/sched/deadline.c
@@ -19,41 +19,6 @@
#include <linux/slab.h>
-#ifdef CONFIG_SCHED_WALT
-
-static void
-inc_hmp_sched_stats_dl(struct rq *rq, struct task_struct *p)
-{
- inc_cumulative_runnable_avg(&rq->hmp_stats, p);
-}
-
-static void
-dec_hmp_sched_stats_dl(struct rq *rq, struct task_struct *p)
-{
- dec_cumulative_runnable_avg(&rq->hmp_stats, p);
-}
-
-static void
-fixup_hmp_sched_stats_dl(struct rq *rq, struct task_struct *p,
- u32 new_task_load, u32 new_pred_demand)
-{
- s64 task_load_delta = (s64)new_task_load - task_load(p);
- s64 pred_demand_delta = PRED_DEMAND_DELTA;
-
- fixup_cumulative_runnable_avg(&rq->hmp_stats, p, task_load_delta,
- pred_demand_delta);
-}
-
-#else /* CONFIG_SCHED_WALT */
-
-static inline void
-inc_hmp_sched_stats_dl(struct rq *rq, struct task_struct *p) { }
-
-static inline void
-dec_hmp_sched_stats_dl(struct rq *rq, struct task_struct *p) { }
-
-#endif /* CONFIG_SCHED_WALT */
-
struct dl_bandwidth def_dl_bandwidth;
static inline struct task_struct *dl_task_of(struct sched_dl_entity *dl_se)
@@ -865,7 +830,7 @@
WARN_ON(!dl_prio(prio));
dl_rq->dl_nr_running++;
add_nr_running(rq_of_dl_rq(dl_rq), 1);
- inc_hmp_sched_stats_dl(rq_of_dl_rq(dl_rq), dl_task_of(dl_se));
+ walt_inc_cumulative_runnable_avg(rq_of_dl_rq(dl_rq), dl_task_of(dl_se));
inc_dl_deadline(dl_rq, deadline);
inc_dl_migration(dl_se, dl_rq);
@@ -880,7 +845,7 @@
WARN_ON(!dl_rq->dl_nr_running);
dl_rq->dl_nr_running--;
sub_nr_running(rq_of_dl_rq(dl_rq), 1);
- dec_hmp_sched_stats_dl(rq_of_dl_rq(dl_rq), dl_task_of(dl_se));
+ walt_dec_cumulative_runnable_avg(rq_of_dl_rq(dl_rq), dl_task_of(dl_se));
dec_dl_deadline(dl_rq, dl_se->deadline);
dec_dl_migration(dl_se, dl_rq);
@@ -1845,7 +1810,7 @@
.update_curr = update_curr_dl,
#ifdef CONFIG_SCHED_WALT
- .fixup_hmp_sched_stats = fixup_hmp_sched_stats_dl,
+ .fixup_walt_sched_stats = fixup_walt_sched_stats_common,
#endif
};
diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c
index b520691..0f8c0b2 100644
--- a/kernel/sched/debug.c
+++ b/kernel/sched/debug.c
@@ -600,12 +600,6 @@
cfs_rq->throttle_count);
SEQ_printf(m, " .%-30s: %d\n", "runtime_enabled",
cfs_rq->runtime_enabled);
-#ifdef CONFIG_SCHED_WALT
- SEQ_printf(m, " .%-30s: %d\n", "nr_big_tasks",
- cfs_rq->hmp_stats.nr_big_tasks);
- SEQ_printf(m, " .%-30s: %llu\n", "cumulative_runnable_avg",
- cfs_rq->hmp_stats.cumulative_runnable_avg);
-#endif
#endif
#ifdef CONFIG_FAIR_GROUP_SCHED
@@ -706,10 +700,10 @@
P(cluster->max_freq);
P(cluster->exec_scale_factor);
#ifdef CONFIG_SCHED_WALT
- P(hmp_stats.nr_big_tasks);
+ P(walt_stats.nr_big_tasks);
#endif
- SEQ_printf(m, " .%-30s: %llu\n", "hmp_stats.cumulative_runnable_avg",
- rq->hmp_stats.cumulative_runnable_avg);
+ SEQ_printf(m, " .%-30s: %llu\n", "walt_stats.cumulative_runnable_avg",
+ rq->walt_stats.cumulative_runnable_avg);
#endif
#undef P
#undef PN
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index e0ab4d6..62a29ed 100755
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -37,50 +37,39 @@
#include "walt.h"
#include <trace/events/sched.h>
-/* QHMP/Zone forward declarations */
-
-struct lb_env;
-struct sd_lb_stats;
-struct sg_lb_stats;
-
#ifdef CONFIG_SCHED_WALT
-static void fixup_hmp_sched_stats_fair(struct rq *rq, struct task_struct *p,
- u32 new_task_load, u32 new_pred_demand);
-#endif
-static inline void inc_cfs_rq_hmp_stats(struct cfs_rq *cfs_rq,
- struct task_struct *p, int change_cra) { }
-static inline void dec_cfs_rq_hmp_stats(struct cfs_rq *cfs_rq,
- struct task_struct *p, int change_cra) { }
-static inline void dec_throttled_cfs_rq_hmp_stats(
- struct hmp_sched_stats *stats,
- struct cfs_rq *cfs_rq) { }
-static inline void inc_throttled_cfs_rq_hmp_stats(
- struct hmp_sched_stats *stats,
- struct cfs_rq *cfs_rq) { }
-static inline void init_cfs_rq_hmp_stats(struct cfs_rq *cfs_rq) { }
-
-#ifdef CONFIG_SMP
-
-static inline int
-bail_inter_cluster_balance(struct lb_env *env, struct sd_lb_stats *sds)
-{
- return 0;
-}
-
-static inline bool update_sd_pick_busiest_active_balance(struct lb_env *env,
- struct sd_lb_stats *sds,
- struct sched_group *sg,
- struct sg_lb_stats *sgs)
-{
- return false;
-}
-#endif /* CONFIG_SMP */
-
-#ifdef CONFIG_SCHED_WALT
static inline bool task_fits_max(struct task_struct *p, int cpu);
+static void walt_fixup_sched_stats_fair(struct rq *rq, struct task_struct *p,
+ u32 new_task_load, u32 new_pred_demand);
+static void walt_fixup_nr_big_tasks(struct rq *rq, struct task_struct *p,
+ int delta, bool inc);
+#endif /* CONFIG_SCHED_WALT */
+
+#if defined(CONFIG_SCHED_WALT) && defined(CONFIG_CFS_BANDWIDTH)
+
+static void walt_init_cfs_rq_stats(struct cfs_rq *cfs_rq);
+static void walt_inc_cfs_rq_stats(struct cfs_rq *cfs_rq,
+ struct task_struct *p);
+static void walt_dec_cfs_rq_stats(struct cfs_rq *cfs_rq,
+ struct task_struct *p);
+static void walt_inc_throttled_cfs_rq_stats(struct walt_sched_stats *stats,
+ struct cfs_rq *cfs_rq);
+static void walt_dec_throttled_cfs_rq_stats(struct walt_sched_stats *stats,
+ struct cfs_rq *cfs_rq);
+#else
+static inline void walt_init_cfs_rq_stats(struct cfs_rq *cfs_rq) {}
+static inline void
+walt_inc_cfs_rq_stats(struct cfs_rq *cfs_rq, struct task_struct *p) {}
+static inline void
+walt_dec_cfs_rq_stats(struct cfs_rq *cfs_rq, struct task_struct *p) {}
+
+#define walt_inc_throttled_cfs_rq_stats(...)
+#define walt_dec_throttled_cfs_rq_stats(...)
+
#endif
+
/*
* Targeted preemption latency for CPU-bound tasks:
* (default: 6ms * (1 + ilog(ncpus)), units: nanoseconds)
@@ -4047,7 +4036,7 @@
if (dequeue)
dequeue_entity(qcfs_rq, se, DEQUEUE_SLEEP);
qcfs_rq->h_nr_running -= task_delta;
- dec_throttled_cfs_rq_hmp_stats(&qcfs_rq->hmp_stats, cfs_rq);
+ walt_dec_throttled_cfs_rq_stats(&qcfs_rq->walt_stats, cfs_rq);
if (qcfs_rq->load.weight)
dequeue = 0;
@@ -4055,7 +4044,7 @@
if (!se) {
sub_nr_running(rq, task_delta);
- dec_throttled_cfs_rq_hmp_stats(&rq->hmp_stats, cfs_rq);
+ walt_dec_throttled_cfs_rq_stats(&rq->walt_stats, cfs_rq);
}
cfs_rq->throttled = 1;
@@ -4077,11 +4066,6 @@
start_cfs_bandwidth(cfs_b);
raw_spin_unlock(&cfs_b->lock);
-
- /* Log effect on hmp stats after throttling */
- trace_sched_cpu_load_cgroup(rq, idle_cpu(cpu_of(rq)),
- sched_irqload(cpu_of(rq)),
- power_cost(cpu_of(rq), 0));
}
void unthrottle_cfs_rq(struct cfs_rq *cfs_rq)
@@ -4119,7 +4103,7 @@
if (enqueue)
enqueue_entity(cfs_rq, se, ENQUEUE_WAKEUP);
cfs_rq->h_nr_running += task_delta;
- inc_throttled_cfs_rq_hmp_stats(&cfs_rq->hmp_stats, tcfs_rq);
+ walt_inc_throttled_cfs_rq_stats(&cfs_rq->walt_stats, tcfs_rq);
if (cfs_rq_throttled(cfs_rq))
break;
@@ -4127,17 +4111,12 @@
if (!se) {
add_nr_running(rq, task_delta);
- inc_throttled_cfs_rq_hmp_stats(&rq->hmp_stats, tcfs_rq);
+ walt_inc_throttled_cfs_rq_stats(&rq->walt_stats, tcfs_rq);
}
/* determine whether we need to wake up potentially idle cpu */
if (rq->curr == rq->idle && rq->cfs.nr_running)
resched_curr(rq);
-
- /* Log effect on hmp stats after un-throttling */
- trace_sched_cpu_load_cgroup(rq, idle_cpu(cpu_of(rq)),
- sched_irqload(cpu_of(rq)),
- power_cost(cpu_of(rq), 0));
}
static u64 distribute_cfs_runtime(struct cfs_bandwidth *cfs_b,
@@ -4475,7 +4454,7 @@
{
cfs_rq->runtime_enabled = 0;
INIT_LIST_HEAD(&cfs_rq->throttled_list);
- init_cfs_rq_hmp_stats(cfs_rq);
+ walt_init_cfs_rq_stats(cfs_rq);
}
void start_cfs_bandwidth(struct cfs_bandwidth *cfs_b)
@@ -4670,6 +4649,9 @@
int task_wakeup = flags & ENQUEUE_WAKEUP;
#endif
+#ifdef CONFIG_SCHED_WALT
+ p->misfit = !task_fits_max(p, rq->cpu);
+#endif
/*
* If in_iowait is set, the code below may not trigger any cpufreq
* utilization updates, so do it here explicitly with the IOWAIT flag
@@ -4693,7 +4675,7 @@
if (cfs_rq_throttled(cfs_rq))
break;
cfs_rq->h_nr_running++;
- inc_cfs_rq_hmp_stats(cfs_rq, p, 1);
+ walt_inc_cfs_rq_stats(cfs_rq, p);
flags = ENQUEUE_WAKEUP;
}
@@ -4701,7 +4683,7 @@
for_each_sched_entity(se) {
cfs_rq = cfs_rq_of(se);
cfs_rq->h_nr_running++;
- inc_cfs_rq_hmp_stats(cfs_rq, p, 1);
+ walt_inc_cfs_rq_stats(cfs_rq, p);
if (cfs_rq_throttled(cfs_rq))
break;
@@ -4712,10 +4694,7 @@
if (!se) {
add_nr_running(rq, 1);
-#ifdef CONFIG_SCHED_WALT
- p->misfit = !task_fits_max(p, rq->cpu);
-#endif
- inc_rq_hmp_stats(rq, p, 1);
+ inc_rq_walt_stats(rq, p);
}
#ifdef CONFIG_SMP
@@ -4771,7 +4750,7 @@
if (cfs_rq_throttled(cfs_rq))
break;
cfs_rq->h_nr_running--;
- dec_cfs_rq_hmp_stats(cfs_rq, p, 1);
+ walt_dec_cfs_rq_stats(cfs_rq, p);
/* Don't dequeue parent if it has other entities besides us */
if (cfs_rq->load.weight) {
@@ -4791,7 +4770,7 @@
for_each_sched_entity(se) {
cfs_rq = cfs_rq_of(se);
cfs_rq->h_nr_running--;
- dec_cfs_rq_hmp_stats(cfs_rq, p, 1);
+ walt_dec_cfs_rq_stats(cfs_rq, p);
if (cfs_rq_throttled(cfs_rq))
break;
@@ -4802,7 +4781,7 @@
if (!se) {
sub_nr_running(rq, 1);
- dec_rq_hmp_stats(rq, p, 1);
+ dec_rq_walt_stats(rq, p);
}
#ifdef CONFIG_SMP
@@ -5344,18 +5323,6 @@
return DIV_ROUND_UP(util << SCHED_CAPACITY_SHIFT, capacity);
}
-static inline int task_util(struct task_struct *p)
-{
-#ifdef CONFIG_SCHED_WALT
- if (!walt_disabled && sysctl_sched_use_walt_task_util) {
- u64 demand = p->ravg.demand;
-
- return (demand << 10) / sched_ravg_window;
- }
-#endif
- return p->se.avg.util_avg;
-}
-
static inline bool
bias_to_waker_cpu(struct task_struct *p, int cpu, struct cpumask *rtg_target)
{
@@ -6177,43 +6144,6 @@
return shallowest_idle_cpu != -1 ? shallowest_idle_cpu : least_loaded_cpu;
}
-/*
- * Implement a for_each_cpu() variant that starts the scan at a given cpu
- * (@start), and wraps around.
- *
- * This is used to scan for idle CPUs; such that not all CPUs looking for an
- * idle CPU find the same CPU. The down-side is that tasks tend to cycle
- * through the LLC domain.
- *
- * Especially tbench is found sensitive to this.
- */
-
-static int cpumask_next_wrap(int n, const struct cpumask *mask, int start, int *wrapped)
-{
- int next;
-
-again:
- next = find_next_bit(cpumask_bits(mask), nr_cpumask_bits, n+1);
-
- if (*wrapped) {
- if (next >= start)
- return nr_cpumask_bits;
- } else {
- if (next >= nr_cpumask_bits) {
- *wrapped = 1;
- n = -1;
- goto again;
- }
- }
-
- return next;
-}
-
-#define for_each_cpu_wrap(cpu, mask, start, wrap) \
- for ((wrap) = 0, (cpu) = (start)-1; \
- (cpu) = cpumask_next_wrap((cpu), (mask), (start), &(wrap)), \
- (cpu) < nr_cpumask_bits; )
-
#ifdef CONFIG_SCHED_SMT
static inline void set_idle_cores(int cpu, int val)
@@ -6243,7 +6173,7 @@
* Since SMT siblings share all cache levels, inspecting this limited remote
* state should be fairly cheap.
*/
-void __update_idle_core(struct rq *rq)
+void update_idle_core(struct rq *rq)
{
int core = cpu_of(rq);
int cpu;
@@ -6273,17 +6203,14 @@
static int select_idle_core(struct task_struct *p, struct sched_domain *sd, int target)
{
struct cpumask *cpus = this_cpu_cpumask_var_ptr(select_idle_mask);
- int core, cpu, wrap;
-
- if (!static_branch_likely(&sched_smt_present))
- return -1;
+ int core, cpu;
if (!test_idle_cores(target, false))
return -1;
cpumask_and(cpus, sched_domain_span(sd), tsk_cpus_allowed(p));
- for_each_cpu_wrap(core, cpus, target, wrap) {
+ for_each_cpu_wrap(core, cpus, target) {
bool idle = true;
for_each_cpu(cpu, cpu_smt_mask(core)) {
@@ -6311,9 +6238,6 @@
{
int cpu;
- if (!static_branch_likely(&sched_smt_present))
- return -1;
-
for_each_cpu(cpu, cpu_smt_mask(target)) {
if (!cpumask_test_cpu(cpu, tsk_cpus_allowed(p)))
continue;
@@ -6351,7 +6275,7 @@
u64 avg_cost, avg_idle = this_rq()->avg_idle;
u64 time, cost;
s64 delta;
- int cpu, wrap;
+ int cpu;
this_sd = rcu_dereference(*this_cpu_ptr(&sd_llc));
if (!this_sd)
@@ -6368,7 +6292,7 @@
time = local_clock();
- for_each_cpu_wrap(cpu, sched_domain_span(sd), target, wrap) {
+ for_each_cpu_wrap(cpu, sched_domain_span(sd), target) {
if (!cpumask_test_cpu(cpu, tsk_cpus_allowed(p)))
continue;
if (cpu_isolated(cpu))
@@ -8657,9 +8581,6 @@
{
struct sg_lb_stats *busiest = &sds->busiest_stat;
- if (update_sd_pick_busiest_active_balance(env, sds, sg, sgs))
- return true;
-
if (sgs->group_type > busiest->group_type)
return true;
@@ -9123,9 +9044,6 @@
if (env->flags & LBF_BIG_TASK_ACTIVE_BALANCE)
goto force_balance;
- if (bail_inter_cluster_balance(env, &sds))
- goto out_balanced;
-
sds.avg_load = (SCHED_CAPACITY_SCALE * sds.total_load)
/ sds.total_capacity;
@@ -9970,6 +9888,8 @@
if (sd) {
cpumask_and(&cpumask, nohz.idle_cpus_mask,
sched_domain_span(sd));
+ cpumask_andnot(&cpumask, &cpumask,
+ cpu_isolated_mask);
ilb = cpumask_first(&cpumask);
}
rcu_read_unlock();
@@ -9978,8 +9898,11 @@
if (!energy_aware() ||
(capacity_orig_of(cpu) ==
cpu_rq(cpu)->rd->max_cpu_capacity.val ||
- cpu_overutilized(cpu)))
- ilb = cpumask_first(nohz.idle_cpus_mask);
+ cpu_overutilized(cpu))) {
+ cpumask_andnot(&cpumask, nohz.idle_cpus_mask,
+ cpu_isolated_mask);
+ ilb = cpumask_first(&cpumask);
+ }
}
if (ilb < nr_cpu_ids && idle_cpu(ilb))
@@ -10016,21 +9939,16 @@
return;
}
-void nohz_balance_clear_nohz_mask(int cpu)
-{
- if (likely(cpumask_test_cpu(cpu, nohz.idle_cpus_mask))) {
- cpumask_clear_cpu(cpu, nohz.idle_cpus_mask);
- atomic_dec(&nohz.nr_cpus);
- }
-}
-
void nohz_balance_exit_idle(unsigned int cpu)
{
if (unlikely(test_bit(NOHZ_TICK_STOPPED, nohz_flags(cpu)))) {
/*
* Completely isolated CPUs don't ever set, so we must test.
*/
- nohz_balance_clear_nohz_mask(cpu);
+ if (likely(cpumask_test_cpu(cpu, nohz.idle_cpus_mask))) {
+ cpumask_clear_cpu(cpu, nohz.idle_cpus_mask);
+ atomic_dec(&nohz.nr_cpus);
+ }
clear_bit(NOHZ_TICK_STOPPED, nohz_flags(cpu));
}
}
@@ -10305,6 +10223,7 @@
int nr_busy;
int cpu = rq->cpu;
bool kick = false;
+ cpumask_t cpumask;
if (unlikely(rq->idle_balance))
return false;
@@ -10320,7 +10239,8 @@
* None are in tickless mode and hence no need for NOHZ idle load
* balancing.
*/
- if (likely(!atomic_read(&nohz.nr_cpus)))
+ cpumask_andnot(&cpumask, nohz.idle_cpus_mask, cpu_isolated_mask);
+ if (cpumask_empty(&cpumask))
return false;
if (time_before(now, nohz.next_balance))
@@ -10354,8 +10274,7 @@
}
sd = rcu_dereference(per_cpu(sd_asym, cpu));
- if (sd && (cpumask_first_and(nohz.idle_cpus_mask,
- sched_domain_span(sd)) < cpu)) {
+ if (sd && (cpumask_first_and(&cpumask, sched_domain_span(sd)) < cpu)) {
kick = true;
goto unlock;
}
@@ -10379,6 +10298,13 @@
CPU_IDLE : CPU_NOT_IDLE;
/*
+ * Since core isolation doesn't update nohz.idle_cpus_mask, there
+ * is a possibility this nohz kicked cpu could be isolated. Hence
+ * return if the cpu is isolated.
+ */
+ if (cpu_isolated(this_rq->cpu))
+ return;
+ /*
* If this cpu has a pending nohz_balance_kick, then do the
* balancing on behalf of the other idle cpus whose ticks are
* stopped. Do nohz_idle_balance *before* rebalance_domains to
@@ -10458,7 +10384,7 @@
rq->misfit_task = misfit;
if (old_misfit != misfit) {
- adjust_nr_big_tasks(&rq->hmp_stats, 1, misfit);
+ walt_fixup_nr_big_tasks(rq, curr, 1, misfit);
curr->misfit = misfit;
}
#endif
@@ -10923,7 +10849,7 @@
.task_change_group = task_change_group_fair,
#endif
#ifdef CONFIG_SCHED_WALT
- .fixup_hmp_sched_stats = fixup_hmp_sched_stats_fair,
+ .fixup_walt_sched_stats = walt_fixup_sched_stats_fair,
#endif
};
@@ -10973,70 +10899,68 @@
}
/* WALT sched implementation begins here */
+#ifdef CONFIG_SCHED_WALT
-#if defined(CONFIG_SCHED_WALT) && defined(CONFIG_CFS_BANDWIDTH)
-static inline struct task_group *next_task_group(struct task_group *tg)
+#ifdef CONFIG_CFS_BANDWIDTH
+
+static void walt_init_cfs_rq_stats(struct cfs_rq *cfs_rq)
{
- tg = list_entry_rcu(tg->list.next, typeof(struct task_group), list);
-
- return (&tg->list == &task_groups) ? NULL : tg;
+ cfs_rq->walt_stats.nr_big_tasks = 0;
+ cfs_rq->walt_stats.cumulative_runnable_avg = 0;
+ cfs_rq->walt_stats.pred_demands_sum = 0;
}
-/* Iterate over all cfs_rq in a cpu */
-#define for_each_cfs_rq(cfs_rq, tg, cpu) \
- for (tg = container_of(&task_groups, struct task_group, list); \
- ((tg = next_task_group(tg)) && (cfs_rq = tg->cfs_rq[cpu]));)
-
-void reset_cfs_rq_hmp_stats(int cpu, int reset_cra)
+static void walt_inc_cfs_rq_stats(struct cfs_rq *cfs_rq, struct task_struct *p)
{
- struct task_group *tg;
- struct cfs_rq *cfs_rq;
-
- rcu_read_lock();
-
- for_each_cfs_rq(cfs_rq, tg, cpu)
- reset_hmp_stats(&cfs_rq->hmp_stats, reset_cra);
-
- rcu_read_unlock();
+ inc_nr_big_task(&cfs_rq->walt_stats, p);
+ fixup_cumulative_runnable_avg(&cfs_rq->walt_stats, p->ravg.demand,
+ p->ravg.pred_demand);
}
-static inline int cfs_rq_throttled(struct cfs_rq *cfs_rq);
-
-static void inc_cfs_rq_hmp_stats(struct cfs_rq *cfs_rq,
- struct task_struct *p, int change_cra);
-static void dec_cfs_rq_hmp_stats(struct cfs_rq *cfs_rq,
- struct task_struct *p, int change_cra);
-
-/* Add task's contribution to a cpu' HMP statistics */
-void inc_hmp_sched_stats_fair(struct rq *rq,
- struct task_struct *p, int change_cra)
+static void walt_dec_cfs_rq_stats(struct cfs_rq *cfs_rq, struct task_struct *p)
{
- struct cfs_rq *cfs_rq;
- struct sched_entity *se = &p->se;
+ dec_nr_big_task(&cfs_rq->walt_stats, p);
+ fixup_cumulative_runnable_avg(&cfs_rq->walt_stats, -(s64)p->ravg.demand,
+ -(s64)p->ravg.pred_demand);
+}
+
+static void walt_inc_throttled_cfs_rq_stats(struct walt_sched_stats *stats,
+ struct cfs_rq *tcfs_rq)
+{
+ struct rq *rq = rq_of(tcfs_rq);
+
+ stats->nr_big_tasks += tcfs_rq->walt_stats.nr_big_tasks;
+ fixup_cumulative_runnable_avg(stats,
+ tcfs_rq->walt_stats.cumulative_runnable_avg,
+ tcfs_rq->walt_stats.pred_demands_sum);
+
+ if (stats == &rq->walt_stats)
+ walt_fixup_cum_window_demand(rq,
+ tcfs_rq->walt_stats.cumulative_runnable_avg);
+
+}
+
+static void walt_dec_throttled_cfs_rq_stats(struct walt_sched_stats *stats,
+ struct cfs_rq *tcfs_rq)
+{
+ struct rq *rq = rq_of(tcfs_rq);
+
+ stats->nr_big_tasks -= tcfs_rq->walt_stats.nr_big_tasks;
+ fixup_cumulative_runnable_avg(stats,
+ -tcfs_rq->walt_stats.cumulative_runnable_avg,
+ -tcfs_rq->walt_stats.pred_demands_sum);
/*
- * Although below check is not strictly required (as
- * inc/dec_nr_big_task and inc/dec_cumulative_runnable_avg called
- * from inc_cfs_rq_hmp_stats() have similar checks), we gain a bit on
- * efficiency by short-circuiting for_each_sched_entity() loop when
- * sched_disable_window_stats
+ * We remove the throttled cfs_rq's tasks's contribution from the
+ * cumulative window demand so that the same can be added
+ * unconditionally when the cfs_rq is unthrottled.
*/
- if (sched_disable_window_stats)
- return;
-
- for_each_sched_entity(se) {
- cfs_rq = cfs_rq_of(se);
- inc_cfs_rq_hmp_stats(cfs_rq, p, change_cra);
- if (cfs_rq_throttled(cfs_rq))
- break;
- }
-
- /* Update rq->hmp_stats only if we didn't find any throttled cfs_rq */
- if (!se)
- inc_rq_hmp_stats(rq, p, change_cra);
+ if (stats == &rq->walt_stats)
+ walt_fixup_cum_window_demand(rq,
+ -tcfs_rq->walt_stats.cumulative_runnable_avg);
}
-static void fixup_hmp_sched_stats_fair(struct rq *rq, struct task_struct *p,
+static void walt_fixup_sched_stats_fair(struct rq *rq, struct task_struct *p,
u32 new_task_load, u32 new_pred_demand)
{
struct cfs_rq *cfs_rq;
@@ -11047,47 +10971,91 @@
for_each_sched_entity(se) {
cfs_rq = cfs_rq_of(se);
- fixup_cumulative_runnable_avg(&cfs_rq->hmp_stats, p,
+ fixup_cumulative_runnable_avg(&cfs_rq->walt_stats,
task_load_delta,
pred_demand_delta);
if (cfs_rq_throttled(cfs_rq))
break;
}
- /* Fix up rq->hmp_stats only if we didn't find any throttled cfs_rq */
+ /* Fix up rq->walt_stats only if we didn't find any throttled cfs_rq */
if (!se) {
- fixup_cumulative_runnable_avg(&rq->hmp_stats, p,
+ fixup_cumulative_runnable_avg(&rq->walt_stats,
task_load_delta,
pred_demand_delta);
+ walt_fixup_cum_window_demand(rq, task_load_delta);
}
}
-#elif defined(CONFIG_SCHED_WALT)
-
-inline void reset_cfs_rq_hmp_stats(int cpu, int reset_cra) { }
-
-static void
-fixup_hmp_sched_stats_fair(struct rq *rq, struct task_struct *p,
- u32 new_task_load, u32 new_pred_demand)
+static void walt_fixup_nr_big_tasks(struct rq *rq, struct task_struct *p,
+ int delta, bool inc)
{
- s64 task_load_delta = (s64)new_task_load - task_load(p);
- s64 pred_demand_delta = PRED_DEMAND_DELTA;
+ struct cfs_rq *cfs_rq;
+ struct sched_entity *se = &p->se;
- fixup_cumulative_runnable_avg(&rq->hmp_stats, p, task_load_delta,
- pred_demand_delta);
+ for_each_sched_entity(se) {
+ cfs_rq = cfs_rq_of(se);
+
+ cfs_rq->walt_stats.nr_big_tasks += inc ? delta : -delta;
+ BUG_ON(cfs_rq->walt_stats.nr_big_tasks < 0);
+
+ if (cfs_rq_throttled(cfs_rq))
+ break;
+ }
+
+ /* Fix up rq->walt_stats only if we didn't find any throttled cfs_rq */
+ if (!se)
+ walt_adjust_nr_big_tasks(rq, delta, inc);
}
-static inline int task_will_be_throttled(struct task_struct *p)
+/*
+ * Check if task is part of a hierarchy where some cfs_rq does not have any
+ * runtime left.
+ *
+ * We can't rely on throttled_hierarchy() to do this test, as
+ * cfs_rq->throttle_count will not be updated yet when this function is called
+ * from scheduler_tick()
+ */
+static int task_will_be_throttled(struct task_struct *p)
{
+ struct sched_entity *se = &p->se;
+ struct cfs_rq *cfs_rq;
+
+ if (!cfs_bandwidth_used())
+ return 0;
+
+ for_each_sched_entity(se) {
+ cfs_rq = cfs_rq_of(se);
+ if (!cfs_rq->runtime_enabled)
+ continue;
+ if (cfs_rq->runtime_remaining <= 0)
+ return 1;
+ }
+
return 0;
}
-void inc_hmp_sched_stats_fair(struct rq *rq,
- struct task_struct *p, int change_cra)
+#else /* CONFIG_CFS_BANDWIDTH */
+
+static void walt_fixup_sched_stats_fair(struct rq *rq, struct task_struct *p,
+ u32 new_task_load, u32 new_pred_demand)
{
- inc_nr_big_task(&rq->hmp_stats, p);
+ fixup_walt_sched_stats_common(rq, p, new_task_load, new_pred_demand);
}
+static void walt_fixup_nr_big_tasks(struct rq *rq, struct task_struct *p,
+ int delta, bool inc)
+{
+ walt_adjust_nr_big_tasks(rq, delta, inc);
+}
+
+static int task_will_be_throttled(struct task_struct *p)
+{
+ return false;
+}
+
+#endif /* CONFIG_CFS_BANDWIDTH */
+
static inline int
kick_active_balance(struct rq *rq, struct task_struct *p, int new_cpu)
{
@@ -11108,17 +11076,6 @@
return rc;
}
-#else
-
-static inline int task_will_be_throttled(struct task_struct *p)
-{
- return 0;
-}
-
-#endif
-
-#if defined(CONFIG_SCHED_WALT)
-
static DEFINE_RAW_SPINLOCK(migration_lock);
void check_for_migration(struct rq *rq, struct task_struct *p)
{
@@ -11131,6 +11088,9 @@
rq->curr->nr_cpus_allowed == 1)
return;
+ if (task_will_be_throttled(p))
+ return;
+
raw_spin_lock(&migration_lock);
rcu_read_lock();
new_cpu = energy_aware_wake_cpu(p, cpu, 0);
diff --git a/kernel/sched/idle_task.c b/kernel/sched/idle_task.c
index b852cbe..5405d3f 100644
--- a/kernel/sched/idle_task.c
+++ b/kernel/sched/idle_task.c
@@ -78,14 +78,6 @@
{
}
-#ifdef CONFIG_SCHED_WALT
-static void
-fixup_hmp_sched_stats_idle(struct rq *rq, struct task_struct *p,
- u32 new_task_load, u32 new_pred_demand)
-{
-}
-#endif
-
/*
* Simple, special scheduling class for the per-CPU idle tasks:
*/
@@ -114,7 +106,4 @@
.prio_changed = prio_changed_idle,
.switched_to = switched_to_idle,
.update_curr = update_curr_idle,
-#ifdef CONFIG_SCHED_WALT
- .fixup_hmp_sched_stats = fixup_hmp_sched_stats_idle,
-#endif
};
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
index 2b556d0..6b935e7 100644
--- a/kernel/sched/rt.c
+++ b/kernel/sched/rt.c
@@ -11,45 +11,6 @@
#include <linux/irq_work.h>
#include <trace/events/sched.h>
-#ifdef CONFIG_SCHED_WALT
-
-static void
-inc_hmp_sched_stats_rt(struct rq *rq, struct task_struct *p)
-{
- inc_cumulative_runnable_avg(&rq->hmp_stats, p);
-}
-
-static void
-dec_hmp_sched_stats_rt(struct rq *rq, struct task_struct *p)
-{
- dec_cumulative_runnable_avg(&rq->hmp_stats, p);
-}
-
-static void
-fixup_hmp_sched_stats_rt(struct rq *rq, struct task_struct *p,
- u32 new_task_load, u32 new_pred_demand)
-{
- s64 task_load_delta = (s64)new_task_load - task_load(p);
- s64 pred_demand_delta = PRED_DEMAND_DELTA;
-
- fixup_cumulative_runnable_avg(&rq->hmp_stats, p, task_load_delta,
- pred_demand_delta);
-}
-
-#ifdef CONFIG_SMP
-static int find_lowest_rq(struct task_struct *task);
-
-#endif /* CONFIG_SMP */
-#else /* CONFIG_SCHED_WALT */
-
-static inline void
-inc_hmp_sched_stats_rt(struct rq *rq, struct task_struct *p) { }
-
-static inline void
-dec_hmp_sched_stats_rt(struct rq *rq, struct task_struct *p) { }
-
-#endif /* CONFIG_SCHED_WALT */
-
#include "walt.h"
int sched_rr_timeslice = RR_TIMESLICE;
@@ -1421,7 +1382,7 @@
rt_se->timeout = 0;
enqueue_rt_entity(rt_se, flags);
- inc_hmp_sched_stats_rt(rq, p);
+ walt_inc_cumulative_runnable_avg(rq, p);
if (!task_current(rq, p) && tsk_nr_cpus_allowed(p) > 1)
enqueue_pushable_task(rq, p);
@@ -1433,7 +1394,7 @@
update_curr_rt(rq);
dequeue_rt_entity(rt_se, flags);
- dec_hmp_sched_stats_rt(rq, p);
+ walt_dec_cumulative_runnable_avg(rq, p);
dequeue_pushable_task(rq, p);
}
@@ -1752,18 +1713,6 @@
static DEFINE_PER_CPU(cpumask_var_t, local_cpu_mask);
-static inline unsigned long task_util(struct task_struct *p)
-{
-#ifdef CONFIG_SCHED_WALT
- if (!walt_disabled && sysctl_sched_use_walt_task_util) {
- u64 demand = p->ravg.demand;
-
- return (demand << 10) / sched_ravg_window;
- }
-#endif
- return p->se.avg.util_avg;
-}
-
static int find_lowest_rq(struct task_struct *task)
{
struct sched_domain *sd;
@@ -2623,7 +2572,7 @@
.update_curr = update_curr_rt,
#ifdef CONFIG_SCHED_WALT
- .fixup_hmp_sched_stats = fixup_hmp_sched_stats_rt,
+ .fixup_walt_sched_stats = fixup_walt_sched_stats_common,
#endif
};
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 07d7731..318d289 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -25,10 +25,12 @@
struct rq;
struct cpuidle_state;
+extern __read_mostly bool sched_predl;
+
#ifdef CONFIG_SCHED_WALT
extern unsigned int sched_ravg_window;
-struct hmp_sched_stats {
+struct walt_sched_stats {
int nr_big_tasks;
u64 cumulative_runnable_avg;
u64 pred_demands_sum;
@@ -106,6 +108,12 @@
static inline void cpu_load_update_active(struct rq *this_rq) { }
#endif
+#ifdef CONFIG_SCHED_SMT
+extern void update_idle_core(struct rq *rq);
+#else
+static inline void update_idle_core(struct rq *rq) { }
+#endif
+
/*
* Helpers for converting nanosecond timing to jiffy resolution
*/
@@ -503,13 +511,10 @@
struct list_head leaf_cfs_rq_list;
struct task_group *tg; /* group that "owns" this runqueue */
-#ifdef CONFIG_SCHED_WALT
- u64 cumulative_runnable_avg;
-#endif
-
#ifdef CONFIG_CFS_BANDWIDTH
+
#ifdef CONFIG_SCHED_WALT
- struct hmp_sched_stats hmp_stats;
+ struct walt_sched_stats walt_stats;
#endif
int runtime_enabled;
@@ -768,13 +773,13 @@
#ifdef CONFIG_SCHED_WALT
struct sched_cluster *cluster;
struct cpumask freq_domain_cpumask;
- struct hmp_sched_stats hmp_stats;
+ struct walt_sched_stats walt_stats;
int cstate, wakeup_latency, wakeup_energy;
u64 window_start;
s64 cum_window_start;
u64 load_reported_window;
- unsigned long hmp_flags;
+ unsigned long walt_flags;
u64 cur_irqload;
u64 avg_irqload;
@@ -859,23 +864,6 @@
#endif
}
-
-#ifdef CONFIG_SCHED_SMT
-
-extern struct static_key_false sched_smt_present;
-
-extern void __update_idle_core(struct rq *rq);
-
-static inline void update_idle_core(struct rq *rq)
-{
- if (static_branch_unlikely(&sched_smt_present))
- __update_idle_core(rq);
-}
-
-#else
-static inline void update_idle_core(struct rq *rq) { }
-#endif
-
DECLARE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues);
#define cpu_rq(cpu) (&per_cpu(runqueues, (cpu)))
@@ -1424,7 +1412,7 @@
void (*task_change_group) (struct task_struct *p, int type);
#endif
#ifdef CONFIG_SCHED_WALT
- void (*fixup_hmp_sched_stats)(struct rq *rq, struct task_struct *p,
+ void (*fixup_walt_sched_stats)(struct rq *rq, struct task_struct *p,
u32 new_task_load, u32 new_pred_demand);
#endif
};
@@ -1456,7 +1444,6 @@
extern void update_group_capacity(struct sched_domain *sd, int cpu);
extern void trigger_load_balance(struct rq *rq);
-extern void nohz_balance_clear_nohz_mask(int cpu);
extern void set_cpus_allowed_common(struct task_struct *p, const struct cpumask *new_mask);
@@ -1716,9 +1703,18 @@
return cpu_rq(cpu)->cpu_capacity_orig;
}
-extern unsigned int sysctl_sched_use_walt_cpu_util;
extern unsigned int walt_disabled;
+static inline unsigned long task_util(struct task_struct *p)
+{
+#ifdef CONFIG_SCHED_WALT
+ if (!walt_disabled && sysctl_sched_use_walt_task_util)
+ return p->ravg.demand /
+ (sched_ravg_window >> SCHED_CAPACITY_SHIFT);
+#endif
+ return p->se.avg.util_avg;
+}
+
/*
* cpu_util returns the amount of capacity of a CPU that is used by CFS
* tasks. The unit of the return value must be the one of capacity so we can
@@ -1752,7 +1748,7 @@
#ifdef CONFIG_SCHED_WALT
if (!walt_disabled && sysctl_sched_use_walt_cpu_util) {
- util = cpu_rq(cpu)->hmp_stats.cumulative_runnable_avg;
+ util = cpu_rq(cpu)->walt_stats.cumulative_runnable_avg;
util = div64_u64(util,
sched_ravg_window >> SCHED_CAPACITY_SHIFT);
}
@@ -1816,13 +1812,18 @@
if (walt_load) {
u64 nl = cpu_rq(cpu)->nt_prev_runnable_sum +
rq->grp_time.nt_prev_runnable_sum;
+ u64 pl = rq->walt_stats.pred_demands_sum;
nl = div64_u64(nl, sched_ravg_window >>
SCHED_CAPACITY_SHIFT);
+ pl = div64_u64(pl, sched_ravg_window >>
+ SCHED_CAPACITY_SHIFT);
walt_load->prev_window_util = util;
walt_load->nl = nl;
- walt_load->pl = 0;
+ walt_load->pl = pl;
+ rq->old_busy_time = util;
+ rq->old_estimated_time = pl;
walt_load->ws = rq->window_start;
}
}
@@ -2206,14 +2207,12 @@
#ifdef CONFIG_SCHED_WALT
u64 sched_ktime_clock(void);
void note_task_waking(struct task_struct *p, u64 wallclock);
-extern void update_avg_burst(struct task_struct *p);
#else /* CONFIG_SCHED_WALT */
static inline u64 sched_ktime_clock(void)
{
return 0;
}
static inline void note_task_waking(struct task_struct *p, u64 wallclock) { }
-static inline void update_avg_burst(struct task_struct *p) { }
#endif /* CONFIG_SCHED_WALT */
#ifdef CONFIG_CPU_FREQ
@@ -2246,6 +2245,9 @@
struct update_util_data *data;
#ifdef CONFIG_SCHED_WALT
+ unsigned int exception_flags = SCHED_CPUFREQ_INTERCLUSTER_MIG |
+ SCHED_CPUFREQ_PL;
+
/*
* Skip if we've already reported, but not if this is an inter-cluster
* migration. Also only allow WALT update sites.
@@ -2254,7 +2256,7 @@
return;
if (!sched_disable_window_stats &&
(rq->load_reported_window == rq->window_start) &&
- !(flags & SCHED_CPUFREQ_INTERCLUSTER_MIG))
+ !(flags & exception_flags))
return;
rq->load_reported_window = rq->window_start;
#endif
@@ -2348,13 +2350,11 @@
extern unsigned int __read_mostly sched_load_granule;
extern int register_cpu_cycle_counter_cb(struct cpu_cycle_counter_cb *cb);
-extern void reset_cpu_hmp_stats(int cpu, int reset_cra);
extern int update_preferred_cluster(struct related_thread_group *grp,
struct task_struct *p, u32 old_load);
extern void set_preferred_cluster(struct related_thread_group *grp);
extern void add_new_task_to_grp(struct task_struct *new);
extern unsigned int update_freq_aggregate_threshold(unsigned int threshold);
-extern void update_avg(u64 *avg, u64 sample);
#define NO_BOOST 0
#define FULL_THROTTLE_BOOST 1
@@ -2482,6 +2482,11 @@
return cpu_max_possible_capacity(cpu) == max_possible_capacity;
}
+static inline bool is_min_capacity_cpu(int cpu)
+{
+ return cpu_max_possible_capacity(cpu) == min_max_possible_capacity;
+}
+
/*
* 'load' is in reference to "best cpu" at its best frequency.
* Scale that in reference to a given cpu, accounting for how bad it is
@@ -2536,6 +2541,11 @@
return p->ravg.demand;
}
+static inline unsigned int task_pl(struct task_struct *p)
+{
+ return p->ravg.pred_demand;
+}
+
#define pct_to_real(tunable) \
(div64_u64((u64)tunable * (u64)max_task_load(), 100))
@@ -2569,54 +2579,11 @@
#define BOOST_KICK 0
#define CPU_RESERVED 1
-static inline u64 cpu_cravg_sync(int cpu, int sync)
-{
- struct rq *rq = cpu_rq(cpu);
- u64 load;
-
- load = rq->hmp_stats.cumulative_runnable_avg;
-
- /*
- * If load is being checked in a sync wakeup environment,
- * we may want to discount the load of the currently running
- * task.
- */
- if (sync && cpu == smp_processor_id()) {
- if (load > rq->curr->ravg.demand)
- load -= rq->curr->ravg.demand;
- else
- load = 0;
- }
-
- return load;
-}
-
-extern int power_delta_exceeded(unsigned int cpu_cost, unsigned int base_cost);
-extern void reset_all_window_stats(u64 window_start, unsigned int window_size);
extern int sched_boost(void);
-extern int task_load_will_fit(struct task_struct *p, u64 task_load, int cpu,
- enum sched_boost_policy boost_policy);
-extern int task_will_fit(struct task_struct *p, int cpu);
-extern u64 cpu_load(int cpu);
-extern u64 cpu_load_sync(int cpu, int sync);
extern int preferred_cluster(struct sched_cluster *cluster,
struct task_struct *p);
-extern void inc_rq_hmp_stats(struct rq *rq,
- struct task_struct *p, int change_cra);
-extern void dec_rq_hmp_stats(struct rq *rq,
- struct task_struct *p, int change_cra);
-extern void reset_hmp_stats(struct hmp_sched_stats *stats, int reset_cra);
-extern int upmigrate_discouraged(struct task_struct *p);
extern struct sched_cluster *rq_cluster(struct rq *rq);
-extern int nr_big_tasks(struct rq *rq);
extern void reset_task_stats(struct task_struct *p);
-extern void reset_cfs_rq_hmp_stats(int cpu, int reset_cra);
-extern void inc_hmp_sched_stats_fair(struct rq *rq,
- struct task_struct *p, int change_cra);
-extern u64 cpu_upmigrate_discourage_read_u64(struct cgroup_subsys_state *css,
- struct cftype *cft);
-extern int cpu_upmigrate_discourage_write_u64(struct cgroup_subsys_state *css,
- struct cftype *cft, u64 upmigrate_discourage);
extern void clear_top_tasks_bitmap(unsigned long *bitmap);
#if defined(CONFIG_SCHED_TUNE) && defined(CONFIG_CGROUP_SCHEDTUNE)
@@ -2652,53 +2619,42 @@
{
struct rq *rq = cpu_rq(cpu);
- return test_bit(CPU_RESERVED, &rq->hmp_flags);
+ return test_bit(CPU_RESERVED, &rq->walt_flags);
}
static inline int mark_reserved(int cpu)
{
struct rq *rq = cpu_rq(cpu);
- return test_and_set_bit(CPU_RESERVED, &rq->hmp_flags);
+ return test_and_set_bit(CPU_RESERVED, &rq->walt_flags);
}
static inline void clear_reserved(int cpu)
{
struct rq *rq = cpu_rq(cpu);
- clear_bit(CPU_RESERVED, &rq->hmp_flags);
-}
-
-static inline bool
-__task_in_cum_window_demand(struct rq *rq, struct task_struct *p)
-{
- return (p->on_rq || p->last_sleep_ts >= rq->window_start);
+ clear_bit(CPU_RESERVED, &rq->walt_flags);
}
static inline bool
task_in_cum_window_demand(struct rq *rq, struct task_struct *p)
{
- return cpu_of(rq) == task_cpu(p) && __task_in_cum_window_demand(rq, p);
+ return cpu_of(rq) == task_cpu(p) && (p->on_rq || p->last_sleep_ts >=
+ rq->window_start);
}
-static inline void
-dec_cum_window_demand(struct rq *rq, struct task_struct *p)
-{
- rq->cum_window_demand -= p->ravg.demand;
- WARN_ON_ONCE(rq->cum_window_demand < 0);
-}
-
-static inline void
-inc_cum_window_demand(struct rq *rq, struct task_struct *p, s64 delta)
+static inline void walt_fixup_cum_window_demand(struct rq *rq, s64 delta)
{
rq->cum_window_demand += delta;
+ if (unlikely((s64)rq->cum_window_demand < 0))
+ rq->cum_window_demand = 0;
}
extern void update_cpu_cluster_capacity(const cpumask_t *cpus);
extern unsigned long thermal_cap(int cpu);
-extern void clear_hmp_request(int cpu);
+extern void clear_walt_request(int cpu);
extern int got_boost_kick(void);
extern void clear_boost_kick(int cpu);
@@ -2714,7 +2670,7 @@
#else /* CONFIG_SCHED_WALT */
-struct hmp_sched_stats;
+struct walt_sched_stats;
struct related_thread_group;
struct sched_cluster;
@@ -2725,43 +2681,14 @@
static inline void check_for_migration(struct rq *rq, struct task_struct *p) { }
-static inline int task_will_fit(struct task_struct *p, int cpu)
-{
- return 1;
-}
-
static inline int sched_boost(void)
{
return 0;
}
-static inline int is_big_task(struct task_struct *p)
-{
- return 0;
-}
-
-static inline int nr_big_tasks(struct rq *rq)
-{
- return 0;
-}
-
-static inline int is_cpu_throttling_imminent(int cpu)
-{
- return 0;
-}
-
-static inline int is_task_migration_throttled(struct task_struct *p)
-{
- return 0;
-}
-
+static inline bool hmp_capable(void) { return false; }
static inline bool is_max_capacity_cpu(int cpu) { return true; }
-
-static inline void
-inc_rq_hmp_stats(struct rq *rq, struct task_struct *p, int change_cra) { }
-
-static inline void
-dec_rq_hmp_stats(struct rq *rq, struct task_struct *p, int change_cra) { }
+static inline bool is_min_capacity_cpu(int cpu) { return true; }
static inline int
preferred_cluster(struct sched_cluster *cluster, struct task_struct *p)
@@ -2798,6 +2725,7 @@
}
static inline u32 task_load(struct task_struct *p) { return 0; }
+static inline u32 task_pl(struct task_struct *p) { return 0; }
static inline int update_preferred_cluster(struct related_thread_group *grp,
struct task_struct *p, u32 old_load)
@@ -2822,17 +2750,7 @@
#define trace_sched_cpu_load_cgroup(...)
#define trace_sched_cpu_load_wakeup(...)
-static inline bool
-__task_in_cum_window_demand(struct rq *rq, struct task_struct *p)
-{
- return 0;
-}
-
-static inline void
-dec_cum_window_demand(struct rq *rq, struct task_struct *p) { }
-
-static inline void
-inc_cum_window_demand(struct rq *rq, struct task_struct *p, s64 delta) { }
+static inline void walt_fixup_cum_window_demand(struct rq *rq, s64 delta) { }
static inline void update_cpu_cluster_capacity(const cpumask_t *cpus) { }
@@ -2843,7 +2761,7 @@
}
#endif
-static inline void clear_hmp_request(int cpu) { }
+static inline void clear_walt_request(int cpu) { }
static inline int got_boost_kick(void)
{
diff --git a/kernel/sched/sched_avg.c b/kernel/sched/sched_avg.c
index 4238924..166c643 100644
--- a/kernel/sched/sched_avg.c
+++ b/kernel/sched/sched_avg.c
@@ -33,6 +33,8 @@
static DEFINE_PER_CPU(spinlock_t, nr_lock) = __SPIN_LOCK_UNLOCKED(nr_lock);
static s64 last_get_time;
+static DEFINE_PER_CPU(atomic64_t, last_busy_time) = ATOMIC64_INIT(0);
+
#define DIV64_U64_ROUNDUP(X, Y) div64_u64((X) + (Y - 1), Y)
/**
* sched_get_nr_running_avg
@@ -120,6 +122,27 @@
}
EXPORT_SYMBOL(sched_get_nr_running_avg);
+#define BUSY_NR_RUN 3
+#define BUSY_LOAD_FACTOR 2
+static inline void update_last_busy_time(int cpu, bool dequeue,
+ unsigned long prev_nr_run, u64 curr_time)
+{
+ bool nr_run_trigger = false, load_trigger = false;
+
+ if (!hmp_capable() || is_min_capacity_cpu(cpu))
+ return;
+
+ if (prev_nr_run >= BUSY_NR_RUN && per_cpu(nr, cpu) < BUSY_NR_RUN)
+ nr_run_trigger = true;
+
+ if (dequeue && (cpu_util(cpu) * BUSY_LOAD_FACTOR) >
+ capacity_orig_of(cpu))
+ load_trigger = true;
+
+ if (nr_run_trigger || load_trigger)
+ atomic64_set(&per_cpu(last_busy_time, cpu), curr_time);
+}
+
/**
* sched_update_nr_prod
* @cpu: The core id of the nr running driver.
@@ -148,6 +171,8 @@
if (per_cpu(nr, cpu) > per_cpu(nr_max, cpu))
per_cpu(nr_max, cpu) = per_cpu(nr, cpu);
+ update_last_busy_time(cpu, !inc, nr_running, curr_time);
+
per_cpu(nr_prod_sum, cpu) += nr_running * diff;
per_cpu(nr_big_prod_sum, cpu) += nr_eligible_big_tasks(cpu) * diff;
per_cpu(iowait_prod_sum, cpu) += nr_iowait_cpu(cpu) * diff;
@@ -184,3 +209,8 @@
busy = (util * 100) / capacity;
return busy;
}
+
+u64 sched_get_cpu_last_busy_time(int cpu)
+{
+ return atomic64_read(&per_cpu(last_busy_time, cpu));
+}
diff --git a/kernel/sched/stop_task.c b/kernel/sched/stop_task.c
index dcc4a36..11a1888 100644
--- a/kernel/sched/stop_task.c
+++ b/kernel/sched/stop_task.c
@@ -18,41 +18,6 @@
}
#endif /* CONFIG_SMP */
-#ifdef CONFIG_SCHED_WALT
-
-static void
-inc_hmp_sched_stats_stop(struct rq *rq, struct task_struct *p)
-{
- inc_cumulative_runnable_avg(&rq->hmp_stats, p);
-}
-
-static void
-dec_hmp_sched_stats_stop(struct rq *rq, struct task_struct *p)
-{
- dec_cumulative_runnable_avg(&rq->hmp_stats, p);
-}
-
-static void
-fixup_hmp_sched_stats_stop(struct rq *rq, struct task_struct *p,
- u32 new_task_load, u32 new_pred_demand)
-{
- s64 task_load_delta = (s64)new_task_load - task_load(p);
- s64 pred_demand_delta = PRED_DEMAND_DELTA;
-
- fixup_cumulative_runnable_avg(&rq->hmp_stats, p, task_load_delta,
- pred_demand_delta);
-}
-
-#else /* CONFIG_SCHED_WALT */
-
-static inline void
-inc_hmp_sched_stats_stop(struct rq *rq, struct task_struct *p) { }
-
-static inline void
-dec_hmp_sched_stats_stop(struct rq *rq, struct task_struct *p) { }
-
-#endif /* CONFIG_SCHED_WALT */
-
static void
check_preempt_curr_stop(struct rq *rq, struct task_struct *p, int flags)
{
@@ -78,14 +43,14 @@
enqueue_task_stop(struct rq *rq, struct task_struct *p, int flags)
{
add_nr_running(rq, 1);
- inc_hmp_sched_stats_stop(rq, p);
+ walt_inc_cumulative_runnable_avg(rq, p);
}
static void
dequeue_task_stop(struct rq *rq, struct task_struct *p, int flags)
{
sub_nr_running(rq, 1);
- dec_hmp_sched_stats_stop(rq, p);
+ walt_dec_cumulative_runnable_avg(rq, p);
}
static void yield_task_stop(struct rq *rq)
@@ -173,6 +138,6 @@
.switched_to = switched_to_stop,
.update_curr = update_curr_stop,
#ifdef CONFIG_SCHED_WALT
- .fixup_hmp_sched_stats = fixup_hmp_sched_stats_stop,
+ .fixup_walt_sched_stats = fixup_walt_sched_stats_common,
#endif
};
diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c
index 6f7d34d..48f3512 100644
--- a/kernel/sched/walt.c
+++ b/kernel/sched/walt.c
@@ -116,8 +116,6 @@
* IMPORTANT: Initialize both copies to same value!!
*/
-static __read_mostly bool sched_predl;
-
__read_mostly unsigned int sched_ravg_hist_size = 5;
__read_mostly unsigned int sysctl_sched_ravg_hist_size = 5;
@@ -207,27 +205,28 @@
}
early_param("sched_predl", set_sched_predl);
-void inc_rq_hmp_stats(struct rq *rq, struct task_struct *p, int change_cra)
+void inc_rq_walt_stats(struct rq *rq, struct task_struct *p)
{
- inc_nr_big_task(&rq->hmp_stats, p);
- if (change_cra)
- inc_cumulative_runnable_avg(&rq->hmp_stats, p);
+ inc_nr_big_task(&rq->walt_stats, p);
+ walt_inc_cumulative_runnable_avg(rq, p);
}
-void dec_rq_hmp_stats(struct rq *rq, struct task_struct *p, int change_cra)
+void dec_rq_walt_stats(struct rq *rq, struct task_struct *p)
{
- dec_nr_big_task(&rq->hmp_stats, p);
- if (change_cra)
- dec_cumulative_runnable_avg(&rq->hmp_stats, p);
+ dec_nr_big_task(&rq->walt_stats, p);
+ walt_dec_cumulative_runnable_avg(rq, p);
}
-void reset_hmp_stats(struct hmp_sched_stats *stats, int reset_cra)
+void fixup_walt_sched_stats_common(struct rq *rq, struct task_struct *p,
+ u32 new_task_load, u32 new_pred_demand)
{
- stats->nr_big_tasks = 0; /* never happens on EAS */
- if (reset_cra) {
- stats->cumulative_runnable_avg = 0;
- stats->pred_demands_sum = 0;
- }
+ s64 task_load_delta = (s64)new_task_load - task_load(p);
+ s64 pred_demand_delta = PRED_DEMAND_DELTA;
+
+ fixup_cumulative_runnable_avg(&rq->walt_stats, task_load_delta,
+ pred_demand_delta);
+
+ walt_fixup_cum_window_demand(rq, task_load_delta);
}
/*
@@ -295,9 +294,7 @@
nr_windows = div64_u64(delta, sched_ravg_window);
rq->window_start += (u64)nr_windows * (u64)sched_ravg_window;
- rq->cum_window_demand = rq->hmp_stats.cumulative_runnable_avg;
- if (event == PUT_PREV_TASK)
- rq->cum_window_demand += rq->curr->ravg.demand;
+ rq->cum_window_demand = rq->walt_stats.cumulative_runnable_avg;
return old_window_start;
}
@@ -379,12 +376,12 @@
struct rq *rq = cpu_rq(cpu);
if (!is_max_capacity_cpu(cpu))
- return rq->hmp_stats.nr_big_tasks;
+ return rq->walt_stats.nr_big_tasks;
return rq->nr_running;
}
-void clear_hmp_request(int cpu)
+void clear_walt_request(int cpu)
{
struct rq *rq = cpu_rq(cpu);
unsigned long flags;
@@ -622,20 +619,6 @@
raw_spin_unlock(&cluster->load_lock);
}
-static inline void
-init_new_task_load_hmp(struct task_struct *p, bool idle_task)
-{
-}
-
-static inline void
-update_task_burst(struct task_struct *p, struct rq *rq, int event, int runtime)
-{
-}
-
-static void reset_task_stats_hmp(struct task_struct *p)
-{
-}
-
static inline void inter_cluster_migration_fixup
(struct task_struct *p, int new_cpu, int task_cpu, bool new_task)
{
@@ -788,9 +771,15 @@
update_task_cpu_cycles(p, new_cpu);
- if (__task_in_cum_window_demand(src_rq, p)) {
- dec_cum_window_demand(src_rq, p);
- inc_cum_window_demand(dest_rq, p, p->ravg.demand);
+ /*
+ * When a task is migrating during the wakeup, adjust
+ * the task's contribution towards cumulative window
+ * demand.
+ */
+ if (p->state == TASK_WAKING && p->last_sleep_ts >=
+ src_rq->window_start) {
+ walt_fixup_cum_window_demand(src_rq, -(s64)p->ravg.demand);
+ walt_fixup_cum_window_demand(dest_rq, p->ravg.demand);
}
new_task = is_new_task(p);
@@ -1071,7 +1060,7 @@
if (task_on_rq_queued(p) && (!task_has_dl_policy(p) ||
!p->dl.dl_throttled))
- p->sched_class->fixup_hmp_sched_stats(rq, p,
+ p->sched_class->fixup_walt_sched_stats(rq, p,
p->ravg.demand,
new);
@@ -1288,6 +1277,33 @@
return delta;
}
+/* Convert busy time to frequency equivalent
+ * Assumes load is scaled to 1024
+ */
+static inline unsigned int load_to_freq(struct rq *rq, u64 load)
+{
+ return mult_frac(cpu_max_possible_freq(cpu_of(rq)), load,
+ capacity_orig_of(cpu_of(rq)));
+}
+
+bool do_pl_notif(struct rq *rq)
+{
+ u64 prev = rq->old_busy_time;
+ u64 pl = rq->walt_stats.pred_demands_sum;
+ int cpu = cpu_of(rq);
+
+ /* If already at max freq, bail out */
+ if (capacity_orig_of(cpu) == capacity_curr_of(cpu))
+ return false;
+
+ prev = max(prev, rq->old_estimated_time);
+
+ pl = div64_u64(pl, sched_ravg_window >> SCHED_CAPACITY_SHIFT);
+
+ /* 400 MHz filter. */
+ return (pl > prev) && (load_to_freq(rq, pl - prev) > 400000);
+}
+
static void rollover_cpu_window(struct rq *rq, bool full_window)
{
u64 curr_sum = rq->curr_runnable_sum;
@@ -1666,21 +1682,28 @@
/*
* A throttled deadline sched class task gets dequeued without
- * changing p->on_rq. Since the dequeue decrements hmp stats
+ * changing p->on_rq. Since the dequeue decrements walt stats
* avoid decrementing it here again.
+ *
+ * When window is rolled over, the cumulative window demand
+ * is reset to the cumulative runnable average (contribution from
+ * the tasks on the runqueue). If the current task is dequeued
+ * already, it's demand is not included in the cumulative runnable
+ * average. So add the task demand separately to cumulative window
+ * demand.
*/
- if (task_on_rq_queued(p) && (!task_has_dl_policy(p) ||
- !p->dl.dl_throttled))
- p->sched_class->fixup_hmp_sched_stats(rq, p, demand,
- pred_demand);
+ if (!task_has_dl_policy(p) || !p->dl.dl_throttled) {
+ if (task_on_rq_queued(p))
+ p->sched_class->fixup_walt_sched_stats(rq, p, demand,
+ pred_demand);
+ else if (rq->curr == p)
+ walt_fixup_cum_window_demand(rq, demand);
+ }
p->ravg.demand = demand;
p->ravg.coloc_demand = div64_u64(sum, sched_ravg_hist_size);
p->ravg.pred_demand = pred_demand;
- if (__task_in_cum_window_demand(rq, p))
- inc_cum_window_demand(rq, p, p->ravg.demand - prev_demand);
-
done:
trace_sched_update_history(rq, p, runtime, samples, event);
}
@@ -1879,7 +1902,7 @@
void update_task_ravg(struct task_struct *p, struct rq *rq, int event,
u64 wallclock, u64 irqtime)
{
- u64 runtime, old_window_start;
+ u64 old_window_start;
if (!rq->window_start || sched_disable_window_stats ||
p->ravg.mark_start == wallclock)
@@ -1895,9 +1918,7 @@
}
update_task_rq_cpu_cycles(p, rq, event, wallclock, irqtime);
- runtime = update_task_demand(p, rq, event, wallclock);
- if (runtime)
- update_task_burst(p, rq, event, runtime);
+ update_task_demand(p, rq, event, wallclock);
update_cpu_busy_time(p, rq, event, wallclock, irqtime);
update_task_pred_demand(rq, p, event);
done:
@@ -1938,8 +1959,6 @@
memset(&p->ravg, 0, sizeof(struct ravg));
p->cpu_cycles = 0;
- init_new_task_load_hmp(p, idle_task);
-
p->ravg.curr_window_cpu = kcalloc(nr_cpu_ids, sizeof(u32), GFP_KERNEL);
p->ravg.prev_window_cpu = kcalloc(nr_cpu_ids, sizeof(u32), GFP_KERNEL);
@@ -1995,8 +2014,6 @@
p->ravg.curr_window_cpu = curr_window_ptr;
p->ravg.prev_window_cpu = prev_window_ptr;
- reset_task_stats_hmp(p);
-
/* Retain EXITING_TASK marker */
p->ravg.sum_history[0] = sum;
}
@@ -3069,11 +3086,11 @@
cpumask_set_cpu(cpu_of(rq), &rq->freq_domain_cpumask);
init_irq_work(&walt_migration_irq_work, walt_irq_work);
init_irq_work(&walt_cpufreq_irq_work, walt_irq_work);
- rq->hmp_stats.cumulative_runnable_avg = 0;
+ rq->walt_stats.cumulative_runnable_avg = 0;
rq->window_start = 0;
rq->cum_window_start = 0;
- rq->hmp_stats.nr_big_tasks = 0;
- rq->hmp_flags = 0;
+ rq->walt_stats.nr_big_tasks = 0;
+ rq->walt_flags = 0;
rq->cur_irqload = 0;
rq->avg_irqload = 0;
rq->irqload_ts = 0;
@@ -3096,7 +3113,7 @@
rq->old_busy_time = 0;
rq->old_estimated_time = 0;
rq->old_busy_time_group = 0;
- rq->hmp_stats.pred_demands_sum = 0;
+ rq->walt_stats.pred_demands_sum = 0;
rq->ed_task = NULL;
rq->curr_table = 0;
rq->prev_top = 0;
diff --git a/kernel/sched/walt.h b/kernel/sched/walt.h
index 3f4739e..535f14b 100644
--- a/kernel/sched/walt.h
+++ b/kernel/sched/walt.h
@@ -66,7 +66,7 @@
extern unsigned int nr_eligible_big_tasks(int cpu);
static inline void
-inc_nr_big_task(struct hmp_sched_stats *stats, struct task_struct *p)
+inc_nr_big_task(struct walt_sched_stats *stats, struct task_struct *p)
{
if (sched_disable_window_stats)
return;
@@ -76,7 +76,7 @@
}
static inline void
-dec_nr_big_task(struct hmp_sched_stats *stats, struct task_struct *p)
+dec_nr_big_task(struct walt_sched_stats *stats, struct task_struct *p)
{
if (sched_disable_window_stats)
return;
@@ -88,57 +88,20 @@
}
static inline void
-adjust_nr_big_tasks(struct hmp_sched_stats *stats, int delta, bool inc)
+walt_adjust_nr_big_tasks(struct rq *rq, int delta, bool inc)
{
- struct rq *rq = container_of(stats, struct rq, hmp_stats);
-
if (sched_disable_window_stats)
return;
sched_update_nr_prod(cpu_of(rq), 0, true);
- stats->nr_big_tasks += inc ? delta : -delta;
+ rq->walt_stats.nr_big_tasks += inc ? delta : -delta;
- BUG_ON(stats->nr_big_tasks < 0);
+ BUG_ON(rq->walt_stats.nr_big_tasks < 0);
}
static inline void
-inc_cumulative_runnable_avg(struct hmp_sched_stats *stats,
- struct task_struct *p)
-{
- u32 task_load;
-
- if (sched_disable_window_stats)
- return;
-
- task_load = sched_disable_window_stats ? 0 : p->ravg.demand;
-
- stats->cumulative_runnable_avg += task_load;
- stats->pred_demands_sum += p->ravg.pred_demand;
-}
-
-static inline void
-dec_cumulative_runnable_avg(struct hmp_sched_stats *stats,
- struct task_struct *p)
-{
- u32 task_load;
-
- if (sched_disable_window_stats)
- return;
-
- task_load = sched_disable_window_stats ? 0 : p->ravg.demand;
-
- stats->cumulative_runnable_avg -= task_load;
-
- BUG_ON((s64)stats->cumulative_runnable_avg < 0);
-
- stats->pred_demands_sum -= p->ravg.pred_demand;
- BUG_ON((s64)stats->pred_demands_sum < 0);
-}
-
-static inline void
-fixup_cumulative_runnable_avg(struct hmp_sched_stats *stats,
- struct task_struct *p, s64 task_load_delta,
- s64 pred_demand_delta)
+fixup_cumulative_runnable_avg(struct walt_sched_stats *stats,
+ s64 task_load_delta, s64 pred_demand_delta)
{
if (sched_disable_window_stats)
return;
@@ -150,17 +113,56 @@
BUG_ON((s64)stats->pred_demands_sum < 0);
}
-extern void inc_rq_hmp_stats(struct rq *rq,
- struct task_struct *p, int change_cra);
-extern void dec_rq_hmp_stats(struct rq *rq,
- struct task_struct *p, int change_cra);
-extern void reset_hmp_stats(struct hmp_sched_stats *stats, int reset_cra);
+static inline void
+walt_inc_cumulative_runnable_avg(struct rq *rq, struct task_struct *p)
+{
+ if (sched_disable_window_stats)
+ return;
+
+ fixup_cumulative_runnable_avg(&rq->walt_stats, p->ravg.demand,
+ p->ravg.pred_demand);
+
+ /*
+ * Add a task's contribution to the cumulative window demand when
+ *
+ * (1) task is enqueued with on_rq = 1 i.e migration,
+ * prio/cgroup/class change.
+ * (2) task is waking for the first time in this window.
+ */
+ if (p->on_rq || (p->last_sleep_ts < rq->window_start))
+ walt_fixup_cum_window_demand(rq, p->ravg.demand);
+}
+
+static inline void
+walt_dec_cumulative_runnable_avg(struct rq *rq, struct task_struct *p)
+{
+ if (sched_disable_window_stats)
+ return;
+
+ fixup_cumulative_runnable_avg(&rq->walt_stats, -(s64)p->ravg.demand,
+ -(s64)p->ravg.pred_demand);
+
+ /*
+ * on_rq will be 1 for sleeping tasks. So check if the task
+ * is migrating or dequeuing in RUNNING state to change the
+ * prio/cgroup/class.
+ */
+ if (task_on_rq_migrating(p) || p->state == TASK_RUNNING)
+ walt_fixup_cum_window_demand(rq, -(s64)p->ravg.demand);
+}
+
+extern void fixup_walt_sched_stats_common(struct rq *rq, struct task_struct *p,
+ u32 new_task_load,
+ u32 new_pred_demand);
+extern void inc_rq_walt_stats(struct rq *rq, struct task_struct *p);
+extern void dec_rq_walt_stats(struct rq *rq, struct task_struct *p);
extern void fixup_busy_time(struct task_struct *p, int new_cpu);
extern void init_new_task_load(struct task_struct *p, bool idle_task);
extern void mark_task_starting(struct task_struct *p);
extern void set_window_start(struct rq *rq);
void account_irqtime(int cpu, struct task_struct *curr, u64 delta,
u64 wallclock);
+extern bool do_pl_notif(struct rq *rq);
#define SCHED_HIGH_IRQ_TIMEOUT 3
static inline u64 sched_irqload(int cpu)
@@ -297,8 +299,8 @@
static inline void update_task_ravg(struct task_struct *p, struct rq *rq,
int event, u64 wallclock, u64 irqtime) { }
-static inline void inc_cumulative_runnable_avg(struct hmp_sched_stats *stats,
- struct task_struct *p)
+static inline void walt_inc_cumulative_runnable_avg(struct rq *rq,
+ struct task_struct *p)
{
}
@@ -307,21 +309,21 @@
return 0;
}
-static inline void adjust_nr_big_tasks(struct hmp_sched_stats *stats,
+static inline void walt_adjust_nr_big_tasks(struct rq *rq,
int delta, bool inc)
{
}
-static inline void inc_nr_big_task(struct hmp_sched_stats *stats,
+static inline void inc_nr_big_task(struct walt_sched_stats *stats,
struct task_struct *p)
{
}
-static inline void dec_nr_big_task(struct hmp_sched_stats *stats,
+static inline void dec_nr_big_task(struct walt_sched_stats *stats,
struct task_struct *p)
{
}
-static inline void dec_cumulative_runnable_avg(struct hmp_sched_stats *stats,
+static inline void walt_dec_cumulative_runnable_avg(struct rq *rq,
struct task_struct *p)
{
}
@@ -348,6 +350,19 @@
}
static inline int same_cluster(int src_cpu, int dst_cpu) { return 1; }
+static inline bool do_pl_notif(struct rq *rq) { return false; }
+
+static inline void
+inc_rq_walt_stats(struct rq *rq, struct task_struct *p) { }
+
+static inline void
+dec_rq_walt_stats(struct rq *rq, struct task_struct *p) { }
+
+static inline void
+fixup_walt_sched_stats_common(struct rq *rq, struct task_struct *p,
+ u32 new_task_load, u32 new_pred_demand)
+{
+}
#endif /* CONFIG_SCHED_WALT */
diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c
index 5dfdf39..842928a 100644
--- a/kernel/time/alarmtimer.c
+++ b/kernel/time/alarmtimer.c
@@ -845,7 +845,8 @@
* Rate limit to the tick as a hot fix to prevent DOS. Will be
* mopped up later.
*/
- if (ktime_to_ns(timr->it.alarm.interval) < TICK_NSEC)
+ if (timr->it.alarm.interval.tv64 &&
+ ktime_to_ns(timr->it.alarm.interval) < TICK_NSEC)
timr->it.alarm.interval = ktime_set(0, TICK_NSEC);
exp = timespec_to_ktime(new_setting->it_value);
diff --git a/kernel/time/sched_clock.c b/kernel/time/sched_clock.c
index a26036d..49237ae 100644
--- a/kernel/time/sched_clock.c
+++ b/kernel/time/sched_clock.c
@@ -70,6 +70,9 @@
static struct hrtimer sched_clock_timer;
static int irqtime = -1;
+static u64 suspend_ns;
+static u64 suspend_cycles;
+static u64 resume_cycles;
core_param(irqtime, irqtime, int, 0400);
@@ -274,6 +277,11 @@
struct clock_read_data *rd = &cd.read_data[0];
update_sched_clock();
+
+ suspend_ns = rd->epoch_ns;
+ suspend_cycles = rd->epoch_cyc;
+ pr_info("suspend ns:%17llu suspend cycles:%17llu\n",
+ rd->epoch_ns, rd->epoch_cyc);
hrtimer_cancel(&sched_clock_timer);
rd->read_sched_clock = suspended_sched_clock_read;
@@ -285,6 +293,8 @@
struct clock_read_data *rd = &cd.read_data[0];
rd->epoch_cyc = cd.actual_read_sched_clock();
+ resume_cycles = rd->epoch_cyc;
+ pr_info("resume cycles:%17llu\n", rd->epoch_cyc);
hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL);
rd->read_sched_clock = cd.actual_read_sched_clock;
}
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 221eb59..4f7ea84 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -3590,7 +3590,7 @@
int exclude_mod = 0;
int found = 0;
int ret;
- int clear_filter;
+ int clear_filter = 0;
if (func) {
func_g.type = filter_parse_regex(func, len, &func_g.search,
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index ebf9498..4a848f7 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -1928,7 +1928,7 @@
#endif
((pc & NMI_MASK ) ? TRACE_FLAG_NMI : 0) |
((pc & HARDIRQ_MASK) ? TRACE_FLAG_HARDIRQ : 0) |
- ((pc & SOFTIRQ_MASK) ? TRACE_FLAG_SOFTIRQ : 0) |
+ ((pc & SOFTIRQ_OFFSET) ? TRACE_FLAG_SOFTIRQ : 0) |
(tif_need_resched() ? TRACE_FLAG_NEED_RESCHED : 0) |
(test_preempt_need_resched() ? TRACE_FLAG_PREEMPT_RESCHED : 0);
}
@@ -7257,6 +7257,7 @@
}
kfree(tr->topts);
+ free_cpumask_var(tr->tracing_cpumask);
kfree(tr->name);
kfree(tr);
diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c
index 562fa69..997ac0b 100644
--- a/kernel/trace/trace_event_perf.c
+++ b/kernel/trace/trace_event_perf.c
@@ -259,7 +259,8 @@
void perf_trace_del(struct perf_event *p_event, int flags)
{
struct trace_event_call *tp_event = p_event->tp_event;
- hlist_del_rcu(&p_event->hlist_entry);
+ if (!hlist_unhashed(&p_event->hlist_entry))
+ hlist_del_rcu(&p_event->hlist_entry);
tp_event->class->reg(tp_event, TRACE_REG_PERF_DEL, p_event);
}
diff --git a/kernel/trace/trace_printk.c b/kernel/trace/trace_printk.c
index ad1d616..e82cff5 100644
--- a/kernel/trace/trace_printk.c
+++ b/kernel/trace/trace_printk.c
@@ -304,7 +304,7 @@
if (!*fmt)
return 0;
- seq_printf(m, "0x%lx : \"", *(unsigned long *)fmt);
+ seq_printf(m, "0x%lx : \"", 0L);
/*
* Tabs and new lines need to be converted.
diff --git a/lib/cpumask.c b/lib/cpumask.c
index 81dedaa..4731a08 100644
--- a/lib/cpumask.c
+++ b/lib/cpumask.c
@@ -43,6 +43,38 @@
}
EXPORT_SYMBOL(cpumask_any_but);
+/**
+ * cpumask_next_wrap - helper to implement for_each_cpu_wrap
+ * @n: the cpu prior to the place to search
+ * @mask: the cpumask pointer
+ * @start: the start point of the iteration
+ * @wrap: assume @n crossing @start terminates the iteration
+ *
+ * Returns >= nr_cpu_ids on completion
+ *
+ * Note: the @wrap argument is required for the start condition when
+ * we cannot assume @start is set in @mask.
+ */
+int cpumask_next_wrap(int n, const struct cpumask *mask, int start, bool wrap)
+{
+ int next;
+
+again:
+ next = cpumask_next(n, mask);
+
+ if (wrap && n < start && next >= start) {
+ return nr_cpumask_bits;
+
+ } else if (next >= nr_cpumask_bits) {
+ wrap = true;
+ n = -1;
+ goto again;
+ }
+
+ return next;
+}
+EXPORT_SYMBOL(cpumask_next_wrap);
+
/* These are not inline because of header tangles. */
#ifdef CONFIG_CPUMASK_OFFSTACK
/**
diff --git a/lib/string.c b/lib/string.c
index ed83562..ccabe16 100644
--- a/lib/string.c
+++ b/lib/string.c
@@ -952,3 +952,10 @@
return s;
}
EXPORT_SYMBOL(strreplace);
+
+void fortify_panic(const char *name)
+{
+ pr_emerg("detected buffer overflow in %s\n", name);
+ BUG();
+}
+EXPORT_SYMBOL(fortify_panic);
diff --git a/mm/cma.c b/mm/cma.c
index 3322b30..2984dac 100644
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -36,6 +36,7 @@
#include <linux/highmem.h>
#include <linux/io.h>
#include <linux/delay.h>
+#include <linux/show_mem_notifier.h>
#include <trace/events/cma.h>
#include "cma.h"
@@ -54,6 +55,11 @@
return cma->count << PAGE_SHIFT;
}
+const char *cma_get_name(const struct cma *cma)
+{
+ return cma->name ? cma->name : "(undefined)";
+}
+
static unsigned long cma_bitmap_aligned_mask(const struct cma *cma,
int align_order)
{
@@ -95,6 +101,29 @@
mutex_unlock(&cma->lock);
}
+static int cma_showmem_notifier(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ int i;
+ unsigned long used;
+ struct cma *cma;
+
+ for (i = 0; i < cma_area_count; i++) {
+ cma = &cma_areas[i];
+ used = bitmap_weight(cma->bitmap,
+ (int)cma_bitmap_maxno(cma));
+ used <<= cma->order_per_bit;
+ pr_info("cma-%d pages: => %lu used of %lu total pages\n",
+ i, used, cma->count);
+ }
+
+ return 0;
+}
+
+static struct notifier_block cma_nb = {
+ .notifier_call = cma_showmem_notifier,
+};
+
static int __init cma_activate_area(struct cma *cma)
{
int bitmap_size = BITS_TO_LONGS(cma_bitmap_maxno(cma)) * sizeof(long);
@@ -158,6 +187,8 @@
return ret;
}
+ show_mem_notifier_register(&cma_nb);
+
return 0;
}
core_initcall(cma_init_reserved_areas);
@@ -173,6 +204,7 @@
*/
int __init cma_init_reserved_mem(phys_addr_t base, phys_addr_t size,
unsigned int order_per_bit,
+ const char *name,
struct cma **res_cma)
{
struct cma *cma;
@@ -203,6 +235,13 @@
* subsystems (like slab allocator) are available.
*/
cma = &cma_areas[cma_area_count];
+ if (name) {
+ cma->name = name;
+ } else {
+ cma->name = kasprintf(GFP_KERNEL, "cma%d\n", cma_area_count);
+ if (!cma->name)
+ return -ENOMEM;
+ }
cma->base_pfn = PFN_DOWN(base);
cma->count = size >> PAGE_SHIFT;
cma->order_per_bit = order_per_bit;
@@ -234,7 +273,7 @@
int __init cma_declare_contiguous(phys_addr_t base,
phys_addr_t size, phys_addr_t limit,
phys_addr_t alignment, unsigned int order_per_bit,
- bool fixed, struct cma **res_cma)
+ bool fixed, const char *name, struct cma **res_cma)
{
phys_addr_t memblock_end = memblock_end_of_DRAM();
phys_addr_t highmem_start;
@@ -345,7 +384,7 @@
base = addr;
}
- ret = cma_init_reserved_mem(base, size, order_per_bit, res_cma);
+ ret = cma_init_reserved_mem(base, size, order_per_bit, name, res_cma);
if (ret)
goto err;
@@ -358,6 +397,32 @@
return ret;
}
+#ifdef CONFIG_CMA_DEBUG
+static void cma_debug_show_areas(struct cma *cma)
+{
+ unsigned long next_zero_bit, next_set_bit;
+ unsigned long start = 0;
+ unsigned int nr_zero, nr_total = 0;
+
+ mutex_lock(&cma->lock);
+ pr_info("number of available pages: ");
+ for (;;) {
+ next_zero_bit = find_next_zero_bit(cma->bitmap, cma->count, start);
+ if (next_zero_bit >= cma->count)
+ break;
+ next_set_bit = find_next_bit(cma->bitmap, cma->count, next_zero_bit);
+ nr_zero = next_set_bit - next_zero_bit;
+ pr_cont("%s%u@%lu", nr_total ? "+" : "", nr_zero, next_zero_bit);
+ nr_total += nr_zero;
+ start = next_zero_bit + nr_zero;
+ }
+ pr_cont("=> %u free of %lu total pages\n", nr_total, cma->count);
+ mutex_unlock(&cma->lock);
+}
+#else
+static inline void cma_debug_show_areas(struct cma *cma) { }
+#endif
+
/**
* cma_alloc() - allocate pages from contiguous area
* @cma: Contiguous memory region for which the allocation is performed.
@@ -374,8 +439,8 @@
unsigned long start = 0;
unsigned long bitmap_maxno, bitmap_no, bitmap_count;
struct page *page = NULL;
- int ret;
int retry_after_sleep = 0;
+ int ret = -ENOMEM;
if (!cma || !cma->count)
return NULL;
@@ -452,6 +517,12 @@
trace_cma_alloc(pfn, page, count, align);
+ if (ret) {
+ pr_info("%s: alloc failed, req-size: %zu pages, ret: %d\n",
+ __func__, count, ret);
+ cma_debug_show_areas(cma);
+ }
+
pr_debug("%s(): returned %p\n", __func__, page);
return page;
}
diff --git a/mm/cma.h b/mm/cma.h
index 17c75a4..4986128 100644
--- a/mm/cma.h
+++ b/mm/cma.h
@@ -11,6 +11,7 @@
struct hlist_head mem_head;
spinlock_t mem_head_lock;
#endif
+ const char *name;
};
extern struct cma cma_areas[MAX_CMA_AREAS];
diff --git a/mm/cma_debug.c b/mm/cma_debug.c
index f8e4b60..3f7f84c 100644
--- a/mm/cma_debug.c
+++ b/mm/cma_debug.c
@@ -167,7 +167,7 @@
char name[16];
int u32s;
- sprintf(name, "cma-%d", idx);
+ scnprintf(name, sizeof(name), "cma-%s", cma->name);
tmp = debugfs_create_dir(name, cma_debugfs_root);
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index e7d5db9..8258e9e 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -1373,8 +1373,8 @@
get_page(page);
spin_unlock(ptl);
split_huge_page(page);
- put_page(page);
unlock_page(page);
+ put_page(page);
goto out_unlocked;
}
diff --git a/mm/list_lru.c b/mm/list_lru.c
index 234676e..7a40fa2 100644
--- a/mm/list_lru.c
+++ b/mm/list_lru.c
@@ -117,6 +117,7 @@
l = list_lru_from_kmem(nlru, item);
list_add_tail(item, &l->list);
l->nr_items++;
+ nlru->nr_items++;
spin_unlock(&nlru->lock);
return true;
}
@@ -136,6 +137,7 @@
l = list_lru_from_kmem(nlru, item);
list_del_init(item);
l->nr_items--;
+ nlru->nr_items--;
spin_unlock(&nlru->lock);
return true;
}
@@ -183,15 +185,10 @@
unsigned long list_lru_count_node(struct list_lru *lru, int nid)
{
- long count = 0;
- int memcg_idx;
+ struct list_lru_node *nlru;
- count += __list_lru_count_one(lru, nid, -1);
- if (list_lru_memcg_aware(lru)) {
- for_each_memcg_cache_index(memcg_idx)
- count += __list_lru_count_one(lru, nid, memcg_idx);
- }
- return count;
+ nlru = &lru->node[nid];
+ return nlru->nr_items;
}
EXPORT_SYMBOL_GPL(list_lru_count_node);
@@ -226,6 +223,7 @@
assert_spin_locked(&nlru->lock);
case LRU_REMOVED:
isolated++;
+ nlru->nr_items--;
/*
* If the lru lock has been dropped, our list
* traversal is now invalid and so we have to
diff --git a/mm/mmap.c b/mm/mmap.c
index b8f91e0e..6f90f07 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -2237,7 +2237,7 @@
/* Guard against exceeding limits of the address space. */
address &= PAGE_MASK;
- if (address >= TASK_SIZE)
+ if (address >= (TASK_SIZE & PAGE_MASK))
return -ENOMEM;
address += PAGE_SIZE;
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 2efa9c9..3a22b14 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -37,6 +37,7 @@
#include <linux/ratelimit.h>
#include <linux/kthread.h>
#include <linux/init.h>
+#include <linux/show_mem_notifier.h>
#include <asm/tlb.h>
#include "internal.h"
@@ -416,8 +417,11 @@
dump_stack();
if (oc->memcg)
mem_cgroup_print_oom_info(oc->memcg, p);
- else
+ else {
show_mem(SHOW_MEM_FILTER_NODES);
+ show_mem_call_notifiers();
+ }
+
if (sysctl_oom_dump_tasks)
dump_tasks(oc->memcg, oc->nodemask);
}
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index bdd2bea..44085b2 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -64,6 +64,7 @@
#include <linux/page_owner.h>
#include <linux/kthread.h>
#include <linux/memcontrol.h>
+#include <linux/show_mem_notifier.h>
#include <asm/sections.h>
#include <asm/tlbflush.h>
@@ -3130,8 +3131,10 @@
pr_cont(", mode:%#x(%pGg)\n", gfp_mask, &gfp_mask);
dump_stack();
- if (!should_suppress_show_mem())
+ if (!should_suppress_show_mem()) {
show_mem(filter);
+ show_mem_call_notifiers();
+ }
}
static inline struct page *
diff --git a/mm/page_owner.c b/mm/page_owner.c
index d2db436..65e24fb 100644
--- a/mm/page_owner.c
+++ b/mm/page_owner.c
@@ -285,7 +285,11 @@
continue;
if (PageBuddy(page)) {
- pfn += (1UL << page_order(page)) - 1;
+ unsigned long freepage_order;
+
+ freepage_order = page_order_unsafe(page);
+ if (freepage_order < MAX_ORDER)
+ pfn += (1UL << freepage_order) - 1;
continue;
}
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index ad182e6..ed89128 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -426,7 +426,7 @@
BUG_ON(offset_in_page(size));
BUG_ON(!is_power_of_2(align));
- might_sleep_if(gfpflags_allow_blocking(gfp_mask));
+ might_sleep();
va = kmalloc_node(sizeof(struct vmap_area),
gfp_mask & GFP_RECLAIM_MASK, node);
@@ -662,6 +662,13 @@
static atomic_t vmap_lazy_nr = ATOMIC_INIT(0);
+/*
+ * Serialize vmap purging. There is no actual criticial section protected
+ * by this look, but we want to avoid concurrent calls for performance
+ * reasons and to make the pcpu_get_vm_areas more deterministic.
+ */
+static DEFINE_MUTEX(vmap_purge_lock);
+
/* for per-CPU blocks */
static void purge_fragmented_blocks_allcpus(void);
@@ -676,59 +683,40 @@
/*
* Purges all lazily-freed vmap areas.
- *
- * If sync is 0 then don't purge if there is already a purge in progress.
- * If force_flush is 1, then flush kernel TLBs between *start and *end even
- * if we found no lazy vmap areas to unmap (callers can use this to optimise
- * their own TLB flushing).
- * Returns with *start = min(*start, lowest purged address)
- * *end = max(*end, highest purged address)
*/
-static void __purge_vmap_area_lazy(unsigned long *start, unsigned long *end,
- int sync, int force_flush)
+static bool __purge_vmap_area_lazy(unsigned long start, unsigned long end)
{
- static DEFINE_SPINLOCK(purge_lock);
struct llist_node *valist;
struct vmap_area *va;
struct vmap_area *n_va;
- int nr = 0;
+ bool do_free = false;
- /*
- * If sync is 0 but force_flush is 1, we'll go sync anyway but callers
- * should not expect such behaviour. This just simplifies locking for
- * the case that isn't actually used at the moment anyway.
- */
- if (!sync && !force_flush) {
- if (!spin_trylock(&purge_lock))
- return;
- } else
- spin_lock(&purge_lock);
-
- if (sync)
- purge_fragmented_blocks_allcpus();
+ lockdep_assert_held(&vmap_purge_lock);
valist = llist_del_all(&vmap_purge_list);
llist_for_each_entry(va, valist, purge_list) {
- if (va->va_start < *start)
- *start = va->va_start;
- if (va->va_end > *end)
- *end = va->va_end;
- nr += (va->va_end - va->va_start) >> PAGE_SHIFT;
+ if (va->va_start < start)
+ start = va->va_start;
+ if (va->va_end > end)
+ end = va->va_end;
+ do_free = true;
}
- if (nr)
+ if (!do_free)
+ return false;
+
+ flush_tlb_kernel_range(start, end);
+
+ spin_lock(&vmap_area_lock);
+ llist_for_each_entry_safe(va, n_va, valist, purge_list) {
+ int nr = (va->va_end - va->va_start) >> PAGE_SHIFT;
+
+ __free_vmap_area(va);
atomic_sub(nr, &vmap_lazy_nr);
-
- if (nr || force_flush)
- flush_tlb_kernel_range(*start, *end);
-
- if (nr) {
- spin_lock(&vmap_area_lock);
- llist_for_each_entry_safe(va, n_va, valist, purge_list)
- __free_vmap_area(va);
- spin_unlock(&vmap_area_lock);
+ cond_resched_lock(&vmap_area_lock);
}
- spin_unlock(&purge_lock);
+ spin_unlock(&vmap_area_lock);
+ return true;
}
/*
@@ -737,9 +725,10 @@
*/
static void try_purge_vmap_area_lazy(void)
{
- unsigned long start = ULONG_MAX, end = 0;
-
- __purge_vmap_area_lazy(&start, &end, 0, 0);
+ if (mutex_trylock(&vmap_purge_lock)) {
+ __purge_vmap_area_lazy(ULONG_MAX, 0);
+ mutex_unlock(&vmap_purge_lock);
+ }
}
/*
@@ -747,9 +736,10 @@
*/
static void purge_vmap_area_lazy(void)
{
- unsigned long start = ULONG_MAX, end = 0;
-
- __purge_vmap_area_lazy(&start, &end, 1, 0);
+ mutex_lock(&vmap_purge_lock);
+ purge_fragmented_blocks_allcpus();
+ __purge_vmap_area_lazy(ULONG_MAX, 0);
+ mutex_unlock(&vmap_purge_lock);
}
/*
@@ -772,22 +762,13 @@
}
/*
- * Free and unmap a vmap area, caller ensuring flush_cache_vunmap had been
- * called for the correct range previously.
- */
-static void free_unmap_vmap_area_noflush(struct vmap_area *va)
-{
- unmap_vmap_area(va);
- free_vmap_area_noflush(va);
-}
-
-/*
* Free and unmap a vmap area
*/
static void free_unmap_vmap_area(struct vmap_area *va)
{
flush_cache_vunmap(va->va_start, va->va_end);
- free_unmap_vmap_area_noflush(va);
+ unmap_vmap_area(va);
+ free_vmap_area_noflush(va);
}
static struct vmap_area *find_vmap_area(unsigned long addr)
@@ -801,16 +782,6 @@
return va;
}
-static void free_unmap_vmap_area_addr(unsigned long addr)
-{
- struct vmap_area *va;
-
- va = find_vmap_area(addr);
- BUG_ON(!va);
- free_unmap_vmap_area(va);
-}
-
-
/*** Per cpu kva allocator ***/
/*
@@ -1131,6 +1102,8 @@
if (unlikely(!vmap_initialized))
return;
+ might_sleep();
+
for_each_possible_cpu(cpu) {
struct vmap_block_queue *vbq = &per_cpu(vmap_block_queue, cpu);
struct vmap_block *vb;
@@ -1155,7 +1128,11 @@
rcu_read_unlock();
}
- __purge_vmap_area_lazy(&start, &end, 1, flush);
+ mutex_lock(&vmap_purge_lock);
+ purge_fragmented_blocks_allcpus();
+ if (!__purge_vmap_area_lazy(start, end) && flush)
+ flush_tlb_kernel_range(start, end);
+ mutex_unlock(&vmap_purge_lock);
}
EXPORT_SYMBOL_GPL(vm_unmap_aliases);
@@ -1168,7 +1145,9 @@
{
unsigned long size = (unsigned long)count << PAGE_SHIFT;
unsigned long addr = (unsigned long)mem;
+ struct vmap_area *va;
+ might_sleep();
BUG_ON(!addr);
BUG_ON(addr < VMALLOC_START);
BUG_ON(addr > VMALLOC_END);
@@ -1177,10 +1156,14 @@
debug_check_no_locks_freed(mem, size);
vmap_debug_free_range(addr, addr+size);
- if (likely(count <= VMAP_MAX_ALLOC))
+ if (likely(count <= VMAP_MAX_ALLOC)) {
vb_free(mem, size);
- else
- free_unmap_vmap_area_addr(addr);
+ return;
+ }
+
+ va = find_vmap_area(addr);
+ BUG_ON(!va);
+ free_unmap_vmap_area(va);
}
EXPORT_SYMBOL(vm_unmap_ram);
@@ -1554,6 +1537,8 @@
{
struct vmap_area *va;
+ might_sleep();
+
va = find_vmap_area((unsigned long)addr);
if (va && va->flags & VM_VM_AREA) {
struct vm_struct *vm = va->vm;
@@ -1609,7 +1594,39 @@
kfree(area);
return;
}
-
+
+static inline void __vfree_deferred(const void *addr)
+{
+ /*
+ * Use raw_cpu_ptr() because this can be called from preemptible
+ * context. Preemption is absolutely fine here, because the llist_add()
+ * implementation is lockless, so it works even if we are adding to
+ * nother cpu's list. schedule_work() should be fine with this too.
+ */
+ struct vfree_deferred *p = raw_cpu_ptr(&vfree_deferred);
+
+ if (llist_add((struct llist_node *)addr, &p->list))
+ schedule_work(&p->wq);
+}
+
+/**
+ * vfree_atomic - release memory allocated by vmalloc()
+ * @addr: memory base address
+ *
+ * This one is just like vfree() but can be called in any atomic context
+ * except NMIs.
+ */
+void vfree_atomic(const void *addr)
+{
+ BUG_ON(in_nmi());
+
+ kmemleak_free(addr);
+
+ if (!addr)
+ return;
+ __vfree_deferred(addr);
+}
+
/**
* vfree - release memory allocated by vmalloc()
* @addr: memory base address
@@ -1632,11 +1649,9 @@
if (!addr)
return;
- if (unlikely(in_interrupt())) {
- struct vfree_deferred *p = this_cpu_ptr(&vfree_deferred);
- if (llist_add((struct llist_node *)addr, &p->list))
- schedule_work(&p->wq);
- } else
+ if (unlikely(in_interrupt()))
+ __vfree_deferred(addr);
+ else
__vunmap(addr, 1);
}
EXPORT_SYMBOL(vfree);
diff --git a/mm/vmstat.c b/mm/vmstat.c
index 42098b4..513c37a 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -1122,6 +1122,7 @@
/* Walk all the zones in a node and print using a callback */
static void walk_zones_in_node(struct seq_file *m, pg_data_t *pgdat,
+ bool nolock,
void (*print)(struct seq_file *m, pg_data_t *, struct zone *))
{
struct zone *zone;
@@ -1132,9 +1133,11 @@
if (!populated_zone(zone))
continue;
- spin_lock_irqsave(&zone->lock, flags);
+ if (!nolock)
+ spin_lock_irqsave(&zone->lock, flags);
print(m, pgdat, zone);
- spin_unlock_irqrestore(&zone->lock, flags);
+ if (!nolock)
+ spin_unlock_irqrestore(&zone->lock, flags);
}
}
#endif
@@ -1157,7 +1160,7 @@
static int frag_show(struct seq_file *m, void *arg)
{
pg_data_t *pgdat = (pg_data_t *)arg;
- walk_zones_in_node(m, pgdat, frag_show_print);
+ walk_zones_in_node(m, pgdat, false, frag_show_print);
return 0;
}
@@ -1198,7 +1201,7 @@
seq_printf(m, "%6d ", order);
seq_putc(m, '\n');
- walk_zones_in_node(m, pgdat, pagetypeinfo_showfree_print);
+ walk_zones_in_node(m, pgdat, false, pagetypeinfo_showfree_print);
return 0;
}
@@ -1250,7 +1253,8 @@
for (mtype = 0; mtype < MIGRATE_TYPES; mtype++)
seq_printf(m, "%12s ", migratetype_names[mtype]);
seq_putc(m, '\n');
- walk_zones_in_node(m, pgdat, pagetypeinfo_showblockcount_print);
+ walk_zones_in_node(m, pgdat, false,
+ pagetypeinfo_showblockcount_print);
return 0;
}
@@ -1276,7 +1280,8 @@
seq_printf(m, "%12s ", migratetype_names[mtype]);
seq_putc(m, '\n');
- walk_zones_in_node(m, pgdat, pagetypeinfo_showmixedcount_print);
+ walk_zones_in_node(m, pgdat, true,
+ pagetypeinfo_showmixedcount_print);
#endif /* CONFIG_PAGE_OWNER */
}
@@ -1433,7 +1438,7 @@
static int zoneinfo_show(struct seq_file *m, void *arg)
{
pg_data_t *pgdat = (pg_data_t *)arg;
- walk_zones_in_node(m, pgdat, zoneinfo_show_print);
+ walk_zones_in_node(m, pgdat, false, zoneinfo_show_print);
return 0;
}
@@ -1862,7 +1867,7 @@
if (!node_state(pgdat->node_id, N_MEMORY))
return 0;
- walk_zones_in_node(m, pgdat, unusable_show_print);
+ walk_zones_in_node(m, pgdat, false, unusable_show_print);
return 0;
}
@@ -1914,7 +1919,7 @@
{
pg_data_t *pgdat = (pg_data_t *)arg;
- walk_zones_in_node(m, pgdat, extfrag_show_print);
+ walk_zones_in_node(m, pgdat, false, extfrag_show_print);
return 0;
}
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 43faf2a..658c900 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -23,6 +23,7 @@
#include <linux/debugfs.h>
#include <linux/scatterlist.h>
#include <linux/crypto.h>
+#include <crypto/algapi.h>
#include <crypto/b128ops.h>
#include <crypto/hash.h>
@@ -506,7 +507,7 @@
if (err)
return false;
- return !memcmp(bdaddr->b, hash, 3);
+ return !crypto_memneq(bdaddr->b, hash, 3);
}
int smp_generate_rpa(struct hci_dev *hdev, const u8 irk[16], bdaddr_t *rpa)
@@ -559,7 +560,7 @@
/* This is unlikely, but we need to check that
* we didn't accidentially generate a debug key.
*/
- if (memcmp(smp->local_sk, debug_sk, 32))
+ if (crypto_memneq(smp->local_sk, debug_sk, 32))
break;
}
smp->debug_key = false;
@@ -973,7 +974,7 @@
if (ret)
return SMP_UNSPECIFIED;
- if (memcmp(smp->pcnf, confirm, sizeof(smp->pcnf)) != 0) {
+ if (crypto_memneq(smp->pcnf, confirm, sizeof(smp->pcnf))) {
BT_ERR("Pairing failed (confirmation values mismatch)");
return SMP_CONFIRM_FAILED;
}
@@ -1473,7 +1474,7 @@
smp->rrnd, r, cfm))
return SMP_UNSPECIFIED;
- if (memcmp(smp->pcnf, cfm, 16))
+ if (crypto_memneq(smp->pcnf, cfm, 16))
return SMP_CONFIRM_FAILED;
smp->passkey_round++;
@@ -1857,7 +1858,7 @@
/* This is unlikely, but we need to check that
* we didn't accidentially generate a debug key.
*/
- if (memcmp(smp->local_sk, debug_sk, 32))
+ if (crypto_memneq(smp->local_sk, debug_sk, 32))
break;
}
}
@@ -2122,7 +2123,7 @@
if (err)
return SMP_UNSPECIFIED;
- if (memcmp(smp->pcnf, cfm, 16))
+ if (crypto_memneq(smp->pcnf, cfm, 16))
return SMP_CONFIRM_FAILED;
} else {
smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(smp->prnd),
@@ -2603,7 +2604,7 @@
if (err)
return SMP_UNSPECIFIED;
- if (memcmp(cfm.confirm_val, smp->pcnf, 16))
+ if (crypto_memneq(cfm.confirm_val, smp->pcnf, 16))
return SMP_CONFIRM_FAILED;
}
@@ -2636,7 +2637,7 @@
else
hcon->pending_sec_level = BT_SECURITY_FIPS;
- if (!memcmp(debug_pk, smp->remote_pk, 64))
+ if (!crypto_memneq(debug_pk, smp->remote_pk, 64))
set_bit(SMP_FLAG_DEBUG_KEY, &smp->flags);
if (smp->method == DSP_PASSKEY) {
@@ -2735,7 +2736,7 @@
if (err)
return SMP_UNSPECIFIED;
- if (memcmp(check->e, e, 16))
+ if (crypto_memneq(check->e, e, 16))
return SMP_DHKEY_CHECK_FAILED;
if (!hcon->out) {
@@ -3446,7 +3447,7 @@
if (err)
return err;
- if (memcmp(res, exp, 3))
+ if (crypto_memneq(res, exp, 3))
return -EINVAL;
return 0;
@@ -3476,7 +3477,7 @@
if (err)
return err;
- if (memcmp(res, exp, 16))
+ if (crypto_memneq(res, exp, 16))
return -EINVAL;
return 0;
@@ -3501,7 +3502,7 @@
if (err)
return err;
- if (memcmp(res, exp, 16))
+ if (crypto_memneq(res, exp, 16))
return -EINVAL;
return 0;
@@ -3533,7 +3534,7 @@
if (err)
return err;
- if (memcmp(res, exp, 16))
+ if (crypto_memneq(res, exp, 16))
return -EINVAL;
return 0;
@@ -3567,10 +3568,10 @@
if (err)
return err;
- if (memcmp(mackey, exp_mackey, 16))
+ if (crypto_memneq(mackey, exp_mackey, 16))
return -EINVAL;
- if (memcmp(ltk, exp_ltk, 16))
+ if (crypto_memneq(ltk, exp_ltk, 16))
return -EINVAL;
return 0;
@@ -3603,7 +3604,7 @@
if (err)
return err;
- if (memcmp(res, exp, 16))
+ if (crypto_memneq(res, exp, 16))
return -EINVAL;
return 0;
@@ -3657,7 +3658,7 @@
if (err)
return err;
- if (memcmp(res, exp, 16))
+ if (crypto_memneq(res, exp, 16))
return -EINVAL;
return 0;
diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c
index 7dbc80d..6406010e 100644
--- a/net/bridge/br_mdb.c
+++ b/net/bridge/br_mdb.c
@@ -323,7 +323,8 @@
__mdb_entry_to_br_ip(entry, &complete_info->ip);
mdb.obj.complete_priv = complete_info;
mdb.obj.complete = br_mdb_complete;
- switchdev_port_obj_add(port_dev, &mdb.obj);
+ if (switchdev_port_obj_add(port_dev, &mdb.obj))
+ kfree(complete_info);
}
} else if (port_dev && type == RTM_DELMDB) {
switchdev_port_obj_del(port_dev, &mdb.obj);
diff --git a/net/core/dev.c b/net/core/dev.c
index 8c1860a..7e168d0 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4648,6 +4648,12 @@
}
EXPORT_SYMBOL(gro_find_complete_by_type);
+static void napi_skb_free_stolen_head(struct sk_buff *skb)
+{
+ skb_dst_drop(skb);
+ kmem_cache_free(skbuff_head_cache, skb);
+}
+
static gro_result_t napi_skb_finish(gro_result_t ret, struct sk_buff *skb)
{
switch (ret) {
@@ -4661,12 +4667,10 @@
break;
case GRO_MERGED_FREE:
- if (NAPI_GRO_CB(skb)->free == NAPI_GRO_FREE_STOLEN_HEAD) {
- skb_dst_drop(skb);
- kmem_cache_free(skbuff_head_cache, skb);
- } else {
+ if (NAPI_GRO_CB(skb)->free == NAPI_GRO_FREE_STOLEN_HEAD)
+ napi_skb_free_stolen_head(skb);
+ else
__kfree_skb(skb);
- }
break;
case GRO_HELD:
@@ -4736,10 +4740,16 @@
break;
case GRO_DROP:
- case GRO_MERGED_FREE:
napi_reuse_skb(napi, skb);
break;
+ case GRO_MERGED_FREE:
+ if (NAPI_GRO_CB(skb)->free == NAPI_GRO_FREE_STOLEN_HEAD)
+ napi_skb_free_stolen_head(skb);
+ else
+ napi_reuse_skb(napi, skb);
+ break;
+
case GRO_MERGED:
break;
}
@@ -7551,7 +7561,7 @@
{
#if BITS_PER_LONG == 64
BUILD_BUG_ON(sizeof(*stats64) < sizeof(*netdev_stats));
- memcpy(stats64, netdev_stats, sizeof(*stats64));
+ memcpy(stats64, netdev_stats, sizeof(*netdev_stats));
/* zero out counters that only exist in rtnl_link_stats64 */
memset((char *)stats64 + sizeof(*netdev_stats), 0,
sizeof(*stats64) - sizeof(*netdev_stats));
@@ -7593,9 +7603,9 @@
} else {
netdev_stats_to_stats64(storage, &dev->stats);
}
- storage->rx_dropped += atomic_long_read(&dev->rx_dropped);
- storage->tx_dropped += atomic_long_read(&dev->tx_dropped);
- storage->rx_nohandler += atomic_long_read(&dev->rx_nohandler);
+ storage->rx_dropped += (unsigned long)atomic_long_read(&dev->rx_dropped);
+ storage->tx_dropped += (unsigned long)atomic_long_read(&dev->tx_dropped);
+ storage->rx_nohandler += (unsigned long)atomic_long_read(&dev->rx_nohandler);
return storage;
}
EXPORT_SYMBOL(dev_get_stats);
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index f45f619..227c249 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -687,7 +687,7 @@
NEIGH_CACHE_STAT_INC(neigh->tbl, destroys);
if (!neigh->dead) {
- pr_warn("Destroying alive neighbour %p\n", neigh);
+ pr_warn("Destroying alive neighbour %pK\n", neigh);
dump_stack();
return;
}
diff --git a/net/ipc_router/ipc_router_core.c b/net/ipc_router/ipc_router_core.c
index 7c8af29f..a28b1af 100644
--- a/net/ipc_router/ipc_router_core.c
+++ b/net/ipc_router/ipc_router_core.c
@@ -363,6 +363,8 @@
svc_id = rport_ptr->server->name.service;
svc_ins = rport_ptr->server->name.instance;
port_type = CLIENT_PORT;
+ port_ptr->last_served_svc_id =
+ rport_ptr->server->name.service;
} else if (port_ptr && (port_ptr->type == SERVER_PORT)) {
svc_id = port_ptr->port_name.service;
svc_ins = port_ptr->port_name.instance;
@@ -1330,8 +1332,9 @@
mutex_init(&port_ptr->port_rx_q_lock_lhc3);
init_waitqueue_head(&port_ptr->port_rx_wait_q);
snprintf(port_ptr->rx_ws_name, MAX_WS_NAME_SZ,
- "ipc%08x_%s",
+ "ipc%08x_%d_%s",
port_ptr->this_port.port_id,
+ task_pid_nr(current),
current->comm);
port_ptr->port_rx_ws = wakeup_source_register(port_ptr->rx_ws_name);
if (!port_ptr->port_rx_ws) {
@@ -3847,15 +3850,18 @@
int j;
struct msm_ipc_port *port_ptr;
- seq_printf(s, "%-11s|%-11s|\n", "Node_id", "Port_id");
+ seq_printf(s, "%-11s|%-11s|%-32s|%-11s|\n",
+ "Node_id", "Port_id", "Wakelock", "Last SVCID");
seq_puts(s, "------------------------------------------------------------\n");
down_read(&local_ports_lock_lhc2);
for (j = 0; j < LP_HASH_SIZE; j++) {
list_for_each_entry(port_ptr, &local_ports[j], list) {
mutex_lock(&port_ptr->port_lock_lhc3);
- seq_printf(s, "0x%08x |0x%08x |\n",
+ seq_printf(s, "0x%08x |0x%08x |%-32s|0x%08x |\n",
port_ptr->this_port.node_id,
- port_ptr->this_port.port_id);
+ port_ptr->this_port.port_id,
+ port_ptr->rx_ws_name,
+ port_ptr->last_served_svc_id);
mutex_unlock(&port_ptr->port_lock_lhc3);
}
}
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index c27382f..7c90130 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2309,6 +2309,8 @@
tcp_init_send_head(sk);
memset(&tp->rx_opt, 0, sizeof(tp->rx_opt));
__sk_dst_reset(sk);
+ dst_release(sk->sk_rx_dst);
+ sk->sk_rx_dst = NULL;
tcp_saved_syn_free(tp);
WARN_ON(inet->inet_num && !icsk->icsk_bind_hash);
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index f24b9f4..fe5305a 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -1879,15 +1879,7 @@
if (dad_failed)
ifp->flags |= IFA_F_DADFAILED;
- if (ifp->flags&IFA_F_PERMANENT) {
- spin_lock_bh(&ifp->lock);
- addrconf_del_dad_work(ifp);
- ifp->flags |= IFA_F_TENTATIVE;
- spin_unlock_bh(&ifp->lock);
- if (dad_failed)
- ipv6_ifa_notify(0, ifp);
- in6_ifa_put(ifp);
- } else if (ifp->flags&IFA_F_TEMPORARY) {
+ if (ifp->flags&IFA_F_TEMPORARY) {
struct inet6_ifaddr *ifpub;
spin_lock_bh(&ifp->lock);
ifpub = ifp->ifpub;
@@ -1900,6 +1892,14 @@
spin_unlock_bh(&ifp->lock);
}
ipv6_del_addr(ifp);
+ } else if (ifp->flags&IFA_F_PERMANENT || !dad_failed) {
+ spin_lock_bh(&ifp->lock);
+ addrconf_del_dad_work(ifp);
+ ifp->flags |= IFA_F_TENTATIVE;
+ spin_unlock_bh(&ifp->lock);
+ if (dad_failed)
+ ipv6_ifa_notify(0, ifp);
+ in6_ifa_put(ifp);
} else {
ipv6_del_addr(ifp);
}
@@ -3356,6 +3356,7 @@
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
struct netdev_notifier_changeupper_info *info;
struct inet6_dev *idev = __in6_dev_get(dev);
+ struct net *net = dev_net(dev);
int run_pending = 0;
int err;
@@ -3371,7 +3372,7 @@
case NETDEV_CHANGEMTU:
/* if MTU under IPV6_MIN_MTU stop IPv6 on this interface. */
if (dev->mtu < IPV6_MIN_MTU) {
- addrconf_ifdown(dev, 1);
+ addrconf_ifdown(dev, dev != net->loopback_dev);
break;
}
@@ -3487,7 +3488,7 @@
* IPV6_MIN_MTU stop IPv6 on this interface.
*/
if (dev->mtu < IPV6_MIN_MTU)
- addrconf_ifdown(dev, 1);
+ addrconf_ifdown(dev, dev != net->loopback_dev);
}
break;
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 636d4d8..4345ee3 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -771,10 +771,7 @@
goto next_iter;
}
- if (iter->dst.dev == rt->dst.dev &&
- iter->rt6i_idev == rt->rt6i_idev &&
- ipv6_addr_equal(&iter->rt6i_gateway,
- &rt->rt6i_gateway)) {
+ if (rt6_duplicate_nexthop(iter, rt)) {
if (rt->rt6i_nsiblings)
rt->rt6i_nsiblings = 0;
if (!(iter->rt6i_flags & RTF_EXPIRES))
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 0b21d61..d8123f6 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -2922,17 +2922,11 @@
struct rt6_info *rt, struct fib6_config *r_cfg)
{
struct rt6_nh *nh;
- struct rt6_info *rtnh;
int err = -EEXIST;
list_for_each_entry(nh, rt6_nh_list, next) {
/* check if rt6_info already exists */
- rtnh = nh->rt6_info;
-
- if (rtnh->dst.dev == rt->dst.dev &&
- rtnh->rt6i_idev == rt->rt6i_idev &&
- ipv6_addr_equal(&rtnh->rt6i_gateway,
- &rt->rt6i_gateway))
+ if (rt6_duplicate_nexthop(nh->rt6_info, rt))
return err;
}
diff --git a/net/key/af_key.c b/net/key/af_key.c
index e67c28e..d8d95b6 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -65,6 +65,10 @@
} dump;
};
+static int parse_sockaddr_pair(struct sockaddr *sa, int ext_len,
+ xfrm_address_t *saddr, xfrm_address_t *daddr,
+ u16 *family);
+
static inline struct pfkey_sock *pfkey_sk(struct sock *sk)
{
return (struct pfkey_sock *)sk;
@@ -1922,19 +1926,14 @@
/* addresses present only in tunnel mode */
if (t->mode == XFRM_MODE_TUNNEL) {
- u8 *sa = (u8 *) (rq + 1);
- int family, socklen;
+ int err;
- family = pfkey_sockaddr_extract((struct sockaddr *)sa,
- &t->saddr);
- if (!family)
- return -EINVAL;
-
- socklen = pfkey_sockaddr_len(family);
- if (pfkey_sockaddr_extract((struct sockaddr *)(sa + socklen),
- &t->id.daddr) != family)
- return -EINVAL;
- t->encap_family = family;
+ err = parse_sockaddr_pair(
+ (struct sockaddr *)(rq + 1),
+ rq->sadb_x_ipsecrequest_len - sizeof(*rq),
+ &t->saddr, &t->id.daddr, &t->encap_family);
+ if (err)
+ return err;
} else
t->encap_family = xp->family;
@@ -1954,7 +1953,11 @@
if (pol->sadb_x_policy_len * 8 < sizeof(struct sadb_x_policy))
return -EINVAL;
- while (len >= sizeof(struct sadb_x_ipsecrequest)) {
+ while (len >= sizeof(*rq)) {
+ if (len < rq->sadb_x_ipsecrequest_len ||
+ rq->sadb_x_ipsecrequest_len < sizeof(*rq))
+ return -EINVAL;
+
if ((err = parse_ipsecrequest(xp, rq)) < 0)
return err;
len -= rq->sadb_x_ipsecrequest_len;
@@ -2417,7 +2420,6 @@
return err;
}
-#ifdef CONFIG_NET_KEY_MIGRATE
static int pfkey_sockaddr_pair_size(sa_family_t family)
{
return PFKEY_ALIGN8(pfkey_sockaddr_len(family) * 2);
@@ -2429,7 +2431,7 @@
{
int af, socklen;
- if (ext_len < pfkey_sockaddr_pair_size(sa->sa_family))
+ if (ext_len < 2 || ext_len < pfkey_sockaddr_pair_size(sa->sa_family))
return -EINVAL;
af = pfkey_sockaddr_extract(sa, saddr);
@@ -2445,6 +2447,7 @@
return 0;
}
+#ifdef CONFIG_NET_KEY_MIGRATE
static int ipsecrequests_to_migrate(struct sadb_x_ipsecrequest *rq1, int len,
struct xfrm_migrate *m)
{
@@ -2452,13 +2455,14 @@
struct sadb_x_ipsecrequest *rq2;
int mode;
- if (len <= sizeof(struct sadb_x_ipsecrequest) ||
- len < rq1->sadb_x_ipsecrequest_len)
+ if (len < sizeof(*rq1) ||
+ len < rq1->sadb_x_ipsecrequest_len ||
+ rq1->sadb_x_ipsecrequest_len < sizeof(*rq1))
return -EINVAL;
/* old endoints */
err = parse_sockaddr_pair((struct sockaddr *)(rq1 + 1),
- rq1->sadb_x_ipsecrequest_len,
+ rq1->sadb_x_ipsecrequest_len - sizeof(*rq1),
&m->old_saddr, &m->old_daddr,
&m->old_family);
if (err)
@@ -2467,13 +2471,14 @@
rq2 = (struct sadb_x_ipsecrequest *)((u8 *)rq1 + rq1->sadb_x_ipsecrequest_len);
len -= rq1->sadb_x_ipsecrequest_len;
- if (len <= sizeof(struct sadb_x_ipsecrequest) ||
- len < rq2->sadb_x_ipsecrequest_len)
+ if (len <= sizeof(*rq2) ||
+ len < rq2->sadb_x_ipsecrequest_len ||
+ rq2->sadb_x_ipsecrequest_len < sizeof(*rq2))
return -EINVAL;
/* new endpoints */
err = parse_sockaddr_pair((struct sockaddr *)(rq2 + 1),
- rq2->sadb_x_ipsecrequest_len,
+ rq2->sadb_x_ipsecrequest_len - sizeof(*rq2),
&m->new_saddr, &m->new_daddr,
&m->new_family);
if (err)
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 1118c61..b2c706c 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -4486,20 +4486,20 @@
return -EOPNOTSUPP;
}
- auth_data = kzalloc(sizeof(*auth_data) + req->sae_data_len +
+ auth_data = kzalloc(sizeof(*auth_data) + req->auth_data_len +
req->ie_len, GFP_KERNEL);
if (!auth_data)
return -ENOMEM;
auth_data->bss = req->bss;
- if (req->sae_data_len >= 4) {
- __le16 *pos = (__le16 *) req->sae_data;
+ if (req->auth_data_len >= 4) {
+ __le16 *pos = (__le16 *)req->auth_data;
auth_data->sae_trans = le16_to_cpu(pos[0]);
auth_data->sae_status = le16_to_cpu(pos[1]);
- memcpy(auth_data->data, req->sae_data + 4,
- req->sae_data_len - 4);
- auth_data->data_len += req->sae_data_len - 4;
+ memcpy(auth_data->data, req->auth_data + 4,
+ req->auth_data_len - 4);
+ auth_data->data_len += req->auth_data_len - 4;
}
if (req->ie && req->ie_len) {
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
index 2c1b498..e34d3f6 100644
--- a/net/netfilter/ipvs/ip_vs_core.c
+++ b/net/netfilter/ipvs/ip_vs_core.c
@@ -849,10 +849,8 @@
{
unsigned int verdict = NF_DROP;
- if (IP_VS_FWD_METHOD(cp) != 0) {
- pr_err("shouldn't reach here, because the box is on the "
- "half connection in the tun/dr module.\n");
- }
+ if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ)
+ goto ignore_cp;
/* Ensure the checksum is correct */
if (!skb_csum_unnecessary(skb) && ip_vs_checksum_complete(skb, ihl)) {
@@ -886,6 +884,8 @@
ip_vs_notrack(skb);
else
ip_vs_update_conntrack(skb, cp, 0);
+
+ignore_cp:
verdict = NF_ACCEPT;
out:
@@ -1385,8 +1385,11 @@
*/
cp = pp->conn_out_get(ipvs, af, skb, &iph);
- if (likely(cp))
+ if (likely(cp)) {
+ if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ)
+ goto ignore_cp;
return handle_response(af, skb, pd, cp, &iph, hooknum);
+ }
/* Check for real-server-started requests */
if (atomic_read(&ipvs->conn_out_counter)) {
@@ -1444,9 +1447,15 @@
}
}
}
+
+out:
IP_VS_DBG_PKT(12, af, pp, skb, iph.off,
"ip_vs_out: packet continues traversal as normal");
return NF_ACCEPT;
+
+ignore_cp:
+ __ip_vs_conn_put(cp);
+ goto out;
}
/*
diff --git a/net/netfilter/xt_quota2.c b/net/netfilter/xt_quota2.c
index 834594a..bbf0a3a 100644
--- a/net/netfilter/xt_quota2.c
+++ b/net/netfilter/xt_quota2.c
@@ -16,6 +16,7 @@
#include <linux/proc_fs.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
+#include <linux/workqueue.h>
#include <asm/atomic.h>
#include <net/netlink.h>
@@ -43,6 +44,8 @@
unsigned char payload[0];
} ulog_packet_msg_t;
#endif
+#define QUOTA2_SYSFS_WORK_MAX_SIZE 64
+#define QUOTA2_SYSFS_NUM_ENVP 3
/**
* @lock: lock to protect quota writers from each other
@@ -54,17 +57,16 @@
atomic_t ref;
char name[sizeof(((struct xt_quota_mtinfo2 *)NULL)->name)];
struct proc_dir_entry *procfs_entry;
+ char last_iface[QUOTA2_SYSFS_WORK_MAX_SIZE];
+ char last_prefix[QUOTA2_SYSFS_WORK_MAX_SIZE];
+ struct work_struct work;
};
-#ifdef CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG
-/* Harald's favorite number +1 :D From ipt_ULOG.C */
-static int qlog_nl_event = 112;
-module_param_named(event_num, qlog_nl_event, uint, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(event_num,
- "Event number for NETLINK_NFLOG message. 0 disables log."
- "111 is what ipt_ULOG uses.");
-static struct sock *nflognl;
-#endif
+#define to_quota_counter(x) container_of(x, struct xt_quota_counter, work)
+
+static struct class *quota_class;
+static struct device *quota_device;
+static struct kobject *quota_kobj;
static LIST_HEAD(counter_list);
static DEFINE_SPINLOCK(counter_list_lock);
@@ -75,68 +77,39 @@
static kgid_t quota_list_gid = KGIDT_INIT(0);
module_param_named(perms, quota_list_perms, uint, S_IRUGO | S_IWUSR);
-#ifdef CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG
-static void quota2_log(unsigned int hooknum,
- const struct sk_buff *skb,
- const struct net_device *in,
+static void quota2_work(struct work_struct *work)
+{
+ char alert_msg[QUOTA2_SYSFS_WORK_MAX_SIZE];
+ char iface_name[QUOTA2_SYSFS_WORK_MAX_SIZE];
+ char *envp[QUOTA2_SYSFS_NUM_ENVP] = {alert_msg, iface_name, NULL};
+ struct xt_quota_counter *counter = to_quota_counter(work);
+
+ snprintf(alert_msg, sizeof(alert_msg), "ALERT_NAME=%s", counter->name);
+ snprintf(iface_name, sizeof(iface_name), "INTERFACE=%s",
+ counter->last_iface);
+
+ kobject_uevent_env(quota_kobj, KOBJ_CHANGE, envp);
+}
+
+static void quota2_log(const struct net_device *in,
const struct net_device *out,
+ struct xt_quota_counter *q,
const char *prefix)
{
- ulog_packet_msg_t *pm;
- struct sk_buff *log_skb;
- size_t size;
- struct nlmsghdr *nlh;
-
- if (!qlog_nl_event)
+ if (!prefix)
return;
- size = NLMSG_SPACE(sizeof(*pm));
- size = max(size, (size_t)NLMSG_GOODSIZE);
- log_skb = alloc_skb(size, GFP_ATOMIC);
- if (!log_skb) {
- pr_err("xt_quota2: cannot alloc skb for logging\n");
- return;
- }
+ strlcpy(q->last_prefix, prefix, QUOTA2_SYSFS_WORK_MAX_SIZE);
- nlh = nlmsg_put(log_skb, /*pid*/0, /*seq*/0, qlog_nl_event,
- sizeof(*pm), 0);
- if (!nlh) {
- pr_err("xt_quota2: nlmsg_put failed\n");
- kfree_skb(log_skb);
- return;
- }
- pm = nlmsg_data(nlh);
- if (skb->tstamp.tv64 == 0)
- __net_timestamp((struct sk_buff *)skb);
- pm->data_len = 0;
- pm->hook = hooknum;
- if (prefix != NULL)
- strlcpy(pm->prefix, prefix, sizeof(pm->prefix));
- else
- *(pm->prefix) = '\0';
if (in)
- strlcpy(pm->indev_name, in->name, sizeof(pm->indev_name));
+ strlcpy(q->last_iface, in->name, QUOTA2_SYSFS_WORK_MAX_SIZE);
+ else if (out)
+ strlcpy(q->last_iface, out->name, QUOTA2_SYSFS_WORK_MAX_SIZE);
else
- pm->indev_name[0] = '\0';
+ strlcpy(q->last_iface, "UNKNOWN", QUOTA2_SYSFS_WORK_MAX_SIZE);
- if (out)
- strlcpy(pm->outdev_name, out->name, sizeof(pm->outdev_name));
- else
- pm->outdev_name[0] = '\0';
-
- NETLINK_CB(log_skb).dst_group = 1;
- pr_debug("throwing 1 packets to netlink group 1\n");
- netlink_broadcast(nflognl, log_skb, 0, 1, GFP_ATOMIC);
+ schedule_work(&q->work);
}
-#else
-static void quota2_log(unsigned int hooknum,
- const struct sk_buff *skb,
- const struct net_device *in,
- const struct net_device *out,
- const char *prefix)
-{
-}
-#endif /* if+else CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG */
static ssize_t quota_proc_read(struct file *file, char __user *buf,
size_t size, loff_t *ppos)
@@ -193,6 +166,9 @@
INIT_LIST_HEAD(&e->list);
atomic_set(&e->ref, 1);
strlcpy(e->name, q->name, sizeof(e->name));
+ strlcpy(e->last_prefix, "UNSET", sizeof(e->last_prefix));
+ strlcpy(e->last_iface, "UNSET", sizeof(e->last_iface));
+ INIT_WORK(&e->work, quota2_work);
}
return e;
}
@@ -326,11 +302,7 @@
} else {
/* We are transitioning, log that fact. */
if (e->quota) {
- quota2_log(par->hooknum,
- skb,
- par->in,
- par->out,
- q->name);
+ quota2_log(par->in, par->out, e, q->name);
}
/* we do not allow even small packets from now on */
e->quota = 0;
@@ -368,11 +340,25 @@
int ret;
pr_debug("xt_quota2: init()");
-#ifdef CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG
- nflognl = netlink_kernel_create(&init_net, NETLINK_NFLOG, NULL);
- if (!nflognl)
- return -ENOMEM;
-#endif
+ quota_class = class_create(THIS_MODULE, "xt_quota2");
+ ret = PTR_ERR(quota_class);
+ if (IS_ERR(quota_class)) {
+ pr_err("xt_quota2: couldn't create class");
+ class_destroy(quota_class);
+ return ret;
+ }
+
+ quota_device = device_create(quota_class, NULL, MKDEV(0, 0), NULL,
+ "counters");
+ ret = PTR_ERR(quota_device);
+ if (IS_ERR(quota_device)) {
+ pr_err("xt_quota2: couldn't create device");
+ device_destroy(quota_class, MKDEV(0, 0));
+ class_destroy(quota_class);
+ return ret;
+ }
+
+ quota_kobj = "a_device->kobj;
proc_xt_quota = proc_mkdir("xt_quota", init_net.proc_net);
if (proc_xt_quota == NULL)
@@ -389,6 +375,8 @@
{
xt_unregister_matches(quota_mt2_reg, ARRAY_SIZE(quota_mt2_reg));
remove_proc_entry("xt_quota", init_net.proc_net);
+ device_destroy(quota_class, MKDEV(0, 0));
+ class_destroy(quota_class);
}
module_init(quota_mt2_init);
diff --git a/net/nfc/core.c b/net/nfc/core.c
index 122bb81..5cf33df 100644
--- a/net/nfc/core.c
+++ b/net/nfc/core.c
@@ -982,6 +982,8 @@
kfree(se);
}
+ ida_simple_remove(&nfc_index_ida, dev->idx);
+
kfree(dev);
}
@@ -1056,6 +1058,7 @@
int tx_headroom, int tx_tailroom)
{
struct nfc_dev *dev;
+ int rc;
if (!ops->start_poll || !ops->stop_poll || !ops->activate_target ||
!ops->deactivate_target || !ops->im_transceive)
@@ -1068,6 +1071,15 @@
if (!dev)
return NULL;
+ rc = ida_simple_get(&nfc_index_ida, 0, 0, GFP_KERNEL);
+ if (rc < 0)
+ goto err_free_dev;
+ dev->idx = rc;
+
+ dev->dev.class = &nfc_class;
+ dev_set_name(&dev->dev, "nfc%d", dev->idx);
+ device_initialize(&dev->dev);
+
dev->ops = ops;
dev->supported_protocols = supported_protocols;
dev->tx_headroom = tx_headroom;
@@ -1090,6 +1102,11 @@
}
return dev;
+
+err_free_dev:
+ kfree(dev);
+
+ return ERR_PTR(rc);
}
EXPORT_SYMBOL(nfc_allocate_device);
@@ -1104,14 +1121,6 @@
pr_debug("dev_name=%s\n", dev_name(&dev->dev));
- dev->idx = ida_simple_get(&nfc_index_ida, 0, 0, GFP_KERNEL);
- if (dev->idx < 0)
- return dev->idx;
-
- dev->dev.class = &nfc_class;
- dev_set_name(&dev->dev, "nfc%d", dev->idx);
- device_initialize(&dev->dev);
-
mutex_lock(&nfc_devlist_mutex);
nfc_devlist_generation++;
rc = device_add(&dev->dev);
@@ -1149,12 +1158,10 @@
*/
void nfc_unregister_device(struct nfc_dev *dev)
{
- int rc, id;
+ int rc;
pr_debug("dev_name=%s\n", dev_name(&dev->dev));
- id = dev->idx;
-
if (dev->rfkill) {
rfkill_unregister(dev->rfkill);
rfkill_destroy(dev->rfkill);
@@ -1179,8 +1186,6 @@
nfc_devlist_generation++;
device_del(&dev->dev);
mutex_unlock(&nfc_devlist_mutex);
-
- ida_simple_remove(&nfc_index_ida, id);
}
EXPORT_SYMBOL(nfc_unregister_device);
diff --git a/net/nfc/llcp_sock.c b/net/nfc/llcp_sock.c
index b9edf5f..e31dea1 100644
--- a/net/nfc/llcp_sock.c
+++ b/net/nfc/llcp_sock.c
@@ -76,7 +76,8 @@
struct sockaddr_nfc_llcp llcp_addr;
int len, ret = 0;
- if (!addr || addr->sa_family != AF_NFC)
+ if (!addr || alen < offsetofend(struct sockaddr, sa_family) ||
+ addr->sa_family != AF_NFC)
return -EINVAL;
pr_debug("sk %p addr %p family %d\n", sk, addr, addr->sa_family);
@@ -150,7 +151,8 @@
struct sockaddr_nfc_llcp llcp_addr;
int len, ret = 0;
- if (!addr || addr->sa_family != AF_NFC)
+ if (!addr || alen < offsetofend(struct sockaddr, sa_family) ||
+ addr->sa_family != AF_NFC)
return -EINVAL;
pr_debug("sk %p addr %p family %d\n", sk, addr, addr->sa_family);
@@ -661,8 +663,7 @@
pr_debug("sock %p sk %p flags 0x%x\n", sock, sk, flags);
- if (!addr || len < sizeof(struct sockaddr_nfc) ||
- addr->sa_family != AF_NFC)
+ if (!addr || len < sizeof(*addr) || addr->sa_family != AF_NFC)
return -EINVAL;
if (addr->service_name_len == 0 && addr->dsap == 0)
diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c
index 61fff42..85a3d9e 100644
--- a/net/nfc/nci/core.c
+++ b/net/nfc/nci/core.c
@@ -1173,8 +1173,7 @@
return ndev;
free_nfc:
- kfree(ndev->nfc_dev);
-
+ nfc_free_device(ndev->nfc_dev);
free_nci:
kfree(ndev);
return NULL;
diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c
index ea023b3..102c681 100644
--- a/net/nfc/netlink.c
+++ b/net/nfc/netlink.c
@@ -910,7 +910,9 @@
u32 device_idx, target_idx, protocol;
int rc;
- if (!info->attrs[NFC_ATTR_DEVICE_INDEX])
+ if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
+ !info->attrs[NFC_ATTR_TARGET_INDEX] ||
+ !info->attrs[NFC_ATTR_PROTOCOLS])
return -EINVAL;
device_idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
diff --git a/net/rds/tcp_listen.c b/net/rds/tcp_listen.c
index e0b23fb..525b624 100644
--- a/net/rds/tcp_listen.c
+++ b/net/rds/tcp_listen.c
@@ -129,7 +129,7 @@
if (!sock) /* module unload or netns delete in progress */
return -ENETUNREACH;
- ret = sock_create_kern(sock_net(sock->sk), sock->sk->sk_family,
+ ret = sock_create_lite(sock->sk->sk_family,
sock->sk->sk_type, sock->sk->sk_protocol,
&new_sock);
if (ret)
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index c2225cc..daf6624 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -1008,6 +1008,9 @@
return sch;
}
+ /* ops->init() failed, we call ->destroy() like qdisc_create_dflt() */
+ if (ops->destroy)
+ ops->destroy(sch);
err_out3:
dev_put(dev);
kfree((char *) sch - sch->padded);
diff --git a/net/sched/sch_hhf.c b/net/sched/sch_hhf.c
index e3d0458..2fae8b5 100644
--- a/net/sched/sch_hhf.c
+++ b/net/sched/sch_hhf.c
@@ -627,7 +627,9 @@
q->hhf_arrays[i] = hhf_zalloc(HHF_ARRAYS_LEN *
sizeof(u32));
if (!q->hhf_arrays[i]) {
- hhf_destroy(sch);
+ /* Note: hhf_destroy() will be called
+ * by our caller.
+ */
return -ENOMEM;
}
}
@@ -638,7 +640,9 @@
q->hhf_valid_bits[i] = hhf_zalloc(HHF_ARRAYS_LEN /
BITS_PER_BYTE);
if (!q->hhf_valid_bits[i]) {
- hhf_destroy(sch);
+ /* Note: hhf_destroy() will be called
+ * by our caller.
+ */
return -ENOMEM;
}
}
diff --git a/net/sched/sch_mq.c b/net/sched/sch_mq.c
index 2bc8d7f..20b7f16 100644
--- a/net/sched/sch_mq.c
+++ b/net/sched/sch_mq.c
@@ -52,7 +52,7 @@
/* pre-allocate qdiscs, attachment can't fail */
priv->qdiscs = kcalloc(dev->num_tx_queues, sizeof(priv->qdiscs[0]),
GFP_KERNEL);
- if (priv->qdiscs == NULL)
+ if (!priv->qdiscs)
return -ENOMEM;
for (ntx = 0; ntx < dev->num_tx_queues; ntx++) {
@@ -60,18 +60,14 @@
qdisc = qdisc_create_dflt(dev_queue, get_default_qdisc_ops(dev, ntx),
TC_H_MAKE(TC_H_MAJ(sch->handle),
TC_H_MIN(ntx + 1)));
- if (qdisc == NULL)
- goto err;
+ if (!qdisc)
+ return -ENOMEM;
priv->qdiscs[ntx] = qdisc;
qdisc->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT;
}
sch->flags |= TCQ_F_MQROOT;
return 0;
-
-err:
- mq_destroy(sch);
- return -ENOMEM;
}
static void mq_attach(struct Qdisc *sch)
diff --git a/net/sched/sch_mqprio.c b/net/sched/sch_mqprio.c
index b5c502c..9226834 100644
--- a/net/sched/sch_mqprio.c
+++ b/net/sched/sch_mqprio.c
@@ -118,10 +118,8 @@
/* pre-allocate qdisc, attachment can't fail */
priv->qdiscs = kcalloc(dev->num_tx_queues, sizeof(priv->qdiscs[0]),
GFP_KERNEL);
- if (priv->qdiscs == NULL) {
- err = -ENOMEM;
- goto err;
- }
+ if (!priv->qdiscs)
+ return -ENOMEM;
for (i = 0; i < dev->num_tx_queues; i++) {
dev_queue = netdev_get_tx_queue(dev, i);
@@ -129,10 +127,9 @@
get_default_qdisc_ops(dev, i),
TC_H_MAKE(TC_H_MAJ(sch->handle),
TC_H_MIN(i + 1)));
- if (qdisc == NULL) {
- err = -ENOMEM;
- goto err;
- }
+ if (!qdisc)
+ return -ENOMEM;
+
priv->qdiscs[i] = qdisc;
qdisc->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT;
}
@@ -148,7 +145,7 @@
priv->hw_owned = 1;
err = dev->netdev_ops->ndo_setup_tc(dev, sch->handle, 0, &tc);
if (err)
- goto err;
+ return err;
} else {
netdev_set_num_tc(dev, qopt->num_tc);
for (i = 0; i < qopt->num_tc; i++)
@@ -162,10 +159,6 @@
sch->flags |= TCQ_F_MQROOT;
return 0;
-
-err:
- mqprio_destroy(sch);
- return err;
}
static void mqprio_attach(struct Qdisc *sch)
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index 7f195ed..bc5e995 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -742,9 +742,10 @@
q->ht = sfq_alloc(sizeof(q->ht[0]) * q->divisor);
q->slots = sfq_alloc(sizeof(q->slots[0]) * q->maxflows);
if (!q->ht || !q->slots) {
- sfq_destroy(sch);
+ /* Note: sfq_destroy() will be called by our caller */
return -ENOMEM;
}
+
for (i = 0; i < q->divisor; i++)
q->ht[i] = SFQ_EMPTY_SLOT;
diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c
index 90115ce..79aec90 100644
--- a/net/sunrpc/auth_gss/gss_krb5_crypto.c
+++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c
@@ -34,6 +34,7 @@
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
+#include <crypto/algapi.h>
#include <crypto/hash.h>
#include <crypto/skcipher.h>
#include <linux/err.h>
@@ -927,7 +928,7 @@
if (ret)
goto out_err;
- if (memcmp(pkt_hmac, our_hmac, kctx->gk5e->cksumlength) != 0) {
+ if (crypto_memneq(pkt_hmac, our_hmac, kctx->gk5e->cksumlength) != 0) {
ret = GSS_S_BAD_SIG;
goto out_err;
}
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 80890c0..cf7063a 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -220,15 +220,7 @@
enum cfg80211_event_type type;
union {
- struct {
- u8 bssid[ETH_ALEN];
- const u8 *req_ie;
- const u8 *resp_ie;
- size_t req_ie_len;
- size_t resp_ie_len;
- struct cfg80211_bss *bss;
- int status; /* -1 = failed; 0..65535 = status code */
- } cr;
+ struct cfg80211_connect_resp_params cr;
struct {
const u8 *req_ie;
const u8 *resp_ie;
@@ -346,7 +338,7 @@
const u8 *ssid, int ssid_len,
const u8 *ie, int ie_len,
const u8 *key, int key_len, int key_idx,
- const u8 *sae_data, int sae_data_len);
+ const u8 *auth_data, int auth_data_len);
int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
struct net_device *dev,
struct ieee80211_channel *chan,
@@ -384,11 +376,9 @@
struct cfg80211_connect_params *connect,
struct cfg80211_cached_keys *connkeys,
const u8 *prev_bssid);
-void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
- const u8 *req_ie, size_t req_ie_len,
- const u8 *resp_ie, size_t resp_ie_len,
- int status, bool wextev,
- struct cfg80211_bss *bss);
+void __cfg80211_connect_result(struct net_device *dev,
+ struct cfg80211_connect_resp_params *params,
+ bool wextev);
void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
size_t ie_len, u16 reason, bool from_ap);
int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
diff --git a/net/wireless/db.txt b/net/wireless/db.txt
index a2dff71..413deff 100644
--- a/net/wireless/db.txt
+++ b/net/wireless/db.txt
@@ -538,6 +538,12 @@
(5490 - 5730 @ 160), (24), DFS
(5735 - 5835 @ 80), (30)
+country GI: DFS-ETSI
+ (2402 - 2482 @ 40), (20)
+ (5170 - 5250 @ 80), (23), AUTO-BW
+ (5250 - 5330 @ 80), (23), DFS, AUTO-BW
+ (5490 - 5710 @ 160), (30), DFS
+
country GL: DFS-ETSI
(2402 - 2482 @ 40), (20)
(5170 - 5250 @ 80), (23), AUTO-BW
@@ -678,10 +684,6 @@
(5170 - 5330 @ 160), (23)
(5735 - 5835 @ 80), (30)
-country IR:
- (2402 - 2482 @ 40), (20)
- (5735 - 5835 @ 80), (30)
-
country IS: DFS-ETSI
(2402 - 2482 @ 40), (20)
(5170 - 5250 @ 80), (23), AUTO-BW
@@ -764,19 +766,12 @@
(2402 - 2482 @ 40), (20)
(5170 - 5250 @ 80), (20), AUTO-BW
(5250 - 5330 @ 80), (20), DFS, AUTO-BW
- (5490 - 5710 @ 160), (30), DFS
+ (5490 - 5730 @ 160), (30), DFS
(5735 - 5835 @ 80), (30)
# 60 GHz band channels 1-4,
# ref: http://www.law.go.kr/%ED%96%89%EC%A0%95%EA%B7%9C%EC%B9%99/%EB%AC%B4%EC%84%A0%EC%84%A4%EB%B9%84%EA%B7%9C%EC%B9%99
(57240 - 65880 @ 2160), (43)
-country KP: DFS-ETSI
- (2402 - 2482 @ 40), (20)
- (5170 - 5250 @ 80), (20)
- (5250 - 5330 @ 80), (20), DFS
- (5490 - 5630 @ 80), (30), DFS
- (5735 - 5815 @ 80), (30)
-
country KW: DFS-ETSI
(2402 - 2482 @ 40), (20)
(5170 - 5250 @ 80), (23), AUTO-BW
@@ -1022,7 +1017,7 @@
(2402 - 2482 @ 40), (20)
(5170 - 5250 @ 80), (23), AUTO-BW
(5250 - 5330 @ 80), (23), DFS, AUTO-BW
- (5490 - 5710 @ 160), (30), DFS
+ (5490 - 5730 @ 160), (30), DFS
(5735 - 5835 @ 80), (33)
country NG: DFS-ETSI
@@ -1338,9 +1333,6 @@
(5250 - 5330 @ 20), (23), DFS
(5735 - 5835 @ 20), (30)
-country SY:
- (2402 - 2482 @ 40), (20)
-
country TC: DFS-FCC
(2402 - 2482 @ 40), (20)
(5170 - 5250 @ 80), (24), AUTO-BW
@@ -1426,7 +1418,7 @@
country US: DFS-FCC
(2402 - 2472 @ 40), (30)
- (5170 - 5250 @ 80), (24), AUTO-BW
+ (5170 - 5250 @ 80), (30), AUTO-BW
(5250 - 5330 @ 80), (24), DFS, AUTO-BW
(5490 - 5730 @ 160), (24), DFS
(5735 - 5835 @ 80), (30)
@@ -1467,7 +1459,7 @@
(5490 - 5710 @ 160), (30), DFS
country VE: DFS-FCC
- (2402 - 2482 @ 40), (30)
+ (2402 - 2482 @ 40), (20)
(5170 - 5250 @ 80), (23), AUTO-BW
(5250 - 5330 @ 80), (23), DFS, AUTO-BW
(5735 - 5835 @ 80), (30)
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 76775a2..5499e9f 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -26,9 +26,16 @@
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
- u8 *ie = mgmt->u.assoc_resp.variable;
- int ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
- u16 status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
+ struct cfg80211_connect_resp_params cr;
+
+ memset(&cr, 0, sizeof(cr));
+ cr.status = (int)le16_to_cpu(mgmt->u.assoc_resp.status_code);
+ cr.bssid = mgmt->bssid;
+ cr.bss = bss;
+ cr.resp_ie = mgmt->u.assoc_resp.variable;
+ cr.resp_ie_len =
+ len - offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
+ cr.timeout_reason = NL80211_TIMEOUT_UNSPECIFIED;
trace_cfg80211_send_rx_assoc(dev, bss);
@@ -38,7 +45,7 @@
* and got a reject -- we only try again with an assoc
* frame instead of reassoc.
*/
- if (cfg80211_sme_rx_assoc_resp(wdev, status_code)) {
+ if (cfg80211_sme_rx_assoc_resp(wdev, cr.status)) {
cfg80211_unhold_bss(bss_from_pub(bss));
cfg80211_put_bss(wiphy, bss);
return;
@@ -46,9 +53,7 @@
nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL, uapsd_queues);
/* update current_bss etc., consumes the bss reference */
- __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs,
- status_code,
- status_code == WLAN_STATUS_SUCCESS, bss);
+ __cfg80211_connect_result(dev, &cr, cr.status == WLAN_STATUS_SUCCESS);
}
EXPORT_SYMBOL(cfg80211_rx_assoc_resp);
@@ -216,14 +221,14 @@
const u8 *ssid, int ssid_len,
const u8 *ie, int ie_len,
const u8 *key, int key_len, int key_idx,
- const u8 *sae_data, int sae_data_len)
+ const u8 *auth_data, int auth_data_len)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_auth_request req = {
.ie = ie,
.ie_len = ie_len,
- .sae_data = sae_data,
- .sae_data_len = sae_data_len,
+ .auth_data = auth_data,
+ .auth_data_len = auth_data_len,
.auth_type = auth_type,
.key = key,
.key_len = key_len,
@@ -657,8 +662,25 @@
return err;
}
- if (!ether_addr_equal(mgmt->sa, wdev_address(wdev)))
- return -EINVAL;
+ if (!ether_addr_equal(mgmt->sa, wdev_address(wdev))) {
+ /* Allow random TA to be used with Public Action frames if the
+ * driver has indicated support for this. Otherwise, only allow
+ * the local address to be used.
+ */
+ if (!ieee80211_is_action(mgmt->frame_control) ||
+ mgmt->u.action.category != WLAN_CATEGORY_PUBLIC)
+ return -EINVAL;
+ if (!wdev->current_bss &&
+ !wiphy_ext_feature_isset(
+ &rdev->wiphy,
+ NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA))
+ return -EINVAL;
+ if (wdev->current_bss &&
+ !wiphy_ext_feature_isset(
+ &rdev->wiphy,
+ NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED))
+ return -EINVAL;
+ }
/* Transmit the Action frame as requested by user space */
return rdev_mgmt_tx(rdev, wdev, params, cookie);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 4ba0d590..ebd9a4b 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -305,8 +305,7 @@
[NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 },
[NL80211_ATTR_PID] = { .type = NLA_U32 },
[NL80211_ATTR_4ADDR] = { .type = NLA_U8 },
- [NL80211_ATTR_PMKID] = { .type = NLA_BINARY,
- .len = WLAN_PMKID_LEN },
+ [NL80211_ATTR_PMKID] = { .len = WLAN_PMKID_LEN },
[NL80211_ATTR_DURATION] = { .type = NLA_U32 },
[NL80211_ATTR_COOKIE] = { .type = NLA_U64 },
[NL80211_ATTR_TX_RATES] = { .type = NLA_NESTED },
@@ -357,11 +356,12 @@
[NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 },
[NL80211_ATTR_WDEV] = { .type = NLA_U64 },
[NL80211_ATTR_USER_REG_HINT_TYPE] = { .type = NLA_U32 },
- [NL80211_ATTR_SAE_DATA] = { .type = NLA_BINARY, },
+ [NL80211_ATTR_AUTH_DATA] = { .type = NLA_BINARY, },
[NL80211_ATTR_VHT_CAPABILITY] = { .len = NL80211_VHT_CAPABILITY_LEN },
[NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 },
[NL80211_ATTR_P2P_CTWINDOW] = { .type = NLA_U8 },
[NL80211_ATTR_P2P_OPPPS] = { .type = NLA_U8 },
+ [NL80211_ATTR_LOCAL_MESH_POWER_MODE] = {. type = NLA_U32 },
[NL80211_ATTR_ACL_POLICY] = {. type = NLA_U32 },
[NL80211_ATTR_MAC_ADDRS] = { .type = NLA_NESTED },
[NL80211_ATTR_STA_CAPABILITY] = { .type = NLA_U16 },
@@ -414,7 +414,25 @@
[NL80211_ATTR_NAN_MASTER_PREF] = { .type = NLA_U8 },
[NL80211_ATTR_NAN_DUAL] = { .type = NLA_U8 },
[NL80211_ATTR_NAN_FUNC] = { .type = NLA_NESTED },
+ [NL80211_ATTR_FILS_KEK] = { .type = NLA_BINARY,
+ .len = FILS_MAX_KEK_LEN },
+ [NL80211_ATTR_FILS_NONCES] = { .len = 2 * FILS_NONCE_LEN },
+ [NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED] = { .type = NLA_FLAG, },
[NL80211_ATTR_BSSID] = { .len = ETH_ALEN },
+ [NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI] = { .type = NLA_S8 },
+ [NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST] = {
+ .len = sizeof(struct nl80211_bss_select_rssi_adjust)
+ },
+ [NL80211_ATTR_TIMEOUT_REASON] = { .type = NLA_U32 },
+ [NL80211_ATTR_FILS_ERP_USERNAME] = { .type = NLA_BINARY,
+ .len = FILS_ERP_MAX_USERNAME_LEN },
+ [NL80211_ATTR_FILS_ERP_REALM] = { .type = NLA_BINARY,
+ .len = FILS_ERP_MAX_REALM_LEN },
+ [NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] = { .type = NLA_U16 },
+ [NL80211_ATTR_FILS_ERP_RRK] = { .type = NLA_BINARY,
+ .len = FILS_ERP_MAX_RRK_LEN },
+ [NL80211_ATTR_FILS_CACHE_ID] = { .len = 2 },
+ [NL80211_ATTR_PMK] = { .type = NLA_BINARY, .len = PMK_MAX_LEN },
};
/* policy for the key attributes */
@@ -481,7 +499,8 @@
/* policy for GTK rekey offload attributes */
static const struct nla_policy
nl80211_rekey_policy[NUM_NL80211_REKEY_DATA] = {
- [NL80211_REKEY_DATA_KEK] = { .len = NL80211_KEK_LEN },
+ [NL80211_REKEY_DATA_KEK] = { .type = NLA_BINARY,
+ .len = FILS_MAX_KEK_LEN },
[NL80211_REKEY_DATA_KCK] = { .len = NL80211_KCK_LEN },
[NL80211_REKEY_DATA_REPLAY_CTR] = { .len = NL80211_REPLAY_CTR_LEN },
};
@@ -512,7 +531,7 @@
static const struct nla_policy
nl80211_nan_func_policy[NL80211_NAN_FUNC_ATTR_MAX + 1] = {
[NL80211_NAN_FUNC_TYPE] = { .type = NLA_U8 },
- [NL80211_NAN_FUNC_SERVICE_ID] = { .type = NLA_BINARY,
+ [NL80211_NAN_FUNC_SERVICE_ID] = {
.len = NL80211_NAN_FUNC_SERVICE_ID_LEN },
[NL80211_NAN_FUNC_PUBLISH_TYPE] = { .type = NLA_U8 },
[NL80211_NAN_FUNC_PUBLISH_BCAST] = { .type = NLA_FLAG },
@@ -1609,6 +1628,8 @@
if (rdev->wiphy.features &
NL80211_FEATURE_SUPPORTS_WMM_ADMISSION)
CMD(add_tx_ts, ADD_TX_TS);
+ CMD(set_multicast_to_unicast, SET_MULTICAST_TO_UNICAST);
+ CMD(update_connect_params, UPDATE_CONNECT_PARAMS);
}
/* add into the if now */
#undef CMD
@@ -3747,12 +3768,36 @@
if (!(rdev->wiphy.features & NL80211_FEATURE_SAE) &&
auth_type == NL80211_AUTHTYPE_SAE)
return false;
+ if (!wiphy_ext_feature_isset(&rdev->wiphy,
+ NL80211_EXT_FEATURE_FILS_STA) &&
+ (auth_type == NL80211_AUTHTYPE_FILS_SK ||
+ auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
+ auth_type == NL80211_AUTHTYPE_FILS_PK))
+ return false;
return true;
case NL80211_CMD_CONNECT:
+ /* SAE not supported yet */
+ if (auth_type == NL80211_AUTHTYPE_SAE)
+ return false;
+ /* FILS with SK PFS or PK not supported yet */
+ if (auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
+ auth_type == NL80211_AUTHTYPE_FILS_PK)
+ return false;
+ if (!wiphy_ext_feature_isset(
+ &rdev->wiphy,
+ NL80211_EXT_FEATURE_FILS_SK_OFFLOAD) &&
+ auth_type == NL80211_AUTHTYPE_FILS_SK)
+ return false;
+ return true;
case NL80211_CMD_START_AP:
/* SAE not supported yet */
if (auth_type == NL80211_AUTHTYPE_SAE)
return false;
+ /* FILS not supported yet */
+ if (auth_type == NL80211_AUTHTYPE_FILS_SK ||
+ auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
+ auth_type == NL80211_AUTHTYPE_FILS_PK)
+ return false;
return true;
default:
return false;
@@ -6331,6 +6376,10 @@
struct nlattr *attr1, *attr2;
int n_channels = 0, tmp1, tmp2;
+ nla_for_each_nested(attr1, freqs, tmp1)
+ if (nla_len(attr1) != sizeof(u32))
+ return 0;
+
nla_for_each_nested(attr1, freqs, tmp1) {
n_channels++;
/*
@@ -6923,6 +6972,12 @@
if (!n_plans || n_plans > wiphy->max_sched_scan_plans)
return ERR_PTR(-EINVAL);
+ if (!wiphy_ext_feature_isset(
+ wiphy, NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI) &&
+ (attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI] ||
+ attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]))
+ return ERR_PTR(-EINVAL);
+
request = kzalloc(sizeof(*request)
+ sizeof(*request->ssids) * n_ssids
+ sizeof(*request->match_sets) * n_match_sets
@@ -7129,6 +7184,26 @@
request->delay =
nla_get_u32(attrs[NL80211_ATTR_SCHED_SCAN_DELAY]);
+ if (attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI]) {
+ request->relative_rssi = nla_get_s8(
+ attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI]);
+ request->relative_rssi_set = true;
+ }
+
+ if (request->relative_rssi_set &&
+ attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]) {
+ struct nl80211_bss_select_rssi_adjust *rssi_adjust;
+
+ rssi_adjust = nla_data(
+ attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]);
+ request->rssi_adjust.band = rssi_adjust->band;
+ request->rssi_adjust.delta = rssi_adjust->delta;
+ if (!is_band_valid(wiphy, request->rssi_adjust.band)) {
+ err = -EINVAL;
+ goto out_free;
+ }
+ }
+
err = nl80211_parse_sched_scan_plans(wiphy, n_plans, request, attrs);
if (err)
goto out_free;
@@ -7724,8 +7799,8 @@
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev = info->user_ptr[1];
struct ieee80211_channel *chan;
- const u8 *bssid, *ssid, *ie = NULL, *sae_data = NULL;
- int err, ssid_len, ie_len = 0, sae_data_len = 0;
+ const u8 *bssid, *ssid, *ie = NULL, *auth_data = NULL;
+ int err, ssid_len, ie_len = 0, auth_data_len = 0;
enum nl80211_auth_type auth_type;
struct key_parse key;
bool local_state_change;
@@ -7805,17 +7880,23 @@
if (!nl80211_valid_auth_type(rdev, auth_type, NL80211_CMD_AUTHENTICATE))
return -EINVAL;
- if (auth_type == NL80211_AUTHTYPE_SAE &&
- !info->attrs[NL80211_ATTR_SAE_DATA])
+ if ((auth_type == NL80211_AUTHTYPE_SAE ||
+ auth_type == NL80211_AUTHTYPE_FILS_SK ||
+ auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
+ auth_type == NL80211_AUTHTYPE_FILS_PK) &&
+ !info->attrs[NL80211_ATTR_AUTH_DATA])
return -EINVAL;
- if (info->attrs[NL80211_ATTR_SAE_DATA]) {
- if (auth_type != NL80211_AUTHTYPE_SAE)
+ if (info->attrs[NL80211_ATTR_AUTH_DATA]) {
+ if (auth_type != NL80211_AUTHTYPE_SAE &&
+ auth_type != NL80211_AUTHTYPE_FILS_SK &&
+ auth_type != NL80211_AUTHTYPE_FILS_SK_PFS &&
+ auth_type != NL80211_AUTHTYPE_FILS_PK)
return -EINVAL;
- sae_data = nla_data(info->attrs[NL80211_ATTR_SAE_DATA]);
- sae_data_len = nla_len(info->attrs[NL80211_ATTR_SAE_DATA]);
+ auth_data = nla_data(info->attrs[NL80211_ATTR_AUTH_DATA]);
+ auth_data_len = nla_len(info->attrs[NL80211_ATTR_AUTH_DATA]);
/* need to include at least Auth Transaction and Status Code */
- if (sae_data_len < 4)
+ if (auth_data_len < 4)
return -EINVAL;
}
@@ -7832,7 +7913,7 @@
err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
ssid, ssid_len, ie, ie_len,
key.p.key, key.p.key_len, key.idx,
- sae_data, sae_data_len);
+ auth_data, auth_data_len);
wdev_unlock(dev->ieee80211_ptr);
return err;
}
@@ -8011,6 +8092,15 @@
req.flags |= ASSOC_REQ_USE_RRM;
}
+ if (info->attrs[NL80211_ATTR_FILS_KEK]) {
+ req.fils_kek = nla_data(info->attrs[NL80211_ATTR_FILS_KEK]);
+ req.fils_kek_len = nla_len(info->attrs[NL80211_ATTR_FILS_KEK]);
+ if (!info->attrs[NL80211_ATTR_FILS_NONCES])
+ return -EINVAL;
+ req.fils_nonces =
+ nla_data(info->attrs[NL80211_ATTR_FILS_NONCES]);
+ }
+
err = nl80211_crypto_settings(rdev, info, &req.crypto, 1);
if (!err) {
wdev_lock(dev->ieee80211_ptr);
@@ -8734,6 +8824,35 @@
}
}
+ if (wiphy_ext_feature_isset(&rdev->wiphy,
+ NL80211_EXT_FEATURE_FILS_SK_OFFLOAD) &&
+ info->attrs[NL80211_ATTR_FILS_ERP_USERNAME] &&
+ info->attrs[NL80211_ATTR_FILS_ERP_REALM] &&
+ info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] &&
+ info->attrs[NL80211_ATTR_FILS_ERP_RRK]) {
+ connect.fils_erp_username =
+ nla_data(info->attrs[NL80211_ATTR_FILS_ERP_USERNAME]);
+ connect.fils_erp_username_len =
+ nla_len(info->attrs[NL80211_ATTR_FILS_ERP_USERNAME]);
+ connect.fils_erp_realm =
+ nla_data(info->attrs[NL80211_ATTR_FILS_ERP_REALM]);
+ connect.fils_erp_realm_len =
+ nla_len(info->attrs[NL80211_ATTR_FILS_ERP_REALM]);
+ connect.fils_erp_next_seq_num =
+ nla_get_u16(
+ info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM]);
+ connect.fils_erp_rrk =
+ nla_data(info->attrs[NL80211_ATTR_FILS_ERP_RRK]);
+ connect.fils_erp_rrk_len =
+ nla_len(info->attrs[NL80211_ATTR_FILS_ERP_RRK]);
+ } else if (info->attrs[NL80211_ATTR_FILS_ERP_USERNAME] ||
+ info->attrs[NL80211_ATTR_FILS_ERP_REALM] ||
+ info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] ||
+ info->attrs[NL80211_ATTR_FILS_ERP_RRK]) {
+ kzfree(connkeys);
+ return -EINVAL;
+ }
+
wdev_lock(dev->ieee80211_ptr);
err = cfg80211_connect(rdev, dev, &connect, connkeys,
connect.prev_bssid);
@@ -8743,6 +8862,76 @@
return err;
}
+static int nl80211_update_connect_params(struct sk_buff *skb,
+ struct genl_info *info)
+{
+ struct cfg80211_connect_params connect = {};
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ u32 changed = 0;
+ int ret;
+
+ if (!rdev->ops->update_connect_params)
+ return -EOPNOTSUPP;
+
+ if (info->attrs[NL80211_ATTR_IE]) {
+ if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
+ return -EINVAL;
+ connect.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
+ connect.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
+ changed |= UPDATE_ASSOC_IES;
+ }
+
+ if (wiphy_ext_feature_isset(&rdev->wiphy,
+ NL80211_EXT_FEATURE_FILS_SK_OFFLOAD) &&
+ info->attrs[NL80211_ATTR_FILS_ERP_USERNAME] &&
+ info->attrs[NL80211_ATTR_FILS_ERP_REALM] &&
+ info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] &&
+ info->attrs[NL80211_ATTR_FILS_ERP_RRK]) {
+ connect.fils_erp_username =
+ nla_data(info->attrs[NL80211_ATTR_FILS_ERP_USERNAME]);
+ connect.fils_erp_username_len =
+ nla_len(info->attrs[NL80211_ATTR_FILS_ERP_USERNAME]);
+ connect.fils_erp_realm =
+ nla_data(info->attrs[NL80211_ATTR_FILS_ERP_REALM]);
+ connect.fils_erp_realm_len =
+ nla_len(info->attrs[NL80211_ATTR_FILS_ERP_REALM]);
+ connect.fils_erp_next_seq_num =
+ nla_get_u16(
+ info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM]);
+ connect.fils_erp_rrk =
+ nla_data(info->attrs[NL80211_ATTR_FILS_ERP_RRK]);
+ connect.fils_erp_rrk_len =
+ nla_len(info->attrs[NL80211_ATTR_FILS_ERP_RRK]);
+ changed |= UPDATE_FILS_ERP_INFO;
+ } else if (info->attrs[NL80211_ATTR_FILS_ERP_USERNAME] ||
+ info->attrs[NL80211_ATTR_FILS_ERP_REALM] ||
+ info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] ||
+ info->attrs[NL80211_ATTR_FILS_ERP_RRK]) {
+ return -EINVAL;
+ }
+
+ if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
+ u32 auth_type =
+ nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
+ if (!nl80211_valid_auth_type(rdev, auth_type,
+ NL80211_CMD_CONNECT))
+ return -EINVAL;
+ connect.auth_type = auth_type;
+ changed |= UPDATE_AUTH_TYPE;
+ }
+
+ wdev_lock(dev->ieee80211_ptr);
+ if (!wdev->current_bss)
+ ret = -ENOLINK;
+ else
+ ret = rdev_update_connect_params(rdev, dev, &connect, changed);
+ wdev_unlock(dev->ieee80211_ptr);
+
+ return ret;
+}
+
static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
@@ -8809,14 +8998,28 @@
memset(&pmksa, 0, sizeof(struct cfg80211_pmksa));
- if (!info->attrs[NL80211_ATTR_MAC])
- return -EINVAL;
-
if (!info->attrs[NL80211_ATTR_PMKID])
return -EINVAL;
pmksa.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]);
- pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+ if (info->attrs[NL80211_ATTR_MAC]) {
+ pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
+ } else if (info->attrs[NL80211_ATTR_SSID] &&
+ info->attrs[NL80211_ATTR_FILS_CACHE_ID] &&
+ (info->genlhdr->cmd == NL80211_CMD_DEL_PMKSA ||
+ info->attrs[NL80211_ATTR_PMK])) {
+ pmksa.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
+ pmksa.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
+ pmksa.cache_id =
+ nla_data(info->attrs[NL80211_ATTR_FILS_CACHE_ID]);
+ } else {
+ return -EINVAL;
+ }
+ if (info->attrs[NL80211_ATTR_PMK]) {
+ pmksa.pmk = nla_data(info->attrs[NL80211_ATTR_PMK]);
+ pmksa.pmk_len = nla_len(info->attrs[NL80211_ATTR_PMK]);
+ }
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
@@ -9604,6 +9807,20 @@
if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_DELAY, req->delay))
return -ENOBUFS;
+ if (req->relative_rssi_set) {
+ struct nl80211_bss_select_rssi_adjust rssi_adjust;
+
+ if (nla_put_s8(msg, NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI,
+ req->relative_rssi))
+ return -ENOBUFS;
+
+ rssi_adjust.band = req->rssi_adjust.band;
+ rssi_adjust.delta = req->rssi_adjust.delta;
+ if (nla_put(msg, NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST,
+ sizeof(rssi_adjust), &rssi_adjust))
+ return -ENOBUFS;
+ }
+
freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
if (!freqs)
return -ENOBUFS;
@@ -10392,15 +10609,27 @@
if (err)
return err;
+ if (!tb[NL80211_REKEY_DATA_KEK] || !tb[NL80211_REKEY_DATA_REPLAY_CTR] ||
+ (!wiphy_ext_feature_isset(&rdev->wiphy,
+ NL80211_EXT_FEATURE_FILS_SK_OFFLOAD) &&
+ !wiphy_ext_feature_isset(&rdev->wiphy,
+ NL80211_EXT_FEATURE_FILS_STA) &&
+ !tb[NL80211_REKEY_DATA_KCK]))
+ return -EINVAL;
+
if (nla_len(tb[NL80211_REKEY_DATA_REPLAY_CTR]) != NL80211_REPLAY_CTR_LEN)
return -ERANGE;
- if (nla_len(tb[NL80211_REKEY_DATA_KEK]) != NL80211_KEK_LEN)
+ if (nla_len(tb[NL80211_REKEY_DATA_KEK]) < NL80211_KEK_LEN)
return -ERANGE;
- if (nla_len(tb[NL80211_REKEY_DATA_KCK]) != NL80211_KCK_LEN)
+ if (tb[NL80211_REKEY_DATA_KCK] &&
+ nla_len(tb[NL80211_REKEY_DATA_KCK]) != NL80211_KCK_LEN)
return -ERANGE;
+ memset(&rekey_data, 0, sizeof(rekey_data));
rekey_data.kek = nla_data(tb[NL80211_REKEY_DATA_KEK]);
- rekey_data.kck = nla_data(tb[NL80211_REKEY_DATA_KCK]);
+ rekey_data.kek_len = nla_len(tb[NL80211_REKEY_DATA_KEK]);
+ if (tb[NL80211_REKEY_DATA_KCK])
+ rekey_data.kck = nla_data(tb[NL80211_REKEY_DATA_KCK]);
rekey_data.replay_ctr = nla_data(tb[NL80211_REKEY_DATA_REPLAY_CTR]);
wdev_lock(wdev);
@@ -11739,6 +11968,31 @@
return 0;
}
+static int nl80211_set_multicast_to_unicast(struct sk_buff *skb,
+ struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ const struct nlattr *nla;
+ bool enabled;
+
+ if (netif_running(dev))
+ return -EBUSY;
+
+ if (!rdev->ops->set_multicast_to_unicast)
+ return -EOPNOTSUPP;
+
+ if (wdev->iftype != NL80211_IFTYPE_AP &&
+ wdev->iftype != NL80211_IFTYPE_P2P_GO)
+ return -EOPNOTSUPP;
+
+ nla = info->attrs[NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED];
+ enabled = nla_get_flag(nla);
+
+ return rdev_set_multicast_to_unicast(rdev, dev, enabled);
+}
+
#define NL80211_FLAG_NEED_WIPHY 0x01
#define NL80211_FLAG_NEED_NETDEV 0x02
#define NL80211_FLAG_NEED_RTNL 0x04
@@ -12192,6 +12446,14 @@
NL80211_FLAG_NEED_RTNL,
},
{
+ .cmd = NL80211_CMD_UPDATE_CONNECT_PARAMS,
+ .doit = nl80211_update_connect_params,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
+ },
+ {
.cmd = NL80211_CMD_DISCONNECT,
.doit = nl80211_disconnect,
.policy = nl80211_policy,
@@ -12612,6 +12874,14 @@
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
NL80211_FLAG_NEED_RTNL,
},
+ {
+ .cmd = NL80211_CMD_SET_MULTICAST_TO_UNICAST,
+ .doit = nl80211_set_multicast_to_unicast,
+ .policy = nl80211_policy,
+ .flags = GENL_UNS_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV |
+ NL80211_FLAG_NEED_RTNL,
+ },
};
/* notification functions */
@@ -12941,7 +13211,7 @@
struct sk_buff *msg;
void *hdr;
- msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
+ msg = nlmsg_new(100 + len, gfp);
if (!msg)
return;
@@ -13085,15 +13355,16 @@
}
void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
- struct net_device *netdev, const u8 *bssid,
- const u8 *req_ie, size_t req_ie_len,
- const u8 *resp_ie, size_t resp_ie_len,
- int status, gfp_t gfp)
+ struct net_device *netdev,
+ struct cfg80211_connect_resp_params *cr,
+ gfp_t gfp)
{
struct sk_buff *msg;
void *hdr;
- msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
+ msg = nlmsg_new(100 + cr->req_ie_len + cr->resp_ie_len +
+ cr->fils_kek_len + cr->pmk_len +
+ (cr->pmkid ? WLAN_PMKID_LEN : 0), gfp);
if (!msg)
return;
@@ -13105,15 +13376,31 @@
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
- (bssid && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid)) ||
+ (cr->bssid &&
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, cr->bssid)) ||
nla_put_u16(msg, NL80211_ATTR_STATUS_CODE,
- status < 0 ? WLAN_STATUS_UNSPECIFIED_FAILURE :
- status) ||
- (status < 0 && nla_put_flag(msg, NL80211_ATTR_TIMED_OUT)) ||
- (req_ie &&
- nla_put(msg, NL80211_ATTR_REQ_IE, req_ie_len, req_ie)) ||
- (resp_ie &&
- nla_put(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie)))
+ cr->status < 0 ? WLAN_STATUS_UNSPECIFIED_FAILURE :
+ cr->status) ||
+ (cr->status < 0 &&
+ (nla_put_flag(msg, NL80211_ATTR_TIMED_OUT) ||
+ nla_put_u32(msg, NL80211_ATTR_TIMEOUT_REASON,
+ cr->timeout_reason))) ||
+ (cr->req_ie &&
+ nla_put(msg, NL80211_ATTR_REQ_IE, cr->req_ie_len, cr->req_ie)) ||
+ (cr->resp_ie &&
+ nla_put(msg, NL80211_ATTR_RESP_IE, cr->resp_ie_len,
+ cr->resp_ie)) ||
+ (cr->update_erp_next_seq_num &&
+ nla_put_u16(msg, NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM,
+ cr->fils_erp_next_seq_num)) ||
+ (cr->status == WLAN_STATUS_SUCCESS &&
+ ((cr->fils_kek &&
+ nla_put(msg, NL80211_ATTR_FILS_KEK, cr->fils_kek_len,
+ cr->fils_kek)) ||
+ (cr->pmk &&
+ nla_put(msg, NL80211_ATTR_PMK, cr->pmk_len, cr->pmk)) ||
+ (cr->pmkid &&
+ nla_put(msg, NL80211_ATTR_PMKID, WLAN_PMKID_LEN, cr->pmkid)))))
goto nla_put_failure;
genlmsg_end(msg, hdr);
@@ -13135,7 +13422,7 @@
struct sk_buff *msg;
void *hdr;
- msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
+ msg = nlmsg_new(100 + req_ie_len + resp_ie_len, gfp);
if (!msg)
return;
@@ -13172,7 +13459,7 @@
struct sk_buff *msg;
void *hdr;
- msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ msg = nlmsg_new(100 + ie_len, GFP_KERNEL);
if (!msg)
return;
@@ -13248,7 +13535,7 @@
trace_cfg80211_notify_new_peer_candidate(dev, addr);
- msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
+ msg = nlmsg_new(100 + ie_len, gfp);
if (!msg)
return;
@@ -13619,7 +13906,7 @@
struct sk_buff *msg;
void *hdr;
- msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
+ msg = nlmsg_new(100 + len, gfp);
if (!msg)
return -ENOMEM;
@@ -13663,7 +13950,7 @@
trace_cfg80211_mgmt_tx_status(wdev, cookie, ack);
- msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
+ msg = nlmsg_new(100 + len, gfp);
if (!msg)
return;
@@ -14472,7 +14759,7 @@
if (!ft_event->target_ap)
return;
- msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ msg = nlmsg_new(100 + ft_event->ric_ies_len, GFP_KERNEL);
if (!msg)
return;
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index 7e3821d..2a84d18 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -55,10 +55,9 @@
struct net_device *netdev,
const u8 *addr, gfp_t gfp);
void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
- struct net_device *netdev, const u8 *bssid,
- const u8 *req_ie, size_t req_ie_len,
- const u8 *resp_ie, size_t resp_ie_len,
- int status, gfp_t gfp);
+ struct net_device *netdev,
+ struct cfg80211_connect_resp_params *params,
+ gfp_t gfp);
void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
struct net_device *netdev, const u8 *bssid,
const u8 *req_ie, size_t req_ie_len,
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 11cf83c..2f42507 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -490,6 +490,18 @@
return ret;
}
+static inline int
+rdev_update_connect_params(struct cfg80211_registered_device *rdev,
+ struct net_device *dev,
+ struct cfg80211_connect_params *sme, u32 changed)
+{
+ int ret;
+ trace_rdev_update_connect_params(&rdev->wiphy, dev, sme, changed);
+ ret = rdev->ops->update_connect_params(&rdev->wiphy, dev, sme, changed);
+ trace_rdev_return_int(&rdev->wiphy, ret);
+ return ret;
+}
+
static inline int rdev_disconnect(struct cfg80211_registered_device *rdev,
struct net_device *dev, u16 reason_code)
{
@@ -562,6 +574,18 @@
return ret;
}
+static inline int
+rdev_set_multicast_to_unicast(struct cfg80211_registered_device *rdev,
+ struct net_device *dev,
+ const bool enabled)
+{
+ int ret;
+ trace_rdev_set_multicast_to_unicast(&rdev->wiphy, dev, enabled);
+ ret = rdev->ops->set_multicast_to_unicast(&rdev->wiphy, dev, enabled);
+ trace_rdev_return_int(&rdev->wiphy, ret);
+ return ret;
+}
+
static inline void rdev_rfkill_poll(struct cfg80211_registered_device *rdev)
{
trace_rdev_rfkill_poll(&rdev->wiphy);
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 8ae2e20..d7e6abc 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -34,10 +34,11 @@
CFG80211_CONN_SCAN_AGAIN,
CFG80211_CONN_AUTHENTICATE_NEXT,
CFG80211_CONN_AUTHENTICATING,
- CFG80211_CONN_AUTH_FAILED,
+ CFG80211_CONN_AUTH_FAILED_TIMEOUT,
CFG80211_CONN_ASSOCIATE_NEXT,
CFG80211_CONN_ASSOCIATING,
CFG80211_CONN_ASSOC_FAILED,
+ CFG80211_CONN_ASSOC_FAILED_TIMEOUT,
CFG80211_CONN_DEAUTH,
CFG80211_CONN_ABANDON,
CFG80211_CONN_CONNECTED,
@@ -163,7 +164,8 @@
return err;
}
-static int cfg80211_conn_do_work(struct wireless_dev *wdev)
+static int cfg80211_conn_do_work(struct wireless_dev *wdev,
+ enum nl80211_timeout_reason *treason)
{
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
struct cfg80211_connect_params *params;
@@ -194,7 +196,8 @@
NULL, 0,
params->key, params->key_len,
params->key_idx, NULL, 0);
- case CFG80211_CONN_AUTH_FAILED:
+ case CFG80211_CONN_AUTH_FAILED_TIMEOUT:
+ *treason = NL80211_TIMEOUT_AUTH;
return -ENOTCONN;
case CFG80211_CONN_ASSOCIATE_NEXT:
if (WARN_ON(!rdev->ops->assoc))
@@ -221,6 +224,9 @@
WLAN_REASON_DEAUTH_LEAVING,
false);
return err;
+ case CFG80211_CONN_ASSOC_FAILED_TIMEOUT:
+ *treason = NL80211_TIMEOUT_ASSOC;
+ /* fall through */
case CFG80211_CONN_ASSOC_FAILED:
cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
NULL, 0,
@@ -246,6 +252,7 @@
container_of(work, struct cfg80211_registered_device, conn_work);
struct wireless_dev *wdev;
u8 bssid_buf[ETH_ALEN], *bssid = NULL;
+ enum nl80211_timeout_reason treason;
rtnl_lock();
@@ -267,10 +274,15 @@
memcpy(bssid_buf, wdev->conn->params.bssid, ETH_ALEN);
bssid = bssid_buf;
}
- if (cfg80211_conn_do_work(wdev)) {
- __cfg80211_connect_result(
- wdev->netdev, bssid,
- NULL, 0, NULL, 0, -1, false, NULL);
+ treason = NL80211_TIMEOUT_UNSPECIFIED;
+ if (cfg80211_conn_do_work(wdev, &treason)) {
+ struct cfg80211_connect_resp_params cr;
+
+ memset(&cr, 0, sizeof(cr));
+ cr.status = -1;
+ cr.bssid = bssid;
+ cr.timeout_reason = treason;
+ __cfg80211_connect_result(wdev->netdev, &cr, false);
}
wdev_unlock(wdev);
}
@@ -373,9 +385,13 @@
wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
schedule_work(&rdev->conn_work);
} else if (status_code != WLAN_STATUS_SUCCESS) {
- __cfg80211_connect_result(wdev->netdev, mgmt->bssid,
- NULL, 0, NULL, 0,
- status_code, false, NULL);
+ struct cfg80211_connect_resp_params cr;
+
+ memset(&cr, 0, sizeof(cr));
+ cr.status = status_code;
+ cr.bssid = mgmt->bssid;
+ cr.timeout_reason = NL80211_TIMEOUT_UNSPECIFIED;
+ __cfg80211_connect_result(wdev->netdev, &cr, false);
} else if (wdev->conn->state == CFG80211_CONN_AUTHENTICATING) {
wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT;
schedule_work(&rdev->conn_work);
@@ -423,7 +439,7 @@
if (!wdev->conn)
return;
- wdev->conn->state = CFG80211_CONN_AUTH_FAILED;
+ wdev->conn->state = CFG80211_CONN_AUTH_FAILED_TIMEOUT;
schedule_work(&rdev->conn_work);
}
@@ -445,7 +461,7 @@
if (!wdev->conn)
return;
- wdev->conn->state = CFG80211_CONN_ASSOC_FAILED;
+ wdev->conn->state = CFG80211_CONN_ASSOC_FAILED_TIMEOUT;
schedule_work(&rdev->conn_work);
}
@@ -587,7 +603,9 @@
/* we're good if we have a matching bss struct */
if (bss) {
- err = cfg80211_conn_do_work(wdev);
+ enum nl80211_timeout_reason treason;
+
+ err = cfg80211_conn_do_work(wdev, &treason);
cfg80211_put_bss(wdev->wiphy, bss);
} else {
/* otherwise we'll need to scan for the AP first */
@@ -681,11 +699,9 @@
*/
/* This method must consume bss one way or another */
-void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
- const u8 *req_ie, size_t req_ie_len,
- const u8 *resp_ie, size_t resp_ie_len,
- int status, bool wextev,
- struct cfg80211_bss *bss)
+void __cfg80211_connect_result(struct net_device *dev,
+ struct cfg80211_connect_resp_params *cr,
+ bool wextev)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
const u8 *country_ie;
@@ -697,48 +713,48 @@
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION &&
wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) {
- cfg80211_put_bss(wdev->wiphy, bss);
+ cfg80211_put_bss(wdev->wiphy, cr->bss);
return;
}
- nl80211_send_connect_result(wiphy_to_rdev(wdev->wiphy), dev,
- bssid, req_ie, req_ie_len,
- resp_ie, resp_ie_len,
- status, GFP_KERNEL);
+ nl80211_send_connect_result(wiphy_to_rdev(wdev->wiphy), dev, cr,
+ GFP_KERNEL);
#ifdef CONFIG_CFG80211_WEXT
if (wextev) {
- if (req_ie && status == WLAN_STATUS_SUCCESS) {
+ if (cr->req_ie && cr->status == WLAN_STATUS_SUCCESS) {
memset(&wrqu, 0, sizeof(wrqu));
- wrqu.data.length = req_ie_len;
- wireless_send_event(dev, IWEVASSOCREQIE, &wrqu, req_ie);
+ wrqu.data.length = cr->req_ie_len;
+ wireless_send_event(dev, IWEVASSOCREQIE, &wrqu,
+ cr->req_ie);
}
- if (resp_ie && status == WLAN_STATUS_SUCCESS) {
+ if (cr->resp_ie && cr->status == WLAN_STATUS_SUCCESS) {
memset(&wrqu, 0, sizeof(wrqu));
- wrqu.data.length = resp_ie_len;
- wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, resp_ie);
+ wrqu.data.length = cr->resp_ie_len;
+ wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu,
+ cr->resp_ie);
}
memset(&wrqu, 0, sizeof(wrqu));
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
- if (bssid && status == WLAN_STATUS_SUCCESS) {
- memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
- memcpy(wdev->wext.prev_bssid, bssid, ETH_ALEN);
+ if (cr->bssid && cr->status == WLAN_STATUS_SUCCESS) {
+ memcpy(wrqu.ap_addr.sa_data, cr->bssid, ETH_ALEN);
+ memcpy(wdev->wext.prev_bssid, cr->bssid, ETH_ALEN);
wdev->wext.prev_bssid_valid = true;
}
wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
}
#endif
- if (!bss && (status == WLAN_STATUS_SUCCESS)) {
+ if (!cr->bss && (cr->status == WLAN_STATUS_SUCCESS)) {
WARN_ON_ONCE(!wiphy_to_rdev(wdev->wiphy)->ops->connect);
- bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
- wdev->ssid, wdev->ssid_len,
- wdev->conn_bss_type,
- IEEE80211_PRIVACY_ANY);
- if (bss)
- cfg80211_hold_bss(bss_from_pub(bss));
+ cr->bss = cfg80211_get_bss(wdev->wiphy, NULL, cr->bssid,
+ wdev->ssid, wdev->ssid_len,
+ wdev->conn_bss_type,
+ IEEE80211_PRIVACY_ANY);
+ if (cr->bss)
+ cfg80211_hold_bss(bss_from_pub(cr->bss));
}
if (wdev->current_bss) {
@@ -747,28 +763,28 @@
wdev->current_bss = NULL;
}
- if (status != WLAN_STATUS_SUCCESS) {
+ if (cr->status != WLAN_STATUS_SUCCESS) {
kzfree(wdev->connect_keys);
wdev->connect_keys = NULL;
wdev->ssid_len = 0;
- if (bss) {
- cfg80211_unhold_bss(bss_from_pub(bss));
- cfg80211_put_bss(wdev->wiphy, bss);
+ if (cr->bss) {
+ cfg80211_unhold_bss(bss_from_pub(cr->bss));
+ cfg80211_put_bss(wdev->wiphy, cr->bss);
}
cfg80211_sme_free(wdev);
return;
}
- if (WARN_ON(!bss))
+ if (WARN_ON(!cr->bss))
return;
- wdev->current_bss = bss_from_pub(bss);
+ wdev->current_bss = bss_from_pub(cr->bss);
if (!(wdev->wiphy->flags & WIPHY_FLAG_HAS_STATIC_WEP))
cfg80211_upload_connect_keys(wdev);
rcu_read_lock();
- country_ie = ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY);
+ country_ie = ieee80211_bss_get_ie(cr->bss, WLAN_EID_COUNTRY);
if (!country_ie) {
rcu_read_unlock();
return;
@@ -785,62 +801,95 @@
* - country_ie + 2, the start of the country ie data, and
* - and country_ie[1] which is the IE length
*/
- regulatory_hint_country_ie(wdev->wiphy, bss->channel->band,
+ regulatory_hint_country_ie(wdev->wiphy, cr->bss->channel->band,
country_ie + 2, country_ie[1]);
kfree(country_ie);
}
/* Consumes bss object one way or another */
-void cfg80211_connect_bss(struct net_device *dev, const u8 *bssid,
- struct cfg80211_bss *bss, const u8 *req_ie,
- size_t req_ie_len, const u8 *resp_ie,
- size_t resp_ie_len, int status, gfp_t gfp)
+void cfg80211_connect_done(struct net_device *dev,
+ struct cfg80211_connect_resp_params *params,
+ gfp_t gfp)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
struct cfg80211_event *ev;
unsigned long flags;
+ u8 *next;
- if (bss) {
+ if (params->bss) {
/* Make sure the bss entry provided by the driver is valid. */
- struct cfg80211_internal_bss *ibss = bss_from_pub(bss);
+ struct cfg80211_internal_bss *ibss = bss_from_pub(params->bss);
if (WARN_ON(list_empty(&ibss->list))) {
- cfg80211_put_bss(wdev->wiphy, bss);
+ cfg80211_put_bss(wdev->wiphy, params->bss);
return;
}
}
- ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp);
+ ev = kzalloc(sizeof(*ev) + (params->bssid ? ETH_ALEN : 0) +
+ params->req_ie_len + params->resp_ie_len +
+ params->fils_kek_len + params->pmk_len +
+ (params->pmkid ? WLAN_PMKID_LEN : 0), gfp);
if (!ev) {
- cfg80211_put_bss(wdev->wiphy, bss);
+ cfg80211_put_bss(wdev->wiphy, params->bss);
return;
}
ev->type = EVENT_CONNECT_RESULT;
- if (bssid)
- memcpy(ev->cr.bssid, bssid, ETH_ALEN);
- if (req_ie_len) {
- ev->cr.req_ie = ((u8 *)ev) + sizeof(*ev);
- ev->cr.req_ie_len = req_ie_len;
- memcpy((void *)ev->cr.req_ie, req_ie, req_ie_len);
+ next = ((u8 *)ev) + sizeof(*ev);
+ if (params->bssid) {
+ ev->cr.bssid = next;
+ memcpy((void *)ev->cr.bssid, params->bssid, ETH_ALEN);
+ next += ETH_ALEN;
}
- if (resp_ie_len) {
- ev->cr.resp_ie = ((u8 *)ev) + sizeof(*ev) + req_ie_len;
- ev->cr.resp_ie_len = resp_ie_len;
- memcpy((void *)ev->cr.resp_ie, resp_ie, resp_ie_len);
+ if (params->req_ie_len) {
+ ev->cr.req_ie = next;
+ ev->cr.req_ie_len = params->req_ie_len;
+ memcpy((void *)ev->cr.req_ie, params->req_ie,
+ params->req_ie_len);
+ next += params->req_ie_len;
}
- if (bss)
- cfg80211_hold_bss(bss_from_pub(bss));
- ev->cr.bss = bss;
- ev->cr.status = status;
+ if (params->resp_ie_len) {
+ ev->cr.resp_ie = next;
+ ev->cr.resp_ie_len = params->resp_ie_len;
+ memcpy((void *)ev->cr.resp_ie, params->resp_ie,
+ params->resp_ie_len);
+ next += params->resp_ie_len;
+ }
+ if (params->fils_kek_len) {
+ ev->cr.fils_kek = next;
+ ev->cr.fils_kek_len = params->fils_kek_len;
+ memcpy((void *)ev->cr.fils_kek, params->fils_kek,
+ params->fils_kek_len);
+ next += params->fils_kek_len;
+ }
+ if (params->pmk_len) {
+ ev->cr.pmk = next;
+ ev->cr.pmk_len = params->pmk_len;
+ memcpy((void *)ev->cr.pmk, params->pmk, params->pmk_len);
+ next += params->pmk_len;
+ }
+ if (params->pmkid) {
+ ev->cr.pmkid = next;
+ memcpy((void *)ev->cr.pmkid, params->pmkid, WLAN_PMKID_LEN);
+ next += WLAN_PMKID_LEN;
+ }
+ ev->cr.update_erp_next_seq_num = params->update_erp_next_seq_num;
+ if (params->update_erp_next_seq_num)
+ ev->cr.fils_erp_next_seq_num = params->fils_erp_next_seq_num;
+ if (params->bss)
+ cfg80211_hold_bss(bss_from_pub(params->bss));
+ ev->cr.bss = params->bss;
+ ev->cr.status = params->status;
+ ev->cr.timeout_reason = params->timeout_reason;
spin_lock_irqsave(&wdev->event_lock, flags);
list_add_tail(&ev->list, &wdev->event_list);
spin_unlock_irqrestore(&wdev->event_lock, flags);
queue_work(cfg80211_wq, &rdev->event_work);
}
-EXPORT_SYMBOL(cfg80211_connect_bss);
+EXPORT_SYMBOL(cfg80211_connect_done);
/* Consumes bss object one way or another */
void __cfg80211_roamed(struct wireless_dev *wdev,
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index a3d0a91b..ea1b47e 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -1281,6 +1281,24 @@
__entry->wpa_versions, __entry->flags, MAC_PR_ARG(prev_bssid))
);
+TRACE_EVENT(rdev_update_connect_params,
+ TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+ struct cfg80211_connect_params *sme, u32 changed),
+ TP_ARGS(wiphy, netdev, sme, changed),
+ TP_STRUCT__entry(
+ WIPHY_ENTRY
+ NETDEV_ENTRY
+ __field(u32, changed)
+ ),
+ TP_fast_assign(
+ WIPHY_ASSIGN;
+ NETDEV_ASSIGN;
+ __entry->changed = changed;
+ ),
+ TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", parameters changed: %u",
+ WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->changed)
+);
+
TRACE_EVENT(rdev_set_cqm_rssi_config,
TP_PROTO(struct wiphy *wiphy,
struct net_device *netdev, s32 rssi_thold,
@@ -3030,6 +3048,25 @@
TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev),
TP_ARGS(wiphy, wdev)
);
+
+TRACE_EVENT(rdev_set_multicast_to_unicast,
+ TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+ const bool enabled),
+ TP_ARGS(wiphy, netdev, enabled),
+ TP_STRUCT__entry(
+ WIPHY_ENTRY
+ NETDEV_ENTRY
+ __field(bool, enabled)
+ ),
+ TP_fast_assign(
+ WIPHY_ASSIGN;
+ NETDEV_ASSIGN;
+ __entry->enabled = enabled;
+ ),
+ TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", unicast: %s",
+ WIPHY_PR_ARG, NETDEV_PR_ARG,
+ BOOL_TO_STR(__entry->enabled))
+);
#endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
#undef TRACE_INCLUDE_PATH
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 877e9d3..8ac413f 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -15,6 +15,7 @@
#include <linux/mpls.h>
#include <net/ndisc.h>
#include <linux/if_arp.h>
+#include <linux/gcd.h>
#include "core.h"
#include "rdev-ops.h"
@@ -935,7 +936,6 @@
{
struct cfg80211_event *ev;
unsigned long flags;
- const u8 *bssid = NULL;
spin_lock_irqsave(&wdev->event_lock, flags);
while (!list_empty(&wdev->event_list)) {
@@ -947,15 +947,10 @@
wdev_lock(wdev);
switch (ev->type) {
case EVENT_CONNECT_RESULT:
- if (!is_zero_ether_addr(ev->cr.bssid))
- bssid = ev->cr.bssid;
__cfg80211_connect_result(
- wdev->netdev, bssid,
- ev->cr.req_ie, ev->cr.req_ie_len,
- ev->cr.resp_ie, ev->cr.resp_ie_len,
- ev->cr.status,
- ev->cr.status == WLAN_STATUS_SUCCESS,
- ev->cr.bss);
+ wdev->netdev,
+ &ev->cr,
+ ev->cr.status == WLAN_STATUS_SUCCESS);
break;
case EVENT_ROAMED:
__cfg80211_roamed(wdev, ev->rm.bss, ev->rm.req_ie,
@@ -1559,47 +1554,53 @@
}
EXPORT_SYMBOL(ieee80211_chandef_to_operating_class);
+static void cfg80211_calculate_bi_data(struct wiphy *wiphy, u32 new_beacon_int,
+ u32 *beacon_int_gcd,
+ bool *beacon_int_different)
+{
+ struct wireless_dev *wdev;
+
+ *beacon_int_gcd = 0;
+ *beacon_int_different = false;
+
+ list_for_each_entry(wdev, &wiphy->wdev_list, list) {
+ if (!wdev->beacon_interval)
+ continue;
+
+ if (!*beacon_int_gcd) {
+ *beacon_int_gcd = wdev->beacon_interval;
+ continue;
+ }
+
+ if (wdev->beacon_interval == *beacon_int_gcd)
+ continue;
+
+ *beacon_int_different = true;
+ *beacon_int_gcd = gcd(*beacon_int_gcd, wdev->beacon_interval);
+ }
+
+ if (new_beacon_int && *beacon_int_gcd != new_beacon_int) {
+ if (*beacon_int_gcd)
+ *beacon_int_different = true;
+ *beacon_int_gcd = gcd(*beacon_int_gcd, new_beacon_int);
+ }
+}
+
int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
enum nl80211_iftype iftype, u32 beacon_int)
{
- struct wireless_dev *wdev;
- struct iface_combination_params params = {
- .beacon_int_gcd = beacon_int, /* GCD(n) = n */
- };
+ /*
+ * This is just a basic pre-condition check; if interface combinations
+ * are possible the driver must already be checking those with a call
+ * to cfg80211_check_combinations(), in which case we'll validate more
+ * through the cfg80211_calculate_bi_data() call and code in
+ * cfg80211_iter_combinations().
+ */
if (beacon_int < 10 || beacon_int > 10000)
return -EINVAL;
- params.iftype_num[iftype] = 1;
- list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
- if (!wdev->beacon_interval)
- continue;
-
- params.iftype_num[wdev->iftype]++;
- }
-
- list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
- u32 bi_prev = wdev->beacon_interval;
-
- if (!wdev->beacon_interval)
- continue;
-
- /* slight optimisation - skip identical BIs */
- if (wdev->beacon_interval == beacon_int)
- continue;
-
- params.beacon_int_different = true;
-
- /* Get the GCD */
- while (bi_prev != 0) {
- u32 tmp_bi = bi_prev;
-
- bi_prev = params.beacon_int_gcd % bi_prev;
- params.beacon_int_gcd = tmp_bi;
- }
- }
-
- return cfg80211_check_combinations(&rdev->wiphy, ¶ms);
+ return 0;
}
int cfg80211_iter_combinations(struct wiphy *wiphy,
@@ -1613,6 +1614,21 @@
int i, j, iftype;
int num_interfaces = 0;
u32 used_iftypes = 0;
+ u32 beacon_int_gcd;
+ bool beacon_int_different;
+
+ /*
+ * This is a bit strange, since the iteration used to rely only on
+ * the data given by the driver, but here it now relies on context,
+ * in form of the currently operating interfaces.
+ * This is OK for all current users, and saves us from having to
+ * push the GCD calculations into all the drivers.
+ * In the future, this should probably rely more on data that's in
+ * cfg80211 already - the only thing not would appear to be any new
+ * interfaces (while being brought up) and channel/radar data.
+ */
+ cfg80211_calculate_bi_data(wiphy, params->new_beacon_int,
+ &beacon_int_gcd, &beacon_int_different);
if (params->radar_detect) {
rcu_read_lock();
@@ -1675,12 +1691,11 @@
if ((all_iftypes & used_iftypes) != used_iftypes)
goto cont;
- if (params->beacon_int_gcd) {
+ if (beacon_int_gcd) {
if (c->beacon_int_min_gcd &&
- params->beacon_int_gcd < c->beacon_int_min_gcd)
- return -EINVAL;
- if (!c->beacon_int_min_gcd &&
- params->beacon_int_different)
+ beacon_int_gcd < c->beacon_int_min_gcd)
+ goto cont;
+ if (!c->beacon_int_min_gcd && beacon_int_different)
goto cont;
}
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index a0d45ef..cdfa754 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -2963,6 +2963,20 @@
# check we are in a valid source file if not then ignore this hunk
next if ($realfile !~ /\.(h|c|s|S|pl|sh|dtsi|dts)$/);
+# do DT checks:
+# * Property names should be lower-case
+# * Only newline after };
+
+ if ($realfile =~ /\.(dts|dtsi)$/ && $line =~ /^\+/) {
+ if($line =~ /\};.+$/) { # check for any characters after };
+ ERROR("DT_STYLE", "newline does not follow immediately after };\n" . $herecurr);
+ }
+
+ if($line =~ /[0-9a-zA-Z,\._\+\?#]+\s*=/ && $line !~ /[0-9a-z,\._\+\?#]+\s*=/) { # find property names with uppercase characters
+ ERROR("DT_PROPERTY_NAME", "property name is not lowercase\n" . $herecurr);
+ }
+ }
+
# line length limit (with some exclusions)
#
# There are a few types of lines that may extend beyond $max_line_length:
@@ -3654,7 +3668,7 @@
$fixedline =~ s/\s*=\s*$/ = {/;
fix_insert_line($fixlinenr, $fixedline);
$fixedline = $line;
- $fixedline =~ s/^(.\s*){\s*/$1/;
+ $fixedline =~ s/^(.\s*)\{\s*/$1/;
fix_insert_line($fixlinenr, $fixedline);
}
}
@@ -3995,7 +4009,7 @@
my $fixedline = rtrim($prevrawline) . " {";
fix_insert_line($fixlinenr, $fixedline);
$fixedline = $rawline;
- $fixedline =~ s/^(.\s*){\s*/$1\t/;
+ $fixedline =~ s/^(.\s*)\{\s*/$1\t/;
if ($fixedline !~ /^\+\s*$/) {
fix_insert_line($fixlinenr, $fixedline);
}
@@ -4484,7 +4498,7 @@
if (ERROR("SPACING",
"space required before the open brace '{'\n" . $herecurr) &&
$fix) {
- $fixed[$fixlinenr] =~ s/^(\+.*(?:do|\))){/$1 {/;
+ $fixed[$fixlinenr] =~ s/^(\+.*(?:do|\)))\{/$1 {/;
}
}
diff --git a/scripts/dtc/libfdt/fdt.c b/scripts/dtc/libfdt/fdt.c
index 22286a1..14fb793 100644
--- a/scripts/dtc/libfdt/fdt.c
+++ b/scripts/dtc/libfdt/fdt.c
@@ -71,6 +71,20 @@
return -FDT_ERR_BADMAGIC;
}
+ if (fdt_off_dt_struct(fdt) > (UINT_MAX - fdt_size_dt_struct(fdt)))
+ return FDT_ERR_BADOFFSET;
+
+ if (fdt_off_dt_strings(fdt) > (UINT_MAX - fdt_size_dt_strings(fdt)))
+ return FDT_ERR_BADOFFSET;
+
+ if ((fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt))
+ > fdt_totalsize(fdt))
+ return FDT_ERR_BADOFFSET;
+
+ if ((fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt))
+ > fdt_totalsize(fdt))
+ return FDT_ERR_BADOFFSET;
+
return 0;
}
diff --git a/scripts/dtc/libfdt/fdt_rw.c b/scripts/dtc/libfdt/fdt_rw.c
index 8be02b1..468e169 100644
--- a/scripts/dtc/libfdt/fdt_rw.c
+++ b/scripts/dtc/libfdt/fdt_rw.c
@@ -396,7 +396,7 @@
static void _fdt_packblocks(const char *old, char *new,
int mem_rsv_size, int struct_size)
{
- int mem_rsv_off, struct_off, strings_off;
+ uint32_t mem_rsv_off, struct_off, strings_off;
mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8);
struct_off = mem_rsv_off + mem_rsv_size;
diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh
old mode 100755
new mode 100644
index f742c65..1b9e67b
--- a/scripts/link-vmlinux.sh
+++ b/scripts/link-vmlinux.sh
@@ -145,6 +145,25 @@
${CC} ${aflags} -c -o ${2} ${afile}
}
+# Generates ${2} .o file with RTIC MP's from the ${1} object file (vmlinux)
+# ${3} the file name where the sizes of the RTIC MP structure are stored
+# just in case, save copy of the RTIC mp to ${4}
+# Note: RTIC_MPGEN has to be set if MPGen is available
+rtic_mp()
+{
+ # assume that RTIC_MP_O generation may fail
+ RTIC_MP_O=
+
+ ${RTIC_MPGEN} --objcopy="${OBJCOPY}" --objdump="${OBJDUMP}" \
+ --binpath='' --vmlinux=${1} --config=${KCONFIG_CONFIG} && \
+ cat rtic_mp.c | ${CC} -c -o ${2} -x c - && \
+ cp rtic_mp.c ${4} && \
+ ${NM} --print-size --size-sort ${2} > ${3} && \
+ RTIC_MP_O=${2}
+ # NM - save generated variable sizes for verification
+ # RTIC_MP_O is our retval - great success if set to generated .o file
+}
+
# Create map file with all symbols from ${1}
# See mksymap for additional details
mksysmap()
@@ -169,6 +188,8 @@
rm -f System.map
rm -f vmlinux
rm -f vmlinux.o
+ rm -f .tmp_rtic_mp_sz*
+ rm -f rtic_mp.*
}
on_exit()
@@ -231,6 +252,15 @@
# final build of init/
${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init GCC_PLUGINS_CFLAGS="${GCC_PLUGINS_CFLAGS}"
+# Generate RTIC MP placeholder compile unit of the correct size
+# and add it to the list of link objects
+# this needs to be done before generating kallsyms
+if [ ! -z ${RTIC_MPGEN+x} ]; then
+ rtic_mp vmlinux.o rtic_mp.o .tmp_rtic_mp_sz1 .tmp_rtic_mp1.c
+ KBUILD_VMLINUX_MAIN+=" "
+ KBUILD_VMLINUX_MAIN+=$RTIC_MP_O
+fi
+
kallsymso=""
kallsyms_vmlinux=""
if [ -n "${CONFIG_KALLSYMS}" ]; then
@@ -276,6 +306,18 @@
fi
fi
+# Update RTIC MP object by replacing the place holder
+# with actual MP data of the same size
+# Also double check that object size did not change
+if [ ! -z ${RTIC_MPGEN+x} ]; then
+ rtic_mp "${kallsyms_vmlinux}" rtic_mp.o .tmp_rtic_mp_sz2 \
+ .tmp_rtic_mp2.c
+ if ! cmp -s .tmp_rtic_mp_sz1 .tmp_rtic_mp_sz2; then
+ echo >&2 'ERROR: RTIC MP object files size mismatch'
+ exit 1
+ fi
+fi
+
info LD vmlinux
vmlinux_link "${kallsymso}" vmlinux
diff --git a/security/Kconfig b/security/Kconfig
index 59aea7d..5693989 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -40,6 +40,11 @@
If you are unsure how to answer this question, answer N.
+config SECURITY_WRITABLE_HOOKS
+ depends on SECURITY
+ bool
+ default n
+
config SECURITYFS
bool "Enable the securityfs filesystem"
help
@@ -167,6 +172,13 @@
been removed. This config is intended to be used only while
trying to find such users.
+config FORTIFY_SOURCE
+ bool "Harden common str/mem functions against buffer overflows"
+ depends on ARCH_HAS_FORTIFY_SOURCE
+ help
+ Detect overflows of buffers in common string and memory functions
+ where the compiler can determine and validate the buffer sizes.
+
source security/selinux/Kconfig
source security/smack/Kconfig
source security/tomoyo/Kconfig
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 41b8cb1..57bc405 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -584,7 +584,7 @@
return error;
}
-static struct security_hook_list apparmor_hooks[] = {
+static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check),
LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme),
LSM_HOOK_INIT(capget, apparmor_capget),
diff --git a/security/commoncap.c b/security/commoncap.c
index a8e4aac..3e44d01 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -1081,7 +1081,7 @@
#ifdef CONFIG_SECURITY
-struct security_hook_list capability_hooks[] = {
+struct security_hook_list capability_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(capable, cap_capable),
LSM_HOOK_INIT(settime, cap_settime),
LSM_HOOK_INIT(ptrace_access_check, cap_ptrace_access_check),
diff --git a/security/loadpin/loadpin.c b/security/loadpin/loadpin.c
index 89a46f1..afd4ab9 100644
--- a/security/loadpin/loadpin.c
+++ b/security/loadpin/loadpin.c
@@ -174,7 +174,7 @@
return 0;
}
-static struct security_hook_list loadpin_hooks[] = {
+static struct security_hook_list loadpin_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(sb_free_security, loadpin_sb_free_security),
LSM_HOOK_INIT(kernel_read_file, loadpin_read_file),
};
diff --git a/security/security.c b/security/security.c
index 1ba5274..6a7b359 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1590,7 +1590,7 @@
}
#endif /* CONFIG_AUDIT */
-struct security_hook_heads security_hook_heads = {
+struct security_hook_heads security_hook_heads __lsm_ro_after_init = {
.binder_set_context_mgr =
LIST_HEAD_INIT(security_hook_heads.binder_set_context_mgr),
.binder_transaction =
diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig
index ea7e3ef..8af7a69 100644
--- a/security/selinux/Kconfig
+++ b/security/selinux/Kconfig
@@ -40,6 +40,7 @@
config SECURITY_SELINUX_DISABLE
bool "NSA SELinux runtime disable"
depends on SECURITY_SELINUX
+ select SECURITY_WRITABLE_HOOKS
default n
help
This option enables writing to a selinuxfs node 'disable', which
@@ -50,6 +51,11 @@
portability across platforms where boot parameters are difficult
to employ.
+ NOTE: selecting this option will disable the '__ro_after_init'
+ kernel hardening feature for security hooks. Please consider
+ using the selinux=0 boot parameter instead of enabling this
+ option.
+
If you are unsure how to answer this question, answer N.
config SECURITY_SELINUX_DEVELOP
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 20b2e7d..e26ecb0 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -6079,7 +6079,7 @@
#endif
-static struct security_hook_list selinux_hooks[] = {
+static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr),
LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction),
LSM_HOOK_INIT(binder_transfer_binder, selinux_binder_transfer_binder),
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 1cb0602..b75c31a 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -4611,7 +4611,7 @@
return 0;
}
-static struct security_hook_list smack_hooks[] = {
+static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(ptrace_access_check, smack_ptrace_access_check),
LSM_HOOK_INIT(ptrace_traceme, smack_ptrace_traceme),
LSM_HOOK_INIT(syslog, smack_syslog),
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c
index 75c9987..f1dce33 100644
--- a/security/tomoyo/tomoyo.c
+++ b/security/tomoyo/tomoyo.c
@@ -496,7 +496,7 @@
* tomoyo_security_ops is a "struct security_operations" which is used for
* registering TOMOYO.
*/
-static struct security_hook_list tomoyo_hooks[] = {
+static struct security_hook_list tomoyo_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(cred_alloc_blank, tomoyo_cred_alloc_blank),
LSM_HOOK_INIT(cred_prepare, tomoyo_cred_prepare),
LSM_HOOK_INIT(cred_transfer, tomoyo_cred_transfer),
diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c
index 0309f21..70aa64c 100644
--- a/security/yama/yama_lsm.c
+++ b/security/yama/yama_lsm.c
@@ -414,7 +414,7 @@
return rc;
}
-static struct security_hook_list yama_hooks[] = {
+static struct security_hook_list yama_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(ptrace_access_check, yama_ptrace_access_check),
LSM_HOOK_INIT(ptrace_traceme, yama_ptrace_traceme),
LSM_HOOK_INIT(task_prctl, yama_task_prctl),
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index a472bf2..01c67be 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -1159,7 +1159,7 @@
config SND_SOC_MSM_HDMI_CODEC_RX
bool "HDMI Audio Playback"
- depends on FB_MSM_MDSS_HDMI_PANEL && (SND_SOC_APQ8084 || SND_SOC_MSM8994 || SND_SOC_MSM8996 || SND_SOC_MSM8998 || SND_SOC_SDM660_COMMON)
+ depends on FB_MSM_MDSS_HDMI_PANEL && (SND_SOC_APQ8084 || SND_SOC_MSM8994 || SND_SOC_MSM8996 || SND_SOC_MSM8998 || SND_SOC_660)
help
HDMI audio drivers should be built only if the platform
supports hdmi panel.
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index d8b5ae6..daf05d8 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -162,14 +162,7 @@
snd-soc-wcd934x-objs := wcd934x.o
snd-soc-wcd9xxx-objs := wcd9xxx-common-v2.o wcd9xxx-resmgr-v2.o \
wcdcal-hwdep.o wcd-dsp-mgr.o wcd-dsp-utils.o \
- wcd9xxx-soc-init.o
-ifeq ($(CONFIG_COMMON_CLK_MSM), y)
- snd-soc-wcd9xxx-objs += audio-ext-clk.o
-endif
-
-ifeq ($(CONFIG_COMMON_CLK_QCOM), y)
- snd-soc-wcd9xxx-objs += audio-ext-clk-up.o
-endif
+ wcd9xxx-soc-init.o audio-ext-clk-up.o
snd-soc-wcd-cpe-objs := wcd_cpe_services.o wcd_cpe_core.o
snd-soc-wsa881x-objs := wsa881x.o wsa881x-tables.o wsa881x-regmap.o wsa881x-temp-sensor.o
snd-soc-wcd-mbhc-objs := wcd-mbhc-v2.o
diff --git a/sound/soc/codecs/audio-ext-clk.c b/sound/soc/codecs/audio-ext-clk.c
deleted file mode 100644
index 72f16f5..0000000
--- a/sound/soc/codecs/audio-ext-clk.c
+++ /dev/null
@@ -1,348 +0,0 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. 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 and
- * only 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/kernel.h>
-#include <linux/init.h>
-#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/clk.h>
-#include <linux/clk/msm-clk-provider.h>
-#include <linux/clk/msm-clk.h>
-#include <linux/platform_device.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
-#include <dt-bindings/clock/audio-ext-clk.h>
-#include <sound/q6afe-v2.h>
-#include "audio-ext-clk-up.h"
-
-struct pinctrl_info {
- struct pinctrl *pinctrl;
- struct pinctrl_state *sleep;
- struct pinctrl_state *active;
-};
-
-struct audio_ext_ap_clk {
- bool enabled;
- int gpio;
- struct clk c;
-};
-
-struct audio_ext_pmi_clk {
- int gpio;
- struct clk c;
-};
-
-struct audio_ext_ap_clk2 {
- bool enabled;
- struct pinctrl_info pnctrl_info;
- struct clk c;
-};
-
-static struct afe_clk_set clk2_config = {
- Q6AFE_LPASS_CLK_CONFIG_API_VERSION,
- Q6AFE_LPASS_CLK_ID_SPEAKER_I2S_OSR,
- Q6AFE_LPASS_IBIT_CLK_11_P2896_MHZ,
- Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
- Q6AFE_LPASS_CLK_ROOT_DEFAULT,
- 0,
-};
-
-static inline struct audio_ext_ap_clk *to_audio_ap_clk(struct clk *clk)
-{
- return container_of(clk, struct audio_ext_ap_clk, c);
-}
-
-static int audio_ext_clk_prepare(struct clk *clk)
-{
- struct audio_ext_ap_clk *audio_clk = to_audio_ap_clk(clk);
-
- pr_debug("%s: gpio: %d\n", __func__, audio_clk->gpio);
- if (gpio_is_valid(audio_clk->gpio))
- return gpio_direction_output(audio_clk->gpio, 1);
- return 0;
-}
-
-static void audio_ext_clk_unprepare(struct clk *clk)
-{
- struct audio_ext_ap_clk *audio_clk = to_audio_ap_clk(clk);
-
- pr_debug("%s: gpio: %d\n", __func__, audio_clk->gpio);
- if (gpio_is_valid(audio_clk->gpio))
- gpio_direction_output(audio_clk->gpio, 0);
-}
-
-static inline struct audio_ext_ap_clk2 *to_audio_ap_clk2(struct clk *clk)
-{
- return container_of(clk, struct audio_ext_ap_clk2, c);
-}
-
-static int audio_ext_clk2_prepare(struct clk *clk)
-{
- struct audio_ext_ap_clk2 *audio_clk2 = to_audio_ap_clk2(clk);
- struct pinctrl_info *pnctrl_info = &audio_clk2->pnctrl_info;
- int ret;
-
-
- if (!pnctrl_info->pinctrl || !pnctrl_info->active)
- return 0;
-
- ret = pinctrl_select_state(pnctrl_info->pinctrl,
- pnctrl_info->active);
- if (ret) {
- pr_err("%s: active state select failed with %d\n",
- __func__, ret);
- return -EIO;
- }
-
- clk2_config.enable = 1;
- ret = afe_set_lpass_clk_cfg(IDX_RSVD_3, &clk2_config);
- if (ret < 0) {
- pr_err("%s: failed to set clock, ret = %d\n", __func__, ret);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static void audio_ext_clk2_unprepare(struct clk *clk)
-{
- struct audio_ext_ap_clk2 *audio_clk2 = to_audio_ap_clk2(clk);
- struct pinctrl_info *pnctrl_info = &audio_clk2->pnctrl_info;
- int ret;
-
- if (!pnctrl_info->pinctrl || !pnctrl_info->sleep)
- return;
-
- ret = pinctrl_select_state(pnctrl_info->pinctrl,
- pnctrl_info->sleep);
- if (ret)
- pr_err("%s: sleep state select failed with %d\n",
- __func__, ret);
-
- clk2_config.enable = 0;
- ret = afe_set_lpass_clk_cfg(IDX_RSVD_3, &clk2_config);
- if (ret < 0)
- pr_err("%s: failed to reset clock, ret = %d\n", __func__, ret);
-}
-
-static const struct clk_ops audio_ext_ap_clk_ops = {
- .prepare = audio_ext_clk_prepare,
- .unprepare = audio_ext_clk_unprepare,
-};
-
-static const struct clk_ops audio_ext_ap_clk2_ops = {
- .prepare = audio_ext_clk2_prepare,
- .unprepare = audio_ext_clk2_unprepare,
-};
-
-static struct audio_ext_pmi_clk audio_pmi_clk = {
- .gpio = -EINVAL,
- .c = {
- .dbg_name = "audio_ext_pmi_clk",
- .ops = &clk_ops_dummy,
- CLK_INIT(audio_pmi_clk.c),
- },
-};
-
-static struct audio_ext_pmi_clk audio_pmi_lnbb_clk = {
- .gpio = -EINVAL,
- .c = {
- .dbg_name = "audio_ext_pmi_lnbb_clk",
- .ops = &clk_ops_dummy,
- CLK_INIT(audio_pmi_lnbb_clk.c),
- },
-};
-
-static struct audio_ext_ap_clk audio_ap_clk = {
- .gpio = -EINVAL,
- .c = {
- .dbg_name = "audio_ext_ap_clk",
- .ops = &audio_ext_ap_clk_ops,
- CLK_INIT(audio_ap_clk.c),
- },
-};
-
-static struct audio_ext_ap_clk2 audio_ap_clk2 = {
- .c = {
- .dbg_name = "audio_ext_ap_clk2",
- .ops = &audio_ext_ap_clk2_ops,
- CLK_INIT(audio_ap_clk2.c),
- },
-};
-
-static struct clk_lookup audio_ref_clock[] = {
- CLK_LIST(audio_ap_clk),
- CLK_LIST(audio_pmi_clk),
- CLK_LIST(audio_pmi_lnbb_clk),
- CLK_LIST(audio_ap_clk2),
-};
-
-static int audio_get_pinctrl(struct platform_device *pdev)
-{
- struct pinctrl_info *pnctrl_info;
- struct pinctrl *pinctrl;
- int ret;
-
- pnctrl_info = &audio_ap_clk2.pnctrl_info;
-
- if (pnctrl_info->pinctrl) {
- dev_dbg(&pdev->dev, "%s: already requested before\n",
- __func__);
- return -EINVAL;
- }
-
- pinctrl = devm_pinctrl_get(&pdev->dev);
- if (IS_ERR_OR_NULL(pinctrl)) {
- dev_dbg(&pdev->dev, "%s: Unable to get pinctrl handle\n",
- __func__);
- return -EINVAL;
- }
- pnctrl_info->pinctrl = pinctrl;
- /* get all state handles from Device Tree */
- pnctrl_info->sleep = pinctrl_lookup_state(pinctrl, "sleep");
- if (IS_ERR(pnctrl_info->sleep)) {
- dev_err(&pdev->dev, "%s: could not get sleep pinstate\n",
- __func__);
- goto err;
- }
- pnctrl_info->active = pinctrl_lookup_state(pinctrl, "active");
- if (IS_ERR(pnctrl_info->active)) {
- dev_err(&pdev->dev, "%s: could not get active pinstate\n",
- __func__);
- goto err;
- }
- /* Reset the TLMM pins to a default state */
- ret = pinctrl_select_state(pnctrl_info->pinctrl,
- pnctrl_info->sleep);
- if (ret) {
- dev_err(&pdev->dev, "%s: Disable TLMM pins failed with %d\n",
- __func__, ret);
- goto err;
- }
- return 0;
-
-err:
- devm_pinctrl_put(pnctrl_info->pinctrl);
- return -EINVAL;
-}
-
-static int audio_ref_clk_probe(struct platform_device *pdev)
-{
- int clk_gpio;
- int ret;
- struct clk *audio_clk;
-
- clk_gpio = of_get_named_gpio(pdev->dev.of_node,
- "qcom,audio-ref-clk-gpio", 0);
- if (clk_gpio > 0) {
- ret = gpio_request(clk_gpio, "EXT_CLK");
- if (ret) {
- dev_err(&pdev->dev,
- "Request ext clk gpio failed %d, err:%d\n",
- clk_gpio, ret);
- goto err;
- }
- if (of_property_read_bool(pdev->dev.of_node,
- "qcom,node_has_rpm_clock")) {
- audio_clk = clk_get(&pdev->dev, NULL);
- if (IS_ERR(audio_clk)) {
- dev_err(&pdev->dev, "Failed to get RPM div clk\n");
- ret = PTR_ERR(audio_clk);
- goto err_gpio;
- }
- audio_pmi_clk.c.parent = audio_clk;
- audio_pmi_clk.gpio = clk_gpio;
- } else
- audio_ap_clk.gpio = clk_gpio;
-
- } else {
- if (of_property_read_bool(pdev->dev.of_node,
- "qcom,node_has_rpm_clock")) {
- audio_clk = clk_get(&pdev->dev, NULL);
- if (IS_ERR(audio_clk)) {
- dev_err(&pdev->dev, "Failed to get lnbbclk2\n");
- ret = PTR_ERR(audio_clk);
- goto err;
- }
- audio_pmi_lnbb_clk.c.parent = audio_clk;
- audio_pmi_lnbb_clk.gpio = -EINVAL;
- }
- }
-
- ret = audio_get_pinctrl(pdev);
- if (ret)
- dev_dbg(&pdev->dev, "%s: Parsing pinctrl failed\n",
- __func__);
-
- ret = of_msm_clock_register(pdev->dev.of_node, audio_ref_clock,
- ARRAY_SIZE(audio_ref_clock));
- if (ret) {
- dev_err(&pdev->dev, "%s: audio ref clock register failed\n",
- __func__);
- goto err_gpio;
- }
-
- return 0;
-
-err_gpio:
- gpio_free(clk_gpio);
-
-err:
- return ret;
-}
-
-static int audio_ref_clk_remove(struct platform_device *pdev)
-{
- struct pinctrl_info *pnctrl_info = &audio_ap_clk2.pnctrl_info;
-
- if (audio_pmi_clk.gpio > 0)
- gpio_free(audio_pmi_clk.gpio);
- else if (audio_ap_clk.gpio > 0)
- gpio_free(audio_ap_clk.gpio);
-
- if (pnctrl_info->pinctrl) {
- devm_pinctrl_put(pnctrl_info->pinctrl);
- pnctrl_info->pinctrl = NULL;
- }
-
- return 0;
-}
-
-static const struct of_device_id audio_ref_clk_match[] = {
- {.compatible = "qcom,audio-ref-clk"},
- {}
-};
-MODULE_DEVICE_TABLE(of, audio_ref_clk_match);
-
-static struct platform_driver audio_ref_clk_driver = {
- .driver = {
- .name = "audio-ref-clk",
- .owner = THIS_MODULE,
- .of_match_table = audio_ref_clk_match,
- },
- .probe = audio_ref_clk_probe,
- .remove = audio_ref_clk_remove,
-};
-
-int audio_ref_clk_platform_init(void)
-{
- return platform_driver_register(&audio_ref_clk_driver);
-}
-
-void audio_ref_clk_platform_exit(void)
-{
- platform_driver_unregister(&audio_ref_clk_driver);
-}
-
-MODULE_DESCRIPTION("Audio Ref Clock module platform driver");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c b/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c
index 34227a0..a253aea 100644
--- a/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c
+++ b/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c
@@ -1376,15 +1376,19 @@
struct snd_info_entry *version_entry;
struct msm_sdw_priv *msm_sdw;
struct snd_soc_card *card;
+ char name[80];
if (!codec_root || !codec)
return -EINVAL;
msm_sdw = snd_soc_codec_get_drvdata(codec);
card = codec->component.card;
+
+ snprintf(name, sizeof(name), "%x.%s", (u32)msm_sdw->sdw_base_addr,
+ "msm-sdw-codec");
msm_sdw->entry = snd_info_create_subdir(codec_root->module,
- "152c1000.msm-sdw-codec",
- codec_root);
+ (const char *)name,
+ codec_root);
if (!msm_sdw->entry) {
dev_err(codec->dev, "%s: failed to create msm_sdw entry\n",
__func__);
diff --git a/sound/soc/codecs/wcd-dsp-mgr.c b/sound/soc/codecs/wcd-dsp-mgr.c
index a6d46ae..6cc9f8c 100644
--- a/sound/soc/codecs/wcd-dsp-mgr.c
+++ b/sound/soc/codecs/wcd-dsp-mgr.c
@@ -417,22 +417,23 @@
/* Go through the list of segments and download one by one */
list_for_each_entry(seg, wdsp->seg_list, list) {
ret = wdsp_load_each_segment(wdsp, seg);
- if (ret < 0) {
- wdsp_broadcast_event_downseq(wdsp,
- WDSP_EVENT_DLOAD_FAILED,
- NULL);
+ if (ret)
goto dload_error;
- }
}
+ /* Flush the list before setting status and notifying components */
+ wdsp_flush_segment_list(wdsp->seg_list);
+
WDSP_SET_STATUS(wdsp, status);
/* Notify all components that image is downloaded */
wdsp_broadcast_event_downseq(wdsp, post, NULL);
+done:
+ return ret;
dload_error:
wdsp_flush_segment_list(wdsp->seg_list);
-done:
+ wdsp_broadcast_event_downseq(wdsp, WDSP_EVENT_DLOAD_FAILED, NULL);
return ret;
}
@@ -486,10 +487,14 @@
/* Make sure wdsp is in good state */
if (!WDSP_STATUS_IS_SET(wdsp, WDSP_STATUS_CODE_DLOADED)) {
WDSP_ERR(wdsp, "WDSP in invalid state 0x%x", wdsp->status);
- ret = -EINVAL;
- goto done;
+ return -EINVAL;
}
+ /*
+ * Acquire SSR mutex lock to make sure enablement of DSP
+ * does not race with SSR handling.
+ */
+ WDSP_MGR_MUTEX_LOCK(wdsp, wdsp->ssr_mutex);
/* Download the read-write sections of image */
ret = wdsp_download_segments(wdsp, WDSP_ELF_FLAG_WRITE);
if (ret < 0) {
@@ -510,6 +515,7 @@
wdsp_broadcast_event_downseq(wdsp, WDSP_EVENT_POST_BOOTUP, NULL);
WDSP_SET_STATUS(wdsp, WDSP_STATUS_BOOTED);
done:
+ WDSP_MGR_MUTEX_UNLOCK(wdsp, wdsp->ssr_mutex);
return ret;
}
diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
index a6a5350..3891624 100644
--- a/sound/soc/codecs/wcd9335.c
+++ b/sound/soc/codecs/wcd9335.c
@@ -112,7 +112,7 @@
/* Convert from vout ctl to micbias voltage in mV */
#define WCD_VOUT_CTL_TO_MICB(v) (1000 + v * 50)
-#define TASHA_ZDET_NUM_MEASUREMENTS 150
+#define TASHA_ZDET_NUM_MEASUREMENTS 900
#define TASHA_MBHC_GET_C1(c) ((c & 0xC000) >> 14)
#define TASHA_MBHC_GET_X1(x) (x & 0x3FFF)
/* z value compared in milliOhm */
diff --git a/sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.c b/sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.c
index 8da0425..b62f26c 100644
--- a/sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.c
+++ b/sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.c
@@ -763,10 +763,6 @@
case WDSP_EVENT_DLOAD_FAILED:
case WDSP_EVENT_POST_SHUTDOWN:
- if (event == WDSP_EVENT_POST_DLOAD_CODE)
- /* Mark DSP online since code download is complete */
- wcd_cntl_change_online_state(cntl, 1);
-
/* Disable CPAR */
wcd_cntl_cpar_ctrl(cntl, false);
/* Disable all the clocks */
@@ -775,6 +771,10 @@
dev_err(codec->dev,
"%s: Failed to disable clocks, err = %d\n",
__func__, ret);
+
+ if (event == WDSP_EVENT_POST_DLOAD_CODE)
+ /* Mark DSP online since code download is complete */
+ wcd_cntl_change_online_state(cntl, 1);
break;
case WDSP_EVENT_PRE_DLOAD_DATA:
diff --git a/sound/soc/codecs/wcd934x/wcd934x-mbhc.c b/sound/soc/codecs/wcd934x/wcd934x-mbhc.c
index ea19caa..bf6e7a1 100644
--- a/sound/soc/codecs/wcd934x/wcd934x-mbhc.c
+++ b/sound/soc/codecs/wcd934x/wcd934x-mbhc.c
@@ -44,7 +44,7 @@
/* Z floating defined in ohms */
#define TAVIL_ZDET_FLOATING_IMPEDANCE 0x0FFFFFFE
-#define TAVIL_ZDET_NUM_MEASUREMENTS 150
+#define TAVIL_ZDET_NUM_MEASUREMENTS 900
#define TAVIL_MBHC_GET_C1(c) ((c & 0xC000) >> 14)
#define TAVIL_MBHC_GET_X1(x) (x & 0x3FFF)
/* Z value compared in milliOhm */
diff --git a/sound/soc/codecs/wsa881x.h b/sound/soc/codecs/wsa881x.h
index be234ac..fbc60d8 100644
--- a/sound/soc/codecs/wsa881x.h
+++ b/sound/soc/codecs/wsa881x.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. 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 and
@@ -20,9 +20,10 @@
#define WSA881X_MAX_SWR_PORTS 4
+#if IS_ENABLED(CONFIG_SND_SOC_WSA881X)
extern int wsa881x_set_channel_map(struct snd_soc_codec *codec, u8 *port,
- u8 num_port, unsigned int *ch_mask,
- unsigned int *ch_rate);
+ u8 num_port, unsigned int *ch_mask,
+ unsigned int *ch_rate);
extern const u8 wsa881x_reg_readable[WSA881X_CACHE_SIZE];
extern struct regmap_config wsa881x_regmap_config;
@@ -31,4 +32,25 @@
struct snd_soc_codec *codec);
void wsa881x_regmap_defaults(struct regmap *regmap, u8 version);
+#else
+extern int wsa881x_set_channel_map(struct snd_soc_codec *codec, u8 *port,
+ u8 num_port, unsigned int *ch_mask,
+ unsigned int *ch_rate)
+{
+ return 0;
+}
+
+extern int wsa881x_codec_info_create_codec_entry(
+ struct snd_info_entry *codec_root,
+ struct snd_soc_codec *codec)
+{
+ return 0;
+}
+
+void wsa881x_regmap_defaults(struct regmap *regmap, u8 version)
+{
+}
+
+#endif
+
#endif /* _WSA881X_H */
diff --git a/sound/soc/msm/Kconfig b/sound/soc/msm/Kconfig
index abadd08..66ecd6a 100644
--- a/sound/soc/msm/Kconfig
+++ b/sound/soc/msm/Kconfig
@@ -160,34 +160,6 @@
the machine driver and the corresponding
DAI-links
-config SND_SOC_MSM8996
- tristate "SoC Machine driver for MSM8996 boards"
- depends on ARCH_MSM8996
- select SND_SOC_COMPRESS
- select SND_SOC_QDSP6V2
- select SND_SOC_MSM_STUB
- select SND_SOC_MSM_HOSTLESS_PCM
- select SND_DYNAMIC_MINORS
- select MSM_QDSP6_APRV2
- select MSM_QDSP6V2_CODECS
- select SND_SOC_WCD9335
- select SND_SOC_WSA881X
- select SND_SOC_MSM_HDMI_CODEC_RX
- select DTS_SRS_TM
- select QTI_PP
- select QTI_PP_AUDIOSPHERE
- select SND_SOC_CPE
- select MSM_ULTRASOUND
- select DOLBY_DS2
- select SND_HWDEP
- select DTS_EAGLE
- help
- To add support for SoC audio on MSM8996.
- This will enable sound soc drivers which
- interfaces with DSP, also it will enable
- the machine driver and the corresponding
- DAI-links
-
config SND_SOC_MACHINE_MSM8998
tristate "SoC Machine driver for MSM8998 boards"
select SND_SOC_WSA881X
@@ -230,7 +202,7 @@
config SND_SOC_660
tristate "SoC Machine driver for SDM660/670 boards"
- depends on ARCH_SDM660 || ARCH_SDM670
+ depends on ARCH_QCOM
select SND_SOC_INT_CODEC
select SND_SOC_EXT_CODEC
help
diff --git a/sound/soc/msm/Makefile b/sound/soc/msm/Makefile
index caf8843..93fddb5 100644
--- a/sound/soc/msm/Makefile
+++ b/sound/soc/msm/Makefile
@@ -12,17 +12,13 @@
snd-soc-cpe-objs := msm-cpe-lsm.o
obj-$(CONFIG_SND_SOC_CPE) += snd-soc-cpe.o
-# for MSM8996 sound card driver
-snd-soc-msm8996-objs := msm8996.o
-obj-$(CONFIG_SND_SOC_MSM8996) += snd-soc-msm8996.o
-
# for MSM8998 sound card driver
snd-soc-msm8998-objs := msm8998.o
obj-$(CONFIG_SND_SOC_MACHINE_MSM8998) += snd-soc-msm8998.o
# for SDM660 sound card driver
snd-soc-sdm660-common-objs := sdm660-common.o
-obj-$(CONFIG_SND_SOC_SDM660_COMMON) += snd-soc-sdm660-common.o
+obj-$(CONFIG_SND_SOC_660) += snd-soc-sdm660-common.o
# for SDM660 sound card driver
snd-soc-int-codec-objs := sdm660-internal.o
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 30a4d59..89a9cc2 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -2376,8 +2376,20 @@
.rate_min = 8000,
.rate_max = 384000,
},
+ .capture = {
+ .stream_name = "MultiMedia10 Capture",
+ .aif_name = "MM_UL10",
+ .rates = (SNDRV_PCM_RATE_8000_48000 |
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
.ops = &msm_fe_Multimedia_dai_ops,
- .compress_new = snd_soc_new_compress,
.name = "MultiMedia10",
.probe = fe_dai_probe,
},
diff --git a/sound/soc/msm/msm8996.c b/sound/soc/msm/msm8996.c
deleted file mode 100644
index 0890037..0000000
--- a/sound/soc/msm/msm8996.c
+++ /dev/null
@@ -1,4007 +0,0 @@
-/*
- * Copyright (c) 2014-2017, The Linux Foundation. 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 and
- * only 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/clk.h>
-#include <linux/delay.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/regulator/consumer.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/switch.h>
-#include <linux/input.h>
-#include <sound/core.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-#include <sound/pcm.h>
-#include <sound/jack.h>
-#include <sound/q6afe-v2.h>
-#include <sound/q6core.h>
-#include <sound/pcm_params.h>
-#include <sound/info.h>
-#include <device_event.h>
-#include "qdsp6v2/msm-pcm-routing-v2.h"
-#include "../codecs/wcd9xxx-common.h"
-#include "../codecs/wcd9330.h"
-#include "../codecs/wcd9335.h"
-#include "../codecs/wsa881x.h"
-
-#define DRV_NAME "msm8996-asoc-snd"
-
-#define SAMPLING_RATE_8KHZ 8000
-#define SAMPLING_RATE_16KHZ 16000
-#define SAMPLING_RATE_32KHZ 32000
-#define SAMPLING_RATE_48KHZ 48000
-#define SAMPLING_RATE_96KHZ 96000
-#define SAMPLING_RATE_192KHZ 192000
-#define SAMPLING_RATE_44P1KHZ 44100
-
-#define MSM8996_SPK_ON 1
-#define MSM8996_HIFI_ON 1
-
-#define WCD9XXX_MBHC_DEF_BUTTONS 8
-#define WCD9XXX_MBHC_DEF_RLOADS 5
-#define CODEC_EXT_CLK_RATE 9600000
-#define ADSP_STATE_READY_TIMEOUT_MS 3000
-#define DEV_NAME_STR_LEN 32
-
-#define WSA8810_NAME_1 "wsa881x.20170211"
-#define WSA8810_NAME_2 "wsa881x.20170212"
-
-static int slim0_rx_sample_rate = SAMPLING_RATE_48KHZ;
-static int slim0_tx_sample_rate = SAMPLING_RATE_48KHZ;
-static int slim1_tx_sample_rate = SAMPLING_RATE_48KHZ;
-static int slim0_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
-static int slim0_tx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
-static int slim1_tx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
-static int hdmi_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
-static int msm8996_auxpcm_rate = SAMPLING_RATE_8KHZ;
-static int slim5_rx_sample_rate = SAMPLING_RATE_48KHZ;
-static int slim5_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
-static int slim6_rx_sample_rate = SAMPLING_RATE_48KHZ;
-static int slim6_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
-
-static struct platform_device *spdev;
-static int ext_us_amp_gpio = -1;
-static int msm8996_spk_control = 1;
-static int msm_slim_0_rx_ch = 1;
-static int msm_slim_0_tx_ch = 1;
-static int msm_slim_1_tx_ch = 1;
-static int msm_slim_5_rx_ch = 1;
-static int msm_slim_6_rx_ch = 1;
-static int msm_hifi_control;
-static int msm_vi_feed_tx_ch = 2;
-
-static int msm_hdmi_rx_ch = 2;
-static int msm_proxy_rx_ch = 2;
-static int hdmi_rx_sample_rate = SAMPLING_RATE_48KHZ;
-static int msm_tert_mi2s_tx_ch = 2;
-
-static bool codec_reg_done;
-
-static const char *const hifi_function[] = {"Off", "On"};
-static const char *const pin_states[] = {"Disable", "active"};
-static const char *const spk_function[] = {"Off", "On"};
-static const char *const slim0_rx_ch_text[] = {"One", "Two"};
-static const char *const slim5_rx_ch_text[] = {"One", "Two"};
-static const char *const slim6_rx_ch_text[] = {"One", "Two"};
-static const char *const slim0_tx_ch_text[] = {"One", "Two", "Three", "Four",
- "Five", "Six", "Seven",
- "Eight"};
-static const char *const vi_feed_ch_text[] = {"One", "Two"};
-static char const *hdmi_rx_ch_text[] = {"Two", "Three", "Four", "Five",
- "Six", "Seven", "Eight"};
-static char const *rx_bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE"};
-static char const *slim5_rx_bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE"};
-static char const *slim6_rx_bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE"};
-static char const *slim0_rx_sample_rate_text[] = {"KHZ_48", "KHZ_96",
- "KHZ_192", "KHZ_44P1", "KHZ_8",
- "KHZ_16", "KHZ_32"};
-static char const *slim5_rx_sample_rate_text[] = {"KHZ_48", "KHZ_96",
- "KHZ_192", "KHZ_44P1"};
-static char const *slim6_rx_sample_rate_text[] = {"KHZ_48", "KHZ_96",
- "KHZ_192", "KHZ_44P1"};
-static const char *const proxy_rx_ch_text[] = {"One", "Two", "Three", "Four",
- "Five", "Six", "Seven", "Eight"};
-
-static char const *hdmi_rx_sample_rate_text[] = {"KHZ_48", "KHZ_96",
- "KHZ_192"};
-
-static const char *const auxpcm_rate_text[] = {"8000", "16000"};
-static const struct soc_enum msm8996_auxpcm_enum[] = {
- SOC_ENUM_SINGLE_EXT(2, auxpcm_rate_text),
-};
-
-static struct afe_clk_set mi2s_tx_clk = {
- AFE_API_VERSION_I2S_CONFIG,
- Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT,
- Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
- Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
- Q6AFE_LPASS_CLK_ROOT_DEFAULT,
- 0,
-};
-
-struct msm8996_wsa881x_dev_info {
- struct device_node *of_node;
- u32 index;
-};
-
-static struct snd_soc_aux_dev *msm8996_aux_dev;
-static struct snd_soc_codec_conf *msm8996_codec_conf;
-
-struct msm8996_asoc_mach_data {
- u32 mclk_freq;
- int us_euro_gpio;
- int hph_en1_gpio;
- int hph_en0_gpio;
- struct snd_info_entry *codec_root;
-};
-
-struct msm8996_asoc_wcd93xx_codec {
- void* (*get_afe_config_fn)(struct snd_soc_codec *codec,
- enum afe_config_type config_type);
- void (*mbhc_hs_detect_exit)(struct snd_soc_codec *codec);
-};
-
-static struct msm8996_asoc_wcd93xx_codec msm8996_codec_fn;
-
-struct msm8996_liquid_dock_dev {
- int dock_plug_gpio;
- int dock_plug_irq;
- int dock_plug_det;
- struct work_struct irq_work;
- struct switch_dev audio_sdev;
-};
-static struct msm8996_liquid_dock_dev *msm8996_liquid_dock_dev;
-
-static void *adsp_state_notifier;
-static void *def_tasha_mbhc_cal(void);
-static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec,
- int enable, bool dapm);
-static int msm8996_wsa881x_init(struct snd_soc_component *component);
-
-/*
- * Need to report LINEIN
- * if R/L channel impedance is larger than 5K ohm
- */
-static struct wcd_mbhc_config wcd_mbhc_cfg = {
- .read_fw_bin = false,
- .calibration = NULL,
- .detect_extn_cable = true,
- .mono_stero_detection = false,
- .swap_gnd_mic = NULL,
- .hs_ext_micbias = true,
- .key_code[0] = KEY_MEDIA,
- .key_code[1] = KEY_VOICECOMMAND,
- .key_code[2] = KEY_VOLUMEUP,
- .key_code[3] = KEY_VOLUMEDOWN,
- .key_code[4] = 0,
- .key_code[5] = 0,
- .key_code[6] = 0,
- .key_code[7] = 0,
- .linein_th = 5000,
- .moisture_en = true,
- .mbhc_micbias = MIC_BIAS_2,
- .anc_micbias = MIC_BIAS_2,
- .enable_anc_mic_detect = false,
-};
-
-static inline int param_is_mask(int p)
-{
- return (p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) &&
- (p <= SNDRV_PCM_HW_PARAM_LAST_MASK);
-}
-
-static inline struct snd_mask *param_to_mask(struct snd_pcm_hw_params *p,
- int n)
-{
- return &(p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK]);
-}
-
-static void param_set_mask(struct snd_pcm_hw_params *p, int n, unsigned int bit)
-{
- if (bit >= SNDRV_MASK_MAX)
- return;
- if (param_is_mask(n)) {
- struct snd_mask *m = param_to_mask(p, n);
-
- m->bits[0] = 0;
- m->bits[1] = 0;
- m->bits[bit >> 5] |= (1 << (bit & 31));
- }
-}
-
-static void msm8996_liquid_docking_irq_work(struct work_struct *work)
-{
- struct msm8996_liquid_dock_dev *dock_dev =
- container_of(work, struct msm8996_liquid_dock_dev,
- irq_work);
-
- dock_dev->dock_plug_det =
- gpio_get_value(dock_dev->dock_plug_gpio);
-
- switch_set_state(&dock_dev->audio_sdev, dock_dev->dock_plug_det);
- /* notify to audio daemon */
- sysfs_notify(&dock_dev->audio_sdev.dev->kobj, NULL, "state");
-}
-
-static irqreturn_t msm8996_liquid_docking_irq_handler(int irq, void *dev)
-{
- struct msm8996_liquid_dock_dev *dock_dev = dev;
-
- /* switch speakers should not run in interrupt context */
- schedule_work(&dock_dev->irq_work);
- return IRQ_HANDLED;
-}
-
-static int msm8996_liquid_init_docking(void)
-{
- int ret = 0;
- int dock_plug_gpio = 0;
-
- /* plug in docking speaker+plug in device OR unplug one of them */
- u32 dock_plug_irq_flags = IRQF_TRIGGER_RISING |
- IRQF_TRIGGER_FALLING |
- IRQF_SHARED;
-
- dock_plug_gpio = of_get_named_gpio(spdev->dev.of_node,
- "qcom,dock-plug-det-irq", 0);
-
- if (dock_plug_gpio >= 0) {
- msm8996_liquid_dock_dev =
- kzalloc(sizeof(*msm8996_liquid_dock_dev), GFP_KERNEL);
- if (!msm8996_liquid_dock_dev) {
- ret = -ENOMEM;
- goto exit;
- }
-
- msm8996_liquid_dock_dev->dock_plug_gpio = dock_plug_gpio;
-
- ret = gpio_request(msm8996_liquid_dock_dev->dock_plug_gpio,
- "dock-plug-det-irq");
- if (ret) {
- pr_err("%s:failed request msm8996_liquid_dock_plug_gpio err = %d\n",
- __func__, ret);
- ret = -EINVAL;
- goto fail_dock_gpio;
- }
-
- msm8996_liquid_dock_dev->dock_plug_det =
- gpio_get_value(
- msm8996_liquid_dock_dev->dock_plug_gpio);
- msm8996_liquid_dock_dev->dock_plug_irq =
- gpio_to_irq(
- msm8996_liquid_dock_dev->dock_plug_gpio);
-
- ret = request_irq(msm8996_liquid_dock_dev->dock_plug_irq,
- msm8996_liquid_docking_irq_handler,
- dock_plug_irq_flags,
- "liquid_dock_plug_irq",
- msm8996_liquid_dock_dev);
- if (ret < 0) {
- pr_err("%s: Request Irq Failed err = %d\n",
- __func__, ret);
- goto fail_dock_gpio;
- }
-
- msm8996_liquid_dock_dev->audio_sdev.name =
- QC_AUDIO_EXTERNAL_SPK_1_EVENT;
-
- if (switch_dev_register(
- &msm8996_liquid_dock_dev->audio_sdev) < 0) {
- pr_err("%s: dock device register in switch diretory failed\n",
- __func__);
- goto fail_switch_dev;
- }
-
- INIT_WORK(
- &msm8996_liquid_dock_dev->irq_work,
- msm8996_liquid_docking_irq_work);
- }
- return 0;
-
-fail_switch_dev:
- free_irq(msm8996_liquid_dock_dev->dock_plug_irq,
- msm8996_liquid_dock_dev);
-fail_dock_gpio:
- gpio_free(msm8996_liquid_dock_dev->dock_plug_gpio);
-exit:
- kfree(msm8996_liquid_dock_dev);
- msm8996_liquid_dock_dev = NULL;
- return ret;
-}
-
-static void msm8996_ext_control(struct snd_soc_codec *codec)
-{
- struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-
- pr_debug("%s: msm8996_spk_control = %d", __func__,
- msm8996_spk_control);
- if (msm8996_spk_control == MSM8996_SPK_ON) {
- snd_soc_dapm_enable_pin(dapm, "Lineout_1 amp");
- snd_soc_dapm_enable_pin(dapm, "Lineout_2 amp");
- } else {
- snd_soc_dapm_disable_pin(dapm, "Lineout_1 amp");
- snd_soc_dapm_disable_pin(dapm, "Lineout_2 amp");
- }
- snd_soc_dapm_sync(dapm);
-}
-
-static int msm8996_get_spk(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- pr_debug("%s: msm8996_spk_control = %d\n",
- __func__, msm8996_spk_control);
- ucontrol->value.integer.value[0] = msm8996_spk_control;
- return 0;
-}
-
-static int msm8996_set_spk(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-
- pr_debug("%s() ucontrol->value.integer.value[0] = %ld\n",
- __func__, ucontrol->value.integer.value[0]);
- if (msm8996_spk_control == ucontrol->value.integer.value[0])
- return 0;
-
- msm8996_spk_control = ucontrol->value.integer.value[0];
- msm8996_ext_control(codec);
- return 1;
-}
-
-static int msm8996_hifi_ctrl(struct snd_soc_codec *codec)
-{
- struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
- struct snd_soc_card *card = codec->component.card;
- struct msm8996_asoc_mach_data *pdata =
- snd_soc_card_get_drvdata(card);
-
- pr_debug("%s: msm_hifi_control = %d", __func__,
- msm_hifi_control);
- if (pdata->hph_en1_gpio < 0) {
- pr_err("%s: hph_en1_gpio is invalid\n", __func__);
- return -EINVAL;
- }
- if (msm_hifi_control == MSM8996_HIFI_ON) {
- gpio_direction_output(pdata->hph_en1_gpio, 1);
- /* 5msec delay needed as per HW requirement */
- usleep_range(5000, 5010);
- } else {
- gpio_direction_output(pdata->hph_en1_gpio, 0);
- }
- snd_soc_dapm_sync(dapm);
- return 0;
-}
-
-static int msm8996_hifi_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- pr_debug("%s: msm_hifi_control = %d\n",
- __func__, msm_hifi_control);
- ucontrol->value.integer.value[0] = msm_hifi_control;
- return 0;
-}
-
-static int msm8996_hifi_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-
- pr_debug("%s() ucontrol->value.integer.value[0] = %ld\n",
- __func__, ucontrol->value.integer.value[0]);
-
- msm_hifi_control = ucontrol->value.integer.value[0];
- msm8996_hifi_ctrl(codec);
- return 1;
-}
-
-static int msm8996_ext_us_amp_init(void)
-{
- int ret = 0;
-
- ext_us_amp_gpio = of_get_named_gpio(spdev->dev.of_node,
- "qcom,ext-ult-spk-amp-gpio", 0);
- if (ext_us_amp_gpio >= 0) {
- ret = gpio_request(ext_us_amp_gpio, "ext_us_amp_gpio");
- if (ret) {
- pr_err("%s: ext_us_amp_gpio request failed, ret:%d\n",
- __func__, ret);
- return ret;
- }
- gpio_direction_output(ext_us_amp_gpio, 0);
- }
- return ret;
-}
-
-static void msm8996_ext_us_amp_enable(u32 on)
-{
- if (on)
- gpio_direction_output(ext_us_amp_gpio, 1);
- else
- gpio_direction_output(ext_us_amp_gpio, 0);
-
- pr_debug("%s: US Emitter GPIO enable:%s\n", __func__,
- on ? "Enable" : "Disable");
-}
-
-static int msm_ext_ultrasound_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *k, int event)
-{
- pr_debug("%s()\n", __func__);
- if (strcmp(w->name, "ultrasound amp")) {
- if (!gpio_is_valid(ext_us_amp_gpio)) {
- pr_err("%s: ext_us_amp_gpio isn't configured\n",
- __func__);
- return -EINVAL;
- }
- if (SND_SOC_DAPM_EVENT_ON(event))
- msm8996_ext_us_amp_enable(1);
- else
- msm8996_ext_us_amp_enable(0);
- } else {
- pr_err("%s() Invalid Widget = %s\n",
- __func__, w->name);
- return -EINVAL;
- }
- return 0;
-}
-
-static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec,
- int enable, bool dapm)
-{
- int ret = 0;
-
- if (!strcmp(dev_name(codec->dev), "tasha_codec")) {
- ret = tasha_cdc_mclk_enable(codec, enable, dapm);
- } else {
- dev_err(codec->dev, "%s: unknown codec to enable ext clk\n",
- __func__);
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-static int msm8996_mclk_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-
- pr_debug("%s: event = %d\n", __func__, event);
-
- switch (event) {
- case SND_SOC_DAPM_PRE_PMU:
- return msm_snd_enable_codec_ext_clk(codec, 1, true);
- case SND_SOC_DAPM_POST_PMD:
- return msm_snd_enable_codec_ext_clk(codec, 0, true);
- }
- return 0;
-}
-
-static int msm_snd_enable_codec_ext_tx_clk(struct snd_soc_codec *codec,
- int enable, bool dapm)
-{
- int ret = 0;
-
- if (!strcmp(dev_name(codec->dev), "tasha_codec"))
- ret = tasha_cdc_mclk_tx_enable(codec, enable, dapm);
- else {
- dev_err(codec->dev, "%s: unknown codec to enable ext clk\n",
- __func__);
- ret = -EINVAL;
- }
- return ret;
-}
-
-static int msm8996_mclk_tx_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-
- pr_debug("%s: event = %d\n", __func__, event);
-
- switch (event) {
- case SND_SOC_DAPM_PRE_PMU:
- return msm_snd_enable_codec_ext_tx_clk(codec, 1, true);
- case SND_SOC_DAPM_POST_PMD:
- return msm_snd_enable_codec_ext_tx_clk(codec, 0, true);
- }
- return 0;
-}
-
-static int msm_hifi_ctrl_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *k, int event)
-{
- struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
- struct snd_soc_card *card = codec->component.card;
- struct msm8996_asoc_mach_data *pdata =
- snd_soc_card_get_drvdata(card);
- int ret = 0;
-
- pr_debug("%s: msm_hifi_control = %d", __func__,
- msm_hifi_control);
- switch (event) {
- case SND_SOC_DAPM_POST_PMU:
- if (msm_hifi_control == MSM8996_HIFI_ON) {
- if (pdata->hph_en0_gpio < 0) {
- pr_err("%s: hph_en0_gpio is invalid\n",
- __func__);
- ret = -EINVAL;
- goto err;
- }
- gpio_direction_output(pdata->hph_en0_gpio, 1);
- }
- break;
- case SND_SOC_DAPM_PRE_PMD:
- if (msm_hifi_control == MSM8996_HIFI_ON) {
- if (pdata->hph_en0_gpio < 0) {
- pr_err("%s: hph_en0_gpio is invalid\n",
- __func__);
- ret = -EINVAL;
- goto err;
- }
- gpio_direction_output(pdata->hph_en0_gpio, 0);
- }
- break;
- }
-err:
- return ret;
-}
-
-static const struct snd_soc_dapm_widget msm8996_dapm_widgets[] = {
-
- SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0,
- msm8996_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_SUPPLY("MCLK TX", SND_SOC_NOPM, 0, 0,
- msm8996_mclk_tx_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_SPK("Lineout_1 amp", NULL),
- SND_SOC_DAPM_SPK("Lineout_3 amp", NULL),
- SND_SOC_DAPM_SPK("Lineout_2 amp", NULL),
- SND_SOC_DAPM_SPK("Lineout_4 amp", NULL),
- SND_SOC_DAPM_SPK("ultrasound amp", msm_ext_ultrasound_event),
- SND_SOC_DAPM_SPK("hifi amp", msm_hifi_ctrl_event),
- SND_SOC_DAPM_MIC("Handset Mic", NULL),
- SND_SOC_DAPM_MIC("Headset Mic", NULL),
- SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL),
- SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL),
- SND_SOC_DAPM_MIC("Analog Mic4", NULL),
- SND_SOC_DAPM_MIC("Analog Mic6", NULL),
- SND_SOC_DAPM_MIC("Analog Mic7", NULL),
- SND_SOC_DAPM_MIC("Analog Mic8", NULL),
-
- SND_SOC_DAPM_MIC("Digital Mic0", NULL),
- SND_SOC_DAPM_MIC("Digital Mic1", NULL),
- SND_SOC_DAPM_MIC("Digital Mic2", NULL),
- SND_SOC_DAPM_MIC("Digital Mic3", NULL),
- SND_SOC_DAPM_MIC("Digital Mic4", NULL),
- SND_SOC_DAPM_MIC("Digital Mic5", NULL),
- SND_SOC_DAPM_MIC("Digital Mic6", NULL),
-};
-
-static struct snd_soc_dapm_route wcd9335_audio_paths[] = {
- {"MIC BIAS1", NULL, "MCLK TX"},
- {"MIC BIAS2", NULL, "MCLK TX"},
- {"MIC BIAS3", NULL, "MCLK TX"},
- {"MIC BIAS4", NULL, "MCLK TX"},
-};
-
-static int slim5_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- int sample_rate_val = 0;
-
- switch (slim5_rx_sample_rate) {
- case SAMPLING_RATE_44P1KHZ:
- sample_rate_val = 3;
- break;
-
- case SAMPLING_RATE_192KHZ:
- sample_rate_val = 2;
- break;
-
- case SAMPLING_RATE_96KHZ:
- sample_rate_val = 1;
- break;
-
- case SAMPLING_RATE_48KHZ:
- default:
- sample_rate_val = 0;
- break;
- }
-
- ucontrol->value.integer.value[0] = sample_rate_val;
- pr_debug("%s: slim5_rx_sample_rate = %d\n", __func__,
- slim5_rx_sample_rate);
-
- return 0;
-}
-
-static int slim5_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- pr_debug("%s: ucontrol value = %ld\n", __func__,
- ucontrol->value.integer.value[0]);
-
- switch (ucontrol->value.integer.value[0]) {
- case 3:
- slim5_rx_sample_rate = SAMPLING_RATE_44P1KHZ;
- break;
- case 2:
- slim5_rx_sample_rate = SAMPLING_RATE_192KHZ;
- break;
- case 1:
- slim5_rx_sample_rate = SAMPLING_RATE_96KHZ;
- break;
- case 0:
- default:
- slim5_rx_sample_rate = SAMPLING_RATE_48KHZ;
- }
-
- pr_debug("%s: slim5_rx_sample_rate = %d\n", __func__,
- slim5_rx_sample_rate);
-
- return 0;
-}
-
-static int slim6_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- int sample_rate_val = 0;
-
- switch (slim6_rx_sample_rate) {
- case SAMPLING_RATE_44P1KHZ:
- sample_rate_val = 3;
- break;
-
- case SAMPLING_RATE_192KHZ:
- sample_rate_val = 2;
- break;
-
- case SAMPLING_RATE_96KHZ:
- sample_rate_val = 1;
- break;
-
- case SAMPLING_RATE_48KHZ:
- default:
- sample_rate_val = 0;
- break;
- }
-
- ucontrol->value.integer.value[0] = sample_rate_val;
- pr_debug("%s: slim6_rx_sample_rate = %d\n", __func__,
- slim6_rx_sample_rate);
-
- return 0;
-}
-
-static int slim6_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- switch (ucontrol->value.integer.value[0]) {
- case 3:
- slim6_rx_sample_rate = SAMPLING_RATE_44P1KHZ;
- break;
- case 2:
- slim6_rx_sample_rate = SAMPLING_RATE_192KHZ;
- break;
- case 1:
- slim6_rx_sample_rate = SAMPLING_RATE_96KHZ;
- break;
- case 0:
- default:
- slim6_rx_sample_rate = SAMPLING_RATE_48KHZ;
- break;
- }
-
- pr_debug("%s: ucontrol value = %ld, slim6_rx_sample_rate = %d\n",
- __func__, ucontrol->value.integer.value[0],
- slim6_rx_sample_rate);
-
- return 0;
-}
-
-static int slim0_tx_bit_format_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- switch (slim0_tx_bit_format) {
- case SNDRV_PCM_FORMAT_S24_3LE:
- ucontrol->value.integer.value[0] = 2;
- break;
- case SNDRV_PCM_FORMAT_S24_LE:
- ucontrol->value.integer.value[0] = 1;
- break;
- case SNDRV_PCM_FORMAT_S16_LE:
- default:
- ucontrol->value.integer.value[0] = 0;
- break;
- }
-
- pr_debug("%s: slim0_tx_bit_format = %d, ucontrol value = %ld\n",
- __func__, slim0_tx_bit_format,
- ucontrol->value.integer.value[0]);
- return 0;
-}
-
-static int slim0_tx_bit_format_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- int rc = 0;
-
- switch (ucontrol->value.integer.value[0]) {
- case 2:
- slim0_tx_bit_format = SNDRV_PCM_FORMAT_S24_3LE;
- break;
- case 1:
- slim0_tx_bit_format = SNDRV_PCM_FORMAT_S24_LE;
- break;
- case 0:
- slim0_tx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
- break;
- default:
- pr_err("%s: invalid value %ld\n", __func__,
- ucontrol->value.integer.value[0]);
- rc = -EINVAL;
- break;
- }
-
- pr_debug("%s: ucontrol value = %ld, slim0_tx_bit_format = %d\n",
- __func__, ucontrol->value.integer.value[0],
- slim0_tx_bit_format);
-
- return rc;
-}
-
-static int slim0_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- int sample_rate_val = 0;
-
- switch (slim0_rx_sample_rate) {
- case SAMPLING_RATE_32KHZ:
- sample_rate_val = 6;
- break;
-
- case SAMPLING_RATE_16KHZ:
- sample_rate_val = 5;
- break;
-
- case SAMPLING_RATE_8KHZ:
- sample_rate_val = 4;
- break;
-
- case SAMPLING_RATE_44P1KHZ:
- sample_rate_val = 3;
- break;
-
- case SAMPLING_RATE_192KHZ:
- sample_rate_val = 2;
- break;
-
- case SAMPLING_RATE_96KHZ:
- sample_rate_val = 1;
- break;
-
- case SAMPLING_RATE_48KHZ:
- default:
- sample_rate_val = 0;
- break;
- }
-
- ucontrol->value.integer.value[0] = sample_rate_val;
- pr_debug("%s: slim0_rx_sample_rate = %d\n", __func__,
- slim0_rx_sample_rate);
-
- return 0;
-}
-
-static int slim0_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- pr_debug("%s: ucontrol value = %ld\n", __func__,
- ucontrol->value.integer.value[0]);
-
- switch (ucontrol->value.integer.value[0]) {
- case 6:
- slim0_rx_sample_rate = SAMPLING_RATE_32KHZ;
- break;
- case 5:
- slim0_rx_sample_rate = SAMPLING_RATE_16KHZ;
- break;
- case 4:
- slim0_rx_sample_rate = SAMPLING_RATE_8KHZ;
- break;
- case 3:
- slim0_rx_sample_rate = SAMPLING_RATE_44P1KHZ;
- break;
- case 2:
- slim0_rx_sample_rate = SAMPLING_RATE_192KHZ;
- break;
- case 1:
- slim0_rx_sample_rate = SAMPLING_RATE_96KHZ;
- break;
- case 0:
- default:
- slim0_rx_sample_rate = SAMPLING_RATE_48KHZ;
- }
-
- pr_debug("%s: slim0_rx_sample_rate = %d\n", __func__,
- slim0_rx_sample_rate);
-
- return 0;
-}
-
-static int slim0_tx_sample_rate_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- int sample_rate_val = 0;
-
- switch (slim0_tx_sample_rate) {
- case SAMPLING_RATE_192KHZ:
- sample_rate_val = 2;
- break;
- case SAMPLING_RATE_96KHZ:
- sample_rate_val = 1;
- break;
- case SAMPLING_RATE_48KHZ:
- default:
- sample_rate_val = 0;
- break;
- }
-
- ucontrol->value.integer.value[0] = sample_rate_val;
- pr_debug("%s: slim0_tx_sample_rate = %d\n", __func__,
- slim0_tx_sample_rate);
- return 0;
-}
-
-static int slim0_tx_sample_rate_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- int rc = 0;
-
- pr_debug("%s: ucontrol value = %ld\n", __func__,
- ucontrol->value.integer.value[0]);
-
- switch (ucontrol->value.integer.value[0]) {
- case 2:
- slim0_tx_sample_rate = SAMPLING_RATE_192KHZ;
- break;
- case 1:
- slim0_tx_sample_rate = SAMPLING_RATE_96KHZ;
- break;
- case 0:
- slim0_tx_sample_rate = SAMPLING_RATE_48KHZ;
- break;
- default:
- rc = -EINVAL;
- pr_err("%s: invalid sample rate being passed\n", __func__);
- break;
- }
-
- pr_debug("%s: slim0_tx_sample_rate = %d\n", __func__,
- slim0_tx_sample_rate);
- return rc;
-}
-
-static int slim5_rx_bit_format_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
-
- switch (slim5_rx_bit_format) {
- case SNDRV_PCM_FORMAT_S24_3LE:
- ucontrol->value.integer.value[0] = 2;
- break;
-
- case SNDRV_PCM_FORMAT_S24_LE:
- ucontrol->value.integer.value[0] = 1;
- break;
-
- case SNDRV_PCM_FORMAT_S16_LE:
- default:
- ucontrol->value.integer.value[0] = 0;
- break;
- }
-
- pr_debug("%s: slim5_rx_bit_format = %d, ucontrol value = %ld\n",
- __func__, slim5_rx_bit_format,
- ucontrol->value.integer.value[0]);
-
- return 0;
-}
-
-static int slim5_rx_bit_format_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- switch (ucontrol->value.integer.value[0]) {
- case 2:
- slim5_rx_bit_format = SNDRV_PCM_FORMAT_S24_3LE;
- break;
- case 1:
- slim5_rx_bit_format = SNDRV_PCM_FORMAT_S24_LE;
- break;
- case 0:
- default:
- slim5_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
- break;
- }
- return 0;
-}
-
-static int slim6_rx_bit_format_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
-
- switch (slim6_rx_bit_format) {
- case SNDRV_PCM_FORMAT_S24_3LE:
- ucontrol->value.integer.value[0] = 2;
- break;
-
- case SNDRV_PCM_FORMAT_S24_LE:
- ucontrol->value.integer.value[0] = 1;
- break;
-
- case SNDRV_PCM_FORMAT_S16_LE:
- default:
- ucontrol->value.integer.value[0] = 0;
- break;
- }
-
- pr_debug("%s: slim6_rx_bit_format = %d, ucontrol value = %ld\n",
- __func__, slim6_rx_bit_format,
- ucontrol->value.integer.value[0]);
-
- return 0;
-}
-
-static int slim6_rx_bit_format_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- switch (ucontrol->value.integer.value[0]) {
- case 2:
- slim6_rx_bit_format = SNDRV_PCM_FORMAT_S24_3LE;
- break;
- case 1:
- slim6_rx_bit_format = SNDRV_PCM_FORMAT_S24_LE;
- break;
- case 0:
- default:
- slim6_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
- break;
- }
- return 0;
-}
-
-static int slim0_rx_bit_format_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
-
- switch (slim0_rx_bit_format) {
- case SNDRV_PCM_FORMAT_S24_3LE:
- ucontrol->value.integer.value[0] = 2;
- break;
-
- case SNDRV_PCM_FORMAT_S24_LE:
- ucontrol->value.integer.value[0] = 1;
- break;
-
- case SNDRV_PCM_FORMAT_S16_LE:
- default:
- ucontrol->value.integer.value[0] = 0;
- break;
- }
-
- pr_debug("%s: slim0_rx_bit_format = %d, ucontrol value = %ld\n",
- __func__, slim0_rx_bit_format,
- ucontrol->value.integer.value[0]);
-
- return 0;
-}
-
-static int slim0_rx_bit_format_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- switch (ucontrol->value.integer.value[0]) {
- case 2:
- slim0_rx_bit_format = SNDRV_PCM_FORMAT_S24_3LE;
- break;
- case 1:
- slim0_rx_bit_format = SNDRV_PCM_FORMAT_S24_LE;
- break;
- case 0:
- default:
- slim0_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
- break;
- }
- return 0;
-}
-
-static int msm_slim_5_rx_ch_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- pr_debug("%s: msm_slim_5_rx_ch = %d\n", __func__,
- msm_slim_5_rx_ch);
- ucontrol->value.integer.value[0] = msm_slim_5_rx_ch - 1;
- return 0;
-}
-
-static int msm_slim_5_rx_ch_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- msm_slim_5_rx_ch = ucontrol->value.integer.value[0] + 1;
- pr_debug("%s: msm_slim_5_rx_ch = %d\n", __func__,
- msm_slim_5_rx_ch);
- return 1;
-}
-
-static int msm_slim_6_rx_ch_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- pr_debug("%s: msm_slim_6_rx_ch = %d\n", __func__,
- msm_slim_6_rx_ch);
- ucontrol->value.integer.value[0] = msm_slim_6_rx_ch - 1;
- return 0;
-}
-
-static int msm_slim_6_rx_ch_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- msm_slim_6_rx_ch = ucontrol->value.integer.value[0] + 1;
- pr_debug("%s: msm_slim_6_rx_ch = %d\n", __func__,
- msm_slim_6_rx_ch);
- return 1;
-}
-
-static int msm_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- pr_debug("%s: msm_slim_0_rx_ch = %d\n", __func__,
- msm_slim_0_rx_ch);
- ucontrol->value.integer.value[0] = msm_slim_0_rx_ch - 1;
- return 0;
-}
-
-static int msm_slim_0_rx_ch_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- msm_slim_0_rx_ch = ucontrol->value.integer.value[0] + 1;
- pr_debug("%s: msm_slim_0_rx_ch = %d\n", __func__,
- msm_slim_0_rx_ch);
- return 1;
-}
-
-static int msm_slim_0_tx_ch_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- pr_debug("%s: msm_slim_0_tx_ch = %d\n", __func__,
- msm_slim_0_tx_ch);
- ucontrol->value.integer.value[0] = msm_slim_0_tx_ch - 1;
- return 0;
-}
-
-static int msm_slim_0_tx_ch_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- msm_slim_0_tx_ch = ucontrol->value.integer.value[0] + 1;
- pr_debug("%s: msm_slim_0_tx_ch = %d\n", __func__, msm_slim_0_tx_ch);
- return 1;
-}
-
-static int msm_slim_1_tx_ch_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- pr_debug("%s: msm_slim_1_tx_ch = %d\n", __func__,
- msm_slim_1_tx_ch);
- ucontrol->value.integer.value[0] = msm_slim_1_tx_ch - 1;
- return 0;
-}
-
-static int msm_slim_1_tx_ch_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- msm_slim_1_tx_ch = ucontrol->value.integer.value[0] + 1;
-
- pr_debug("%s: msm_slim_1_tx_ch = %d\n", __func__, msm_slim_1_tx_ch);
- return 1;
-}
-
-static int msm_vi_feed_tx_ch_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] = msm_vi_feed_tx_ch - 1;
- pr_debug("%s: msm_vi_feed_tx_ch = %ld\n", __func__,
- ucontrol->value.integer.value[0]);
- return 0;
-}
-
-static int msm_vi_feed_tx_ch_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- msm_vi_feed_tx_ch = ucontrol->value.integer.value[0] + 1;
-
- pr_debug("%s: msm_vi_feed_tx_ch = %d\n", __func__, msm_vi_feed_tx_ch);
- return 1;
-}
-
-static int hdmi_rx_bit_format_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
-
- switch (hdmi_rx_bit_format) {
- case SNDRV_PCM_FORMAT_S24_3LE:
- ucontrol->value.integer.value[0] = 2;
- break;
-
- case SNDRV_PCM_FORMAT_S24_LE:
- ucontrol->value.integer.value[0] = 1;
- break;
-
- case SNDRV_PCM_FORMAT_S16_LE:
- default:
- ucontrol->value.integer.value[0] = 0;
- break;
- }
-
- pr_debug("%s: hdmi_rx_bit_format = %d, ucontrol value = %ld\n",
- __func__, hdmi_rx_bit_format,
- ucontrol->value.integer.value[0]);
-
- return 0;
-}
-
-static int hdmi_rx_bit_format_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- switch (ucontrol->value.integer.value[0]) {
- case 2:
- hdmi_rx_bit_format = SNDRV_PCM_FORMAT_S24_3LE;
- break;
- case 1:
- hdmi_rx_bit_format = SNDRV_PCM_FORMAT_S24_LE;
- break;
- case 0:
- default:
- hdmi_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
- break;
- }
- pr_debug("%s: hdmi_rx_bit_format = %d, ucontrol value = %ld\n",
- __func__, hdmi_rx_bit_format,
- ucontrol->value.integer.value[0]);
- return 0;
-}
-
-static int msm_hdmi_rx_ch_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- pr_debug("%s: msm_hdmi_rx_ch = %d\n", __func__,
- msm_hdmi_rx_ch);
- ucontrol->value.integer.value[0] = msm_hdmi_rx_ch - 2;
-
- return 0;
-}
-
-static int msm_hdmi_rx_ch_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- msm_hdmi_rx_ch = ucontrol->value.integer.value[0] + 2;
- if (msm_hdmi_rx_ch > 8) {
- pr_err("%s: channels %d exceeded 8.Limiting to max chs-8\n",
- __func__, msm_hdmi_rx_ch);
- msm_hdmi_rx_ch = 8;
- }
- pr_debug("%s: msm_hdmi_rx_ch = %d\n", __func__, msm_hdmi_rx_ch);
-
- return 1;
-}
-
-static int hdmi_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- int sample_rate_val = 0;
-
- switch (hdmi_rx_sample_rate) {
- case SAMPLING_RATE_192KHZ:
- sample_rate_val = 2;
- break;
-
- case SAMPLING_RATE_96KHZ:
- sample_rate_val = 1;
- break;
-
- case SAMPLING_RATE_48KHZ:
- default:
- sample_rate_val = 0;
- break;
- }
-
- ucontrol->value.integer.value[0] = sample_rate_val;
- pr_debug("%s: hdmi_rx_sample_rate = %d\n", __func__,
- hdmi_rx_sample_rate);
-
- return 0;
-}
-
-static int hdmi_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- pr_debug("%s: ucontrol value = %ld\n", __func__,
- ucontrol->value.integer.value[0]);
-
- switch (ucontrol->value.integer.value[0]) {
- case 2:
- hdmi_rx_sample_rate = SAMPLING_RATE_192KHZ;
- break;
- case 1:
- hdmi_rx_sample_rate = SAMPLING_RATE_96KHZ;
- break;
- case 0:
- default:
- hdmi_rx_sample_rate = SAMPLING_RATE_48KHZ;
- }
-
- pr_debug("%s: hdmi_rx_sample_rate = %d\n", __func__,
- hdmi_rx_sample_rate);
-
- return 0;
-}
-
-static int msm8996_auxpcm_rate_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] = msm8996_auxpcm_rate;
- return 0;
-}
-
-static int msm8996_auxpcm_rate_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- switch (ucontrol->value.integer.value[0]) {
- case 0:
- msm8996_auxpcm_rate = SAMPLING_RATE_8KHZ;
- break;
- case 1:
- msm8996_auxpcm_rate = SAMPLING_RATE_16KHZ;
- break;
- default:
- msm8996_auxpcm_rate = SAMPLING_RATE_8KHZ;
- break;
- }
- return 0;
-}
-
-static int msm_proxy_rx_ch_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- pr_debug("%s: msm_proxy_rx_ch = %d\n", __func__, msm_proxy_rx_ch);
- ucontrol->value.integer.value[0] = msm_proxy_rx_ch - 1;
- return 0;
-}
-
-static int msm_proxy_rx_ch_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- msm_proxy_rx_ch = ucontrol->value.integer.value[0] + 1;
- pr_debug("%s: msm_proxy_rx_ch = %d\n", __func__, msm_proxy_rx_ch);
- return 1;
-}
-
-static int msm_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
-{
- struct snd_interval *rate =
- hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
-
- struct snd_interval *channels =
- hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
-
- rate->min = rate->max = msm8996_auxpcm_rate;
- channels->min = channels->max = 1;
-
- return 0;
-}
-
-static int msm_proxy_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
-{
- struct snd_interval *rate = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_RATE);
- struct snd_interval *channels = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
-
- pr_debug("%s: msm_proxy_rx_ch =%d\n", __func__, msm_proxy_rx_ch);
-
- if (channels->max < 2)
- channels->min = channels->max = 2;
- channels->min = channels->max = msm_proxy_rx_ch;
- rate->min = rate->max = SAMPLING_RATE_48KHZ;
- return 0;
-}
-
-static int msm_proxy_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
-{
- struct snd_interval *rate = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_RATE);
-
- rate->min = rate->max = SAMPLING_RATE_48KHZ;
- return 0;
-}
-
-static int msm8996_hdmi_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
-{
- struct snd_interval *rate = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_RATE);
- struct snd_interval *channels = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
-
- pr_debug("%s channels->min %u channels->max %u ()\n", __func__,
- channels->min, channels->max);
-
- param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
- hdmi_rx_bit_format);
- if (channels->max < 2)
- channels->min = channels->max = 2;
- rate->min = rate->max = hdmi_rx_sample_rate;
- channels->min = channels->max = msm_hdmi_rx_ch;
-
- return 0;
-}
-
-static int msm_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
-{
- struct snd_interval *rate = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_RATE);
- struct snd_interval *channels = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
-
- pr_debug("%s: channel:%d\n", __func__, msm_tert_mi2s_tx_ch);
- rate->min = rate->max = SAMPLING_RATE_48KHZ;
- channels->min = channels->max = msm_tert_mi2s_tx_ch;
- return 0;
-}
-
-static int msm8996_mi2s_snd_startup(struct snd_pcm_substream *substream)
-{
- int ret = 0;
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-
- pr_debug("%s: substream = %s stream = %d\n", __func__,
- substream->name, substream->stream);
-
- mi2s_tx_clk.enable = 1;
- ret = afe_set_lpass_clock_v2(AFE_PORT_ID_TERTIARY_MI2S_TX,
- &mi2s_tx_clk);
- if (ret < 0) {
- pr_err("%s: afe lpass clock failed, err:%d\n", __func__, ret);
- goto err;
- }
- ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS);
- if (ret < 0)
- pr_err("%s: set fmt cpu dai failed, err:%d\n", __func__, ret);
-err:
- return ret;
-}
-
-static void msm8996_mi2s_snd_shutdown(struct snd_pcm_substream *substream)
-{
- int ret = 0;
-
- pr_debug("%s: substream = %s stream = %d\n", __func__,
- substream->name, substream->stream);
-
- mi2s_tx_clk.enable = 0;
- ret = afe_set_lpass_clock_v2(AFE_PORT_ID_TERTIARY_MI2S_TX,
- &mi2s_tx_clk);
- if (ret < 0)
- pr_err("%s: afe lpass clock failed, err:%d\n", __func__, ret);
-}
-
-static struct snd_soc_ops msm8996_mi2s_be_ops = {
- .startup = msm8996_mi2s_snd_startup,
- .shutdown = msm8996_mi2s_snd_shutdown,
-};
-
-static int msm_slim_5_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
-{
- struct snd_interval *rate = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_RATE);
- struct snd_interval *channels = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
-
- param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
- slim5_rx_bit_format);
- rate->min = rate->max = slim5_rx_sample_rate;
- channels->min = channels->max = msm_slim_5_rx_ch;
-
- pr_debug("%s: format = %d, rate = %d, channels = %d\n",
- __func__, params_format(params), params_rate(params),
- msm_slim_5_rx_ch);
-
- return 0;
-}
-
-static int msm_slim_6_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
-{
- struct snd_interval *rate = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_RATE);
- struct snd_interval *channels = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
-
- param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
- slim6_rx_bit_format);
- rate->min = rate->max = slim6_rx_sample_rate;
- channels->min = channels->max = msm_slim_6_rx_ch;
-
- pr_debug("%s: format = %d, rate = %d, channels = %d\n",
- __func__, params_format(params), params_rate(params),
- msm_slim_6_rx_ch);
-
- return 0;
-}
-
-static int msm_slim_0_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
-{
- struct snd_interval *rate = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_RATE);
- struct snd_interval *channels = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
-
- param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
- slim0_rx_bit_format);
- rate->min = rate->max = slim0_rx_sample_rate;
- channels->min = channels->max = msm_slim_0_rx_ch;
-
- pr_debug("%s: format = %d, rate = %d, channels = %d\n",
- __func__, params_format(params), params_rate(params),
- msm_slim_0_rx_ch);
-
- return 0;
-}
-
-static int msm_slim_0_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
-{
- struct snd_interval *rate = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_RATE);
- struct snd_interval *channels = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
-
- pr_debug("%s()\n", __func__);
- param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, slim0_tx_bit_format);
- rate->min = rate->max = slim0_tx_sample_rate;
- channels->min = channels->max = msm_slim_0_tx_ch;
-
- return 0;
-}
-
-static int msm_slim_1_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
-{
- struct snd_interval *rate = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_RATE);
- struct snd_interval *channels = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
-
- pr_debug("%s()\n", __func__);
- param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, slim1_tx_bit_format);
- rate->min = rate->max = slim1_tx_sample_rate;
- channels->min = channels->max = msm_slim_1_tx_ch;
-
- return 0;
-}
-
-static int msm_slim_4_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
-{
- struct snd_interval *rate = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_RATE);
-
- struct snd_interval *channels = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
-
- param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
- SNDRV_PCM_FORMAT_S32_LE);
-
- rate->min = rate->max = SAMPLING_RATE_8KHZ;
- channels->min = channels->max = msm_vi_feed_tx_ch;
- pr_debug("%s: msm_vi_feed_tx_ch: %d\n", __func__, msm_vi_feed_tx_ch);
-
- return 0;
-}
-
-static int msm_slim_5_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
-{
- int rc = 0;
- void *config = NULL;
- struct snd_soc_codec *codec = rtd->codec;
- struct snd_interval *rate = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_RATE);
- struct snd_interval *channels = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
-
- pr_debug("%s: enter\n", __func__);
- rate->min = rate->max = SAMPLING_RATE_16KHZ;
- channels->min = channels->max = 1;
-
- config = msm8996_codec_fn.get_afe_config_fn(codec,
- AFE_SLIMBUS_SLAVE_PORT_CONFIG);
- if (config) {
- rc = afe_set_config(AFE_SLIMBUS_SLAVE_PORT_CONFIG, config,
- SLIMBUS_5_TX);
- if (rc) {
- pr_err("%s: Failed to set slimbus slave port config %d\n",
- __func__, rc);
- }
- }
-
- return rc;
-}
-
-static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
-{
- struct snd_interval *rate = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_RATE);
-
- pr_debug("%s:\n", __func__);
- rate->min = rate->max = SAMPLING_RATE_48KHZ;
- return 0;
-}
-
-static const struct soc_enum msm_snd_enum[] = {
- SOC_ENUM_SINGLE_EXT(2, spk_function),
- SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
- SOC_ENUM_SINGLE_EXT(8, slim0_tx_ch_text),
- SOC_ENUM_SINGLE_EXT(7, hdmi_rx_ch_text),
- SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_bit_format_text),
- rx_bit_format_text),
- SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim0_rx_sample_rate_text),
- slim0_rx_sample_rate_text),
- SOC_ENUM_SINGLE_EXT(8, proxy_rx_ch_text),
- SOC_ENUM_SINGLE_EXT(3, hdmi_rx_sample_rate_text),
- SOC_ENUM_SINGLE_EXT(4, slim5_rx_sample_rate_text),
- SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim5_rx_bit_format_text),
- slim5_rx_bit_format_text),
- SOC_ENUM_SINGLE_EXT(2, slim5_rx_ch_text),
- SOC_ENUM_SINGLE_EXT(2, hifi_function),
- SOC_ENUM_SINGLE_EXT(2, vi_feed_ch_text),
- SOC_ENUM_SINGLE_EXT(4, slim6_rx_sample_rate_text),
- SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim6_rx_bit_format_text),
- slim6_rx_bit_format_text),
- SOC_ENUM_SINGLE_EXT(2, slim6_rx_ch_text),
-};
-
-static const struct snd_kcontrol_new msm_snd_controls[] = {
- SOC_ENUM_EXT("Speaker Function", msm_snd_enum[0], msm8996_get_spk,
- msm8996_set_spk),
- SOC_ENUM_EXT("SLIM_0_RX Channels", msm_snd_enum[1],
- msm_slim_0_rx_ch_get, msm_slim_0_rx_ch_put),
- SOC_ENUM_EXT("SLIM_5_RX Channels", msm_snd_enum[10],
- msm_slim_5_rx_ch_get, msm_slim_5_rx_ch_put),
- SOC_ENUM_EXT("SLIM_6_RX Channels", msm_snd_enum[15],
- msm_slim_6_rx_ch_get, msm_slim_6_rx_ch_put),
- SOC_ENUM_EXT("SLIM_0_TX Channels", msm_snd_enum[2],
- msm_slim_0_tx_ch_get, msm_slim_0_tx_ch_put),
- SOC_ENUM_EXT("SLIM_1_TX Channels", msm_snd_enum[2],
- msm_slim_1_tx_ch_get, msm_slim_1_tx_ch_put),
- SOC_ENUM_EXT("AUX PCM SampleRate", msm8996_auxpcm_enum[0],
- msm8996_auxpcm_rate_get,
- msm8996_auxpcm_rate_put),
- SOC_ENUM_EXT("HDMI_RX Channels", msm_snd_enum[3],
- msm_hdmi_rx_ch_get, msm_hdmi_rx_ch_put),
- SOC_ENUM_EXT("SLIM_0_RX Format", msm_snd_enum[4],
- slim0_rx_bit_format_get, slim0_rx_bit_format_put),
- SOC_ENUM_EXT("SLIM_5_RX Format", msm_snd_enum[9],
- slim5_rx_bit_format_get, slim5_rx_bit_format_put),
- SOC_ENUM_EXT("SLIM_6_RX Format", msm_snd_enum[14],
- slim6_rx_bit_format_get, slim6_rx_bit_format_put),
- SOC_ENUM_EXT("SLIM_0_RX SampleRate", msm_snd_enum[5],
- slim0_rx_sample_rate_get, slim0_rx_sample_rate_put),
- SOC_ENUM_EXT("SLIM_5_RX SampleRate", msm_snd_enum[8],
- slim5_rx_sample_rate_get, slim5_rx_sample_rate_put),
- SOC_ENUM_EXT("SLIM_6_RX SampleRate", msm_snd_enum[13],
- slim6_rx_sample_rate_get, slim6_rx_sample_rate_put),
- SOC_ENUM_EXT("HDMI_RX Bit Format", msm_snd_enum[4],
- hdmi_rx_bit_format_get, hdmi_rx_bit_format_put),
- SOC_ENUM_EXT("PROXY_RX Channels", msm_snd_enum[6],
- msm_proxy_rx_ch_get, msm_proxy_rx_ch_put),
- SOC_ENUM_EXT("HDMI_RX SampleRate", msm_snd_enum[7],
- hdmi_rx_sample_rate_get, hdmi_rx_sample_rate_put),
- SOC_ENUM_EXT("SLIM_0_TX SampleRate", msm_snd_enum[5],
- slim0_tx_sample_rate_get, slim0_tx_sample_rate_put),
- SOC_ENUM_EXT("SLIM_0_TX Format", msm_snd_enum[4],
- slim0_tx_bit_format_get, slim0_tx_bit_format_put),
- SOC_ENUM_EXT("HiFi Function", msm_snd_enum[11], msm8996_hifi_get,
- msm8996_hifi_put),
- SOC_ENUM_EXT("VI_FEED_TX Channels", msm_snd_enum[12],
- msm_vi_feed_tx_ch_get, msm_vi_feed_tx_ch_put),
-};
-
-static bool msm8996_swap_gnd_mic(struct snd_soc_codec *codec)
-{
- struct snd_soc_card *card = codec->component.card;
- struct msm8996_asoc_mach_data *pdata =
- snd_soc_card_get_drvdata(card);
- int value = gpio_get_value_cansleep(pdata->us_euro_gpio);
-
- pr_debug("%s: swap select switch %d to %d\n", __func__, value, !value);
- gpio_set_value_cansleep(pdata->us_euro_gpio, !value);
- return true;
-}
-
-static int msm_afe_set_config(struct snd_soc_codec *codec)
-{
- int rc;
- void *config_data = NULL;
-
- pr_debug("%s: enter\n", __func__);
-
- if (!msm8996_codec_fn.get_afe_config_fn) {
- dev_err(codec->dev, "%s: codec get afe config not init'ed\n",
- __func__);
- return -EINVAL;
- }
-
- config_data = msm8996_codec_fn.get_afe_config_fn(codec,
- AFE_CDC_REGISTERS_CONFIG);
- if (config_data) {
- rc = afe_set_config(AFE_CDC_REGISTERS_CONFIG, config_data, 0);
- if (rc) {
- pr_err("%s: Failed to set codec registers config %d\n",
- __func__, rc);
- return rc;
- }
- }
-
- config_data = msm8996_codec_fn.get_afe_config_fn(codec,
- AFE_CDC_REGISTER_PAGE_CONFIG);
- if (config_data) {
- rc = afe_set_config(AFE_CDC_REGISTER_PAGE_CONFIG, config_data,
- 0);
- if (rc)
- pr_err("%s: Failed to set cdc register page config\n",
- __func__);
- }
-
- config_data = msm8996_codec_fn.get_afe_config_fn(codec,
- AFE_SLIMBUS_SLAVE_CONFIG);
- if (config_data) {
- rc = afe_set_config(AFE_SLIMBUS_SLAVE_CONFIG, config_data, 0);
- if (rc) {
- pr_err("%s: Failed to set slimbus slave config %d\n",
- __func__, rc);
- return rc;
- }
- }
-
- return 0;
-}
-
-static void msm_afe_clear_config(void)
-{
- afe_clear_config(AFE_CDC_REGISTERS_CONFIG);
- afe_clear_config(AFE_SLIMBUS_SLAVE_CONFIG);
-}
-
-static int msm8996_adsp_state_callback(struct notifier_block *nb,
- unsigned long value, void *priv)
-{
- if (value == SUBSYS_BEFORE_SHUTDOWN) {
- pr_debug("%s: ADSP is about to shutdown. Clearing AFE config\n",
- __func__);
- msm_afe_clear_config();
- } else if (value == SUBSYS_AFTER_POWERUP) {
- pr_debug("%s: ADSP is up\n", __func__);
- }
-
- return NOTIFY_OK;
-}
-
-static struct notifier_block adsp_state_notifier_block = {
- .notifier_call = msm8996_adsp_state_callback,
- .priority = -INT_MAX,
-};
-
-static int msm8996_wcd93xx_codec_up(struct snd_soc_codec *codec)
-{
- int err;
- unsigned long timeout;
- int adsp_ready = 0;
-
- timeout = jiffies +
- msecs_to_jiffies(ADSP_STATE_READY_TIMEOUT_MS);
-
- do {
- if (!q6core_is_adsp_ready()) {
- pr_err_ratelimited("%s: ADSP Audio isn't ready\n",
- __func__);
- /*
- * ADSP will be coming up after subsystem restart and
- * it might not be fully up when the control reaches
- * here. So, wait for 50msec before checking ADSP state
- */
- msleep(50);
- } else {
- pr_debug("%s: ADSP Audio is ready\n", __func__);
- adsp_ready = 1;
- break;
- }
- } while (time_after(timeout, jiffies));
-
- if (!adsp_ready) {
- pr_err("%s: timed out waiting for ADSP Audio\n", __func__);
- return -ETIMEDOUT;
- }
-
- err = msm_afe_set_config(codec);
- if (err)
- pr_err("%s: Failed to set AFE config. err %d\n",
- __func__, err);
- return err;
-}
-
-static int msm8996_tasha_codec_event_cb(struct snd_soc_codec *codec,
- enum wcd9335_codec_event codec_event)
-{
- switch (codec_event) {
- case WCD9335_CODEC_EVENT_CODEC_UP:
- return msm8996_wcd93xx_codec_up(codec);
- default:
- pr_err("%s: UnSupported codec event %d\n",
- __func__, codec_event);
- return -EINVAL;
- }
-}
-
-static int msm8996_config_hph_en0_gpio(struct snd_soc_codec *codec, bool high)
-{
- struct snd_soc_card *card = codec->component.card;
- struct msm8996_asoc_mach_data *pdata;
- int val;
-
- if (!card)
- return 0;
-
- pdata = snd_soc_card_get_drvdata(card);
- if (!pdata || !gpio_is_valid(pdata->hph_en0_gpio))
- return 0;
-
- val = gpio_get_value_cansleep(pdata->hph_en0_gpio);
- if ((!!val) == high)
- return 0;
-
- gpio_direction_output(pdata->hph_en0_gpio, (int)high);
-
- return 1;
-}
-
-static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
-{
- int err;
- void *config_data;
- struct snd_soc_codec *codec = rtd->codec;
- struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_component *aux_comp;
- void *mbhc_calibration;
- struct snd_card *card;
- struct snd_info_entry *entry;
- struct msm8996_asoc_mach_data *pdata =
- snd_soc_card_get_drvdata(rtd->card);
-
- /* Codec SLIMBUS configuration
- * RX1, RX2, RX3, RX4, RX5, RX6, RX7, RX8, RX9, RX10, RX11, RX12, RX13
- * TX1, TX2, TX3, TX4, TX5, TX6, TX7, TX8, TX9, TX10, TX11, TX12, TX13
- * TX14, TX15, TX16
- */
- unsigned int rx_ch[TASHA_RX_MAX] = {144, 145, 146, 147, 148, 149, 150,
- 151, 152, 153, 154, 155, 156};
- unsigned int tx_ch[TASHA_TX_MAX] = {128, 129, 130, 131, 132, 133,
- 134, 135, 136, 137, 138, 139,
- 140, 141, 142, 143};
-
- pr_info("%s: dev_name%s\n", __func__, dev_name(cpu_dai->dev));
-
- rtd->pmdown_time = 0;
-
- err = snd_soc_add_codec_controls(codec, msm_snd_controls,
- ARRAY_SIZE(msm_snd_controls));
- if (err < 0) {
- pr_err("%s: add_codec_controls failed, err %d\n",
- __func__, err);
- return err;
- }
-
- err = msm8996_liquid_init_docking();
- if (err) {
- pr_err("%s: 8996 init Docking stat IRQ failed (%d)\n",
- __func__, err);
- return err;
- }
-
- err = msm8996_ext_us_amp_init();
- if (err) {
- pr_err("%s: 8996 US Emitter GPIO init failed (%d)\n",
- __func__, err);
- return err;
- }
-
- snd_soc_dapm_new_controls(dapm, msm8996_dapm_widgets,
- ARRAY_SIZE(msm8996_dapm_widgets));
-
- snd_soc_dapm_add_routes(dapm, wcd9335_audio_paths,
- ARRAY_SIZE(wcd9335_audio_paths));
- snd_soc_dapm_enable_pin(dapm, "Lineout_1 amp");
- snd_soc_dapm_enable_pin(dapm, "Lineout_3 amp");
- snd_soc_dapm_enable_pin(dapm, "Lineout_2 amp");
- snd_soc_dapm_enable_pin(dapm, "Lineout_4 amp");
-
- snd_soc_dapm_ignore_suspend(dapm, "Lineout_1 amp");
- snd_soc_dapm_ignore_suspend(dapm, "Lineout_3 amp");
- snd_soc_dapm_ignore_suspend(dapm, "Lineout_2 amp");
- snd_soc_dapm_ignore_suspend(dapm, "Lineout_4 amp");
- snd_soc_dapm_ignore_suspend(dapm, "ultrasound amp");
- snd_soc_dapm_ignore_suspend(dapm, "Handset Mic");
- snd_soc_dapm_ignore_suspend(dapm, "Headset Mic");
- snd_soc_dapm_ignore_suspend(dapm, "ANCRight Headset Mic");
- snd_soc_dapm_ignore_suspend(dapm, "ANCLeft Headset Mic");
- snd_soc_dapm_ignore_suspend(dapm, "Digital Mic1");
- snd_soc_dapm_ignore_suspend(dapm, "Digital Mic2");
- snd_soc_dapm_ignore_suspend(dapm, "Digital Mic3");
- snd_soc_dapm_ignore_suspend(dapm, "Digital Mic4");
- snd_soc_dapm_ignore_suspend(dapm, "Digital Mic5");
- snd_soc_dapm_ignore_suspend(dapm, "Analog Mic4");
- snd_soc_dapm_ignore_suspend(dapm, "Analog Mic6");
- snd_soc_dapm_ignore_suspend(dapm, "Analog Mic7");
- snd_soc_dapm_ignore_suspend(dapm, "Analog Mic8");
- snd_soc_dapm_ignore_suspend(dapm, "MADINPUT");
- snd_soc_dapm_ignore_suspend(dapm, "MAD_CPE_INPUT");
- snd_soc_dapm_ignore_suspend(dapm, "EAR");
- snd_soc_dapm_ignore_suspend(dapm, "LINEOUT1");
- snd_soc_dapm_ignore_suspend(dapm, "LINEOUT2");
- snd_soc_dapm_ignore_suspend(dapm, "LINEOUT3");
- snd_soc_dapm_ignore_suspend(dapm, "LINEOUT4");
- snd_soc_dapm_ignore_suspend(dapm, "ANC EAR");
- snd_soc_dapm_ignore_suspend(dapm, "AMIC1");
- snd_soc_dapm_ignore_suspend(dapm, "AMIC2");
- snd_soc_dapm_ignore_suspend(dapm, "AMIC3");
- snd_soc_dapm_ignore_suspend(dapm, "AMIC4");
- snd_soc_dapm_ignore_suspend(dapm, "AMIC5");
- snd_soc_dapm_ignore_suspend(dapm, "AMIC6");
- snd_soc_dapm_ignore_suspend(dapm, "DMIC1");
- snd_soc_dapm_ignore_suspend(dapm, "DMIC2");
- snd_soc_dapm_ignore_suspend(dapm, "DMIC3");
- snd_soc_dapm_ignore_suspend(dapm, "DMIC4");
- snd_soc_dapm_ignore_suspend(dapm, "DMIC5");
- snd_soc_dapm_ignore_suspend(dapm, "Digital Mic0");
- snd_soc_dapm_ignore_suspend(dapm, "DMIC0");
- snd_soc_dapm_ignore_suspend(dapm, "SPK1 OUT");
- snd_soc_dapm_ignore_suspend(dapm, "SPK2 OUT");
- snd_soc_dapm_ignore_suspend(dapm, "HPHL");
- snd_soc_dapm_ignore_suspend(dapm, "HPHR");
- snd_soc_dapm_ignore_suspend(dapm, "ANC HPHL");
- snd_soc_dapm_ignore_suspend(dapm, "ANC HPHR");
- snd_soc_dapm_ignore_suspend(dapm, "ANC LINEOUT1");
- snd_soc_dapm_ignore_suspend(dapm, "ANC LINEOUT2");
- snd_soc_dapm_ignore_suspend(dapm, "AIF4 VI");
- snd_soc_dapm_ignore_suspend(dapm, "VIINPUT");
-
- snd_soc_dapm_sync(dapm);
-
- snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
- tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
-
- msm8996_codec_fn.get_afe_config_fn = tasha_get_afe_config;
- msm8996_codec_fn.mbhc_hs_detect_exit = tasha_mbhc_hs_detect_exit;
-
- err = msm_afe_set_config(codec);
- if (err) {
- pr_err("%s: Failed to set AFE config %d\n", __func__, err);
- goto out;
- }
-
- config_data = msm8996_codec_fn.get_afe_config_fn(codec,
- AFE_AANC_VERSION);
- if (config_data) {
- err = afe_set_config(AFE_AANC_VERSION, config_data, 0);
- if (err) {
- pr_err("%s: Failed to set aanc version %d\n",
- __func__, err);
- goto out;
- }
- }
- config_data = msm8996_codec_fn.get_afe_config_fn(codec,
- AFE_CDC_CLIP_REGISTERS_CONFIG);
- if (config_data) {
- err = afe_set_config(AFE_CDC_CLIP_REGISTERS_CONFIG,
- config_data, 0);
- if (err) {
- pr_err("%s: Failed to set clip registers %d\n",
- __func__, err);
- goto out;
- }
- }
- config_data = msm8996_codec_fn.get_afe_config_fn(codec,
- AFE_CLIP_BANK_SEL);
- if (config_data) {
- err = afe_set_config(AFE_CLIP_BANK_SEL, config_data, 0);
- if (err) {
- pr_err("%s: Failed to set AFE bank selection %d\n",
- __func__, err);
- goto out;
- }
- }
- /* Start mbhc */
- tasha_mbhc_zdet_gpio_ctrl(msm8996_config_hph_en0_gpio, rtd->codec);
- mbhc_calibration = def_tasha_mbhc_cal();
- if (mbhc_calibration) {
- wcd_mbhc_cfg.calibration = mbhc_calibration;
- err = tasha_mbhc_hs_detect(codec, &wcd_mbhc_cfg);
- if (err) {
- pr_err("%s: mbhc hs detect failed, err:%d\n",
- __func__, err);
- goto out;
- }
- } else {
- pr_err("%s: mbhc_cfg calibration is NULL\n", __func__);
- err = -ENOMEM;
- goto out;
- }
- adsp_state_notifier = subsys_notif_register_notifier("adsp",
- &adsp_state_notifier_block);
- if (!adsp_state_notifier) {
- pr_err("%s: Failed to register adsp state notifier\n",
- __func__);
- err = -EFAULT;
- msm8996_codec_fn.mbhc_hs_detect_exit(codec);
- goto out;
- }
-
- tasha_event_register(msm8996_tasha_codec_event_cb, rtd->codec);
-
- /*
- * Send speaker configuration only for WSA8810.
- * Defalut configuration is for WSA8815.
- */
- if (!list_empty(&rtd->card->aux_comp_list)) {
- aux_comp = list_first_entry(&rtd->card->aux_comp_list,
- struct snd_soc_component, list_aux);
- if (!strcmp(aux_comp->name, WSA8810_NAME_1) ||
- !strcmp(aux_comp->name, WSA8810_NAME_2)) {
- tasha_set_spkr_mode(rtd->codec, SPKR_MODE_1);
- tasha_set_spkr_gain_offset(rtd->codec,
- RX_GAIN_OFFSET_M1P5_DB);
- }
- }
- codec_reg_done = true;
-
- card = rtd->card->snd_card;
- entry = snd_info_create_subdir(card->module, "codecs",
- card->proc_root);
- if (!entry) {
- pr_debug("%s: Cannot create codecs module entry\n",
- __func__);
- err = 0;
- goto out;
- }
- pdata->codec_root = entry;
- tasha_codec_info_create_codec_entry(pdata->codec_root, codec);
-
- return 0;
-out:
- return err;
-}
-
-static void *def_tasha_mbhc_cal(void)
-{
- void *tasha_wcd_cal;
- struct wcd_mbhc_btn_detect_cfg *btn_cfg;
- u16 *btn_high;
-
- tasha_wcd_cal = kzalloc(WCD_MBHC_CAL_SIZE(WCD_MBHC_DEF_BUTTONS,
- WCD9XXX_MBHC_DEF_RLOADS), GFP_KERNEL);
- if (!tasha_wcd_cal)
- return NULL;
-
-#define S(X, Y) ((WCD_MBHC_CAL_PLUG_TYPE_PTR(tasha_wcd_cal)->X) = (Y))
- S(v_hs_max, 1500);
-#undef S
-#define S(X, Y) ((WCD_MBHC_CAL_BTN_DET_PTR(tasha_wcd_cal)->X) = (Y))
- S(num_btn, WCD_MBHC_DEF_BUTTONS);
-#undef S
-
- btn_cfg = WCD_MBHC_CAL_BTN_DET_PTR(tasha_wcd_cal);
- btn_high = ((void *)&btn_cfg->_v_btn_low) +
- (sizeof(btn_cfg->_v_btn_low[0]) * btn_cfg->num_btn);
-
- btn_high[0] = 75;
- btn_high[1] = 150;
- btn_high[2] = 237;
- btn_high[3] = 500;
- btn_high[4] = 500;
- btn_high[5] = 500;
- btn_high[6] = 500;
- btn_high[7] = 500;
-
- return tasha_wcd_cal;
-}
-
-static int msm_snd_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- struct snd_soc_dai_link *dai_link = rtd->dai_link;
-
- int ret = 0;
- u32 rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
- u32 rx_ch_cnt = 0, tx_ch_cnt = 0;
- u32 user_set_tx_ch = 0;
- u32 rx_ch_count;
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- ret = snd_soc_dai_get_channel_map(codec_dai,
- &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
- if (ret < 0) {
- pr_err("%s: failed to get codec chan map, err:%d\n",
- __func__, ret);
- goto end;
- }
- if (dai_link->id == MSM_BACKEND_DAI_SLIMBUS_5_RX) {
- pr_debug("%s: rx_5_ch=%d\n", __func__,
- msm_slim_5_rx_ch);
- rx_ch_count = msm_slim_5_rx_ch;
- } else if (dai_link->id == MSM_BACKEND_DAI_SLIMBUS_6_RX) {
- pr_debug("%s: rx_6_ch=%d\n", __func__,
- msm_slim_6_rx_ch);
- rx_ch_count = msm_slim_6_rx_ch;
- } else {
- pr_debug("%s: rx_0_ch=%d\n", __func__,
- msm_slim_0_rx_ch);
- rx_ch_count = msm_slim_0_rx_ch;
- }
- ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
- rx_ch_count, rx_ch);
- if (ret < 0) {
- pr_err("%s: failed to set cpu chan map, err:%d\n",
- __func__, ret);
- goto end;
- }
- } else {
-
- pr_debug("%s: %s_tx_dai_id_%d_ch=%d\n", __func__,
- codec_dai->name, codec_dai->id, user_set_tx_ch);
- ret = snd_soc_dai_get_channel_map(codec_dai,
- &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
- if (ret < 0) {
- pr_err("%s: failed to get codec chan map\n, err:%d\n",
- __func__, ret);
- goto end;
- }
- /* For <codec>_tx1 case */
- if (dai_link->id == MSM_BACKEND_DAI_SLIMBUS_0_TX)
- user_set_tx_ch = msm_slim_0_tx_ch;
- /* For <codec>_tx3 case */
- else if (dai_link->id == MSM_BACKEND_DAI_SLIMBUS_1_TX)
- user_set_tx_ch = msm_slim_1_tx_ch;
- else if (dai_link->id == MSM_BACKEND_DAI_SLIMBUS_3_TX)
- /* DAI 5 is used for external EC reference from codec.
- * Since Rx is fed as reference for EC, the config of
- * this DAI is based on that of the Rx path.
- */
- user_set_tx_ch = msm_slim_0_rx_ch;
- else if (dai_link->id == MSM_BACKEND_DAI_SLIMBUS_4_TX)
- user_set_tx_ch = msm_vi_feed_tx_ch;
- else
- user_set_tx_ch = tx_ch_cnt;
-
- pr_debug("%s: msm_slim_0_tx_ch(%d) user_set_tx_ch(%d) tx_ch_cnt(%d), BE id (%d)\n",
- __func__, msm_slim_0_tx_ch, user_set_tx_ch,
- tx_ch_cnt, dai_link->id);
-
- ret = snd_soc_dai_set_channel_map(cpu_dai,
- user_set_tx_ch, tx_ch, 0, 0);
- if (ret < 0) {
- pr_err("%s: failed to set cpu chan map, err:%d\n",
- __func__, ret);
- goto end;
- }
- }
-end:
- return ret;
-}
-
-static int msm_snd_cpe_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- struct snd_soc_dai_link *dai_link = rtd->dai_link;
-
- int ret = 0;
- u32 tx_ch[SLIM_MAX_TX_PORTS];
- u32 tx_ch_cnt = 0;
- u32 user_set_tx_ch = 0;
-
- if (substream->stream != SNDRV_PCM_STREAM_CAPTURE) {
- pr_err("%s: Invalid stream type %d\n",
- __func__, substream->stream);
- ret = -EINVAL;
- goto end;
- }
-
- pr_debug("%s: %s_tx_dai_id_%d\n", __func__,
- codec_dai->name, codec_dai->id);
- ret = snd_soc_dai_get_channel_map(codec_dai,
- &tx_ch_cnt, tx_ch, NULL, NULL);
- if (ret < 0) {
- pr_err("%s: failed to get codec chan map\n, err:%d\n",
- __func__, ret);
- goto end;
- }
-
- user_set_tx_ch = tx_ch_cnt;
-
- pr_debug("%s: tx_ch_cnt(%d) BE id %d\n",
- __func__, tx_ch_cnt, dai_link->id);
-
- ret = snd_soc_dai_set_channel_map(cpu_dai,
- user_set_tx_ch, tx_ch, 0, 0);
- if (ret < 0)
- pr_err("%s: failed to set cpu chan map, err:%d\n",
- __func__, ret);
-end:
- return ret;
-}
-
-static struct snd_soc_ops msm8996_be_ops = {
- .hw_params = msm_snd_hw_params,
-};
-
-static struct snd_soc_ops msm8996_cpe_ops = {
- .hw_params = msm_snd_cpe_hw_params,
-};
-
-static int msm8996_slimbus_2_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- int ret = 0;
- unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
- unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
- unsigned int num_tx_ch = 0;
- unsigned int num_rx_ch = 0;
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- num_rx_ch = params_channels(params);
- pr_debug("%s: %s rx_dai_id = %d num_ch = %d\n", __func__,
- codec_dai->name, codec_dai->id, num_rx_ch);
- ret = snd_soc_dai_get_channel_map(codec_dai,
- &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
- if (ret < 0) {
- pr_err("%s: failed to get codec chan map, err:%d\n",
- __func__, ret);
- goto end;
- }
- ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
- num_rx_ch, rx_ch);
- if (ret < 0) {
- pr_err("%s: failed to set cpu chan map, err:%d\n",
- __func__, ret);
- goto end;
- }
- } else {
- num_tx_ch = params_channels(params);
- pr_debug("%s: %s tx_dai_id = %d num_ch = %d\n", __func__,
- codec_dai->name, codec_dai->id, num_tx_ch);
- ret = snd_soc_dai_get_channel_map(codec_dai,
- &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
- if (ret < 0) {
- pr_err("%s: failed to get codec chan map, err:%d\n",
- __func__, ret);
- goto end;
- }
- ret = snd_soc_dai_set_channel_map(cpu_dai,
- num_tx_ch, tx_ch, 0, 0);
- if (ret < 0) {
- pr_err("%s: failed to set cpu chan map, err:%d\n",
- __func__, ret);
- goto end;
- }
- }
-end:
- return ret;
-}
-
-static struct snd_soc_ops msm8996_slimbus_2_be_ops = {
- .hw_params = msm8996_slimbus_2_hw_params,
-};
-
-static int msm8996_get_ll_qos_val(struct snd_pcm_runtime *runtime)
-{
- int usecs;
-
- /* take 10% of period time as the deadline */
- usecs = (100000 / runtime->rate) * runtime->period_size;
- usecs += ((100000 % runtime->rate) * runtime->period_size) /
- runtime->rate;
-
- return usecs;
-}
-
-static int msm8996_mm5_prepare(struct snd_pcm_substream *substream)
-{
- if (pm_qos_request_active(&substream->latency_pm_qos_req))
- pm_qos_remove_request(&substream->latency_pm_qos_req);
- pm_qos_add_request(&substream->latency_pm_qos_req,
- PM_QOS_CPU_DMA_LATENCY,
- msm8996_get_ll_qos_val(substream->runtime));
- return 0;
-}
-
-static struct snd_soc_ops msm8996_mm5_ops = {
- .prepare = msm8996_mm5_prepare,
-};
-
-/* Digital audio interface glue - connects codec <---> CPU */
-static struct snd_soc_dai_link msm8996_common_dai_links[] = {
- /* FrontEnd DAI Links */
- {
- .name = "MSM8996 Media1",
- .stream_name = "MultiMedia1",
- .cpu_dai_name = "MultiMedia1",
- .platform_name = "msm-pcm-dsp.0",
- .dynamic = 1,
- .async_ops = ASYNC_DPCM_SND_SOC_PREPARE,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST},
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- .ignore_suspend = 1,
- /* this dainlink has playback support */
- .ignore_pmdown_time = 1,
- .id = MSM_FRONTEND_DAI_MULTIMEDIA1
- },
- {
- .name = "MSM8996 Media2",
- .stream_name = "MultiMedia2",
- .cpu_dai_name = "MultiMedia2",
- .platform_name = "msm-pcm-dsp.0",
- .dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- .trigger = {SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST},
- .ignore_suspend = 1,
- /* this dainlink has playback support */
- .ignore_pmdown_time = 1,
- .id = MSM_FRONTEND_DAI_MULTIMEDIA2,
- },
- {
- .name = "VoiceMMode1",
- .stream_name = "VoiceMMode1",
- .cpu_dai_name = "VoiceMMode1",
- .platform_name = "msm-pcm-voice",
- .dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST},
- .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
- .ignore_suspend = 1,
- .ignore_pmdown_time = 1,
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- .id = MSM_FRONTEND_DAI_VOICEMMODE1,
- },
- {
- .name = "MSM VoIP",
- .stream_name = "VoIP",
- .cpu_dai_name = "VoIP",
- .platform_name = "msm-voip-dsp",
- .dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST},
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- .ignore_suspend = 1,
- /* this dainlink has playback support */
- .ignore_pmdown_time = 1,
- .id = MSM_FRONTEND_DAI_VOIP,
- },
- {
- .name = "MSM8996 ULL",
- .stream_name = "MultiMedia3",
- .cpu_dai_name = "MultiMedia3",
- .platform_name = "msm-pcm-dsp.2",
- .dynamic = 1,
- .async_ops = ASYNC_DPCM_SND_SOC_PREPARE,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST},
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- .ignore_suspend = 1,
- /* this dainlink has playback support */
- .ignore_pmdown_time = 1,
- .id = MSM_FRONTEND_DAI_MULTIMEDIA3,
- },
- /* Hostless PCM purpose */
- {
- .name = "SLIMBUS_0 Hostless",
- .stream_name = "SLIMBUS_0 Hostless",
- .cpu_dai_name = "SLIMBUS0_HOSTLESS",
- .platform_name = "msm-pcm-hostless",
- .dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST},
- .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
- .ignore_suspend = 1,
- /* this dailink has playback support */
- .ignore_pmdown_time = 1,
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- },
- {
- .name = "Tertiary MI2S TX_Hostless",
- .stream_name = "Tertiary MI2S_TX Hostless Capture",
- .cpu_dai_name = "TERT_MI2S_TX_HOSTLESS",
- .platform_name = "msm-pcm-hostless",
- .dynamic = 1,
- .dpcm_capture = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST},
- .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
- .ignore_suspend = 1,
- .ignore_pmdown_time = 1,
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- },
- {
- .name = "MSM AFE-PCM RX",
- .stream_name = "AFE-PROXY RX",
- .cpu_dai_name = "msm-dai-q6-dev.241",
- .codec_name = "msm-stub-codec.1",
- .codec_dai_name = "msm-stub-rx",
- .platform_name = "msm-pcm-afe",
- .ignore_suspend = 1,
- /* this dainlink has playback support */
- .ignore_pmdown_time = 1,
- },
- {
- .name = "MSM AFE-PCM TX",
- .stream_name = "AFE-PROXY TX",
- .cpu_dai_name = "msm-dai-q6-dev.240",
- .codec_name = "msm-stub-codec.1",
- .codec_dai_name = "msm-stub-tx",
- .platform_name = "msm-pcm-afe",
- .ignore_suspend = 1,
- },
- {
- .name = "MSM8996 Compress1",
- .stream_name = "Compress1",
- .cpu_dai_name = "MultiMedia4",
- .platform_name = "msm-compress-dsp",
- .dynamic = 1,
- .async_ops = ASYNC_DPCM_SND_SOC_HW_PARAMS,
- .dpcm_playback = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST},
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- .ignore_suspend = 1,
- .ignore_pmdown_time = 1,
- /* this dainlink has playback support */
- .id = MSM_FRONTEND_DAI_MULTIMEDIA4,
- },
- {
- .name = "AUXPCM Hostless",
- .stream_name = "AUXPCM Hostless",
- .cpu_dai_name = "AUXPCM_HOSTLESS",
- .platform_name = "msm-pcm-hostless",
- .dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST},
- .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
- .ignore_suspend = 1,
- /* this dainlink has playback support */
- .ignore_pmdown_time = 1,
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- },
- {
- .name = "SLIMBUS_1 Hostless",
- .stream_name = "SLIMBUS_1 Hostless",
- .cpu_dai_name = "SLIMBUS1_HOSTLESS",
- .platform_name = "msm-pcm-hostless",
- .dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST},
- .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
- .ignore_suspend = 1,
- /* this dailink has playback support */
- .ignore_pmdown_time = 1,
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- },
- {
- .name = "SLIMBUS_3 Hostless",
- .stream_name = "SLIMBUS_3 Hostless",
- .cpu_dai_name = "SLIMBUS3_HOSTLESS",
- .platform_name = "msm-pcm-hostless",
- .dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST},
- .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
- .ignore_suspend = 1,
- /* this dailink has playback support */
- .ignore_pmdown_time = 1,
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- },
- {
- .name = "SLIMBUS_4 Hostless",
- .stream_name = "SLIMBUS_4 Hostless",
- .cpu_dai_name = "SLIMBUS4_HOSTLESS",
- .platform_name = "msm-pcm-hostless",
- .dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST},
- .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
- .ignore_suspend = 1,
- /* this dailink has playback support */
- .ignore_pmdown_time = 1,
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- },
- {
- .name = "VoLTE",
- .stream_name = "VoLTE",
- .cpu_dai_name = "VoLTE",
- .platform_name = "msm-pcm-voice",
- .dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST},
- .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
- .ignore_suspend = 1,
- /* this dainlink has playback support */
- .ignore_pmdown_time = 1,
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- .id = MSM_FRONTEND_DAI_VOLTE,
- },
- {
- .name = "MSM8996 LowLatency",
- .stream_name = "MultiMedia5",
- .cpu_dai_name = "MultiMedia5",
- .platform_name = "msm-pcm-dsp.1",
- .dynamic = 1,
- .async_ops = ASYNC_DPCM_SND_SOC_PREPARE,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- .trigger = {SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST},
- .ignore_suspend = 1,
- /* this dainlink has playback support */
- .ignore_pmdown_time = 1,
- .id = MSM_FRONTEND_DAI_MULTIMEDIA5,
- .ops = &msm8996_mm5_ops,
- },
- {
- .name = "Listen 1 Audio Service",
- .stream_name = "Listen 1 Audio Service",
- .cpu_dai_name = "LSM1",
- .platform_name = "msm-lsm-client",
- .dynamic = 1,
- .dpcm_capture = 1,
- .trigger = { SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST },
- .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
- .ignore_suspend = 1,
- .ignore_pmdown_time = 1,
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- .id = MSM_FRONTEND_DAI_LSM1,
- },
- /* Multiple Tunnel instances */
- {
- .name = "MSM8996 Compress2",
- .stream_name = "Compress2",
- .cpu_dai_name = "MultiMedia7",
- .platform_name = "msm-compress-dsp",
- .dynamic = 1,
- .dpcm_playback = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST},
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- .ignore_suspend = 1,
- .ignore_pmdown_time = 1,
- /* this dainlink has playback support */
- .id = MSM_FRONTEND_DAI_MULTIMEDIA7,
- },
- {
- .name = "MSM8996 Compress3",
- .stream_name = "Compress3",
- .cpu_dai_name = "MultiMedia10",
- .platform_name = "msm-compress-dsp",
- .dynamic = 1,
- .dpcm_playback = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST},
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- .ignore_suspend = 1,
- .ignore_pmdown_time = 1,
- /* this dainlink has playback support */
- .id = MSM_FRONTEND_DAI_MULTIMEDIA10,
- },
- {
- .name = "MSM8996 ULL NOIRQ",
- .stream_name = "MM_NOIRQ",
- .cpu_dai_name = "MultiMedia8",
- .platform_name = "msm-pcm-dsp-noirq",
- .dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST},
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- .ignore_suspend = 1,
- .ignore_pmdown_time = 1,
- /* this dainlink has playback support */
- .id = MSM_FRONTEND_DAI_MULTIMEDIA8,
- },
- {
- .name = "QCHAT",
- .stream_name = "QCHAT",
- .cpu_dai_name = "QCHAT",
- .platform_name = "msm-pcm-voice",
- .dynamic = 1,
- .dpcm_capture = 1,
- .dpcm_playback = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST},
- .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
- .ignore_suspend = 1,
- /* this dainlink has playback support */
- .ignore_pmdown_time = 1,
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- .id = MSM_FRONTEND_DAI_QCHAT,
- },
- /* HDMI Hostless */
- {
- .name = "HDMI_RX_HOSTLESS",
- .stream_name = "HDMI_RX_HOSTLESS",
- .cpu_dai_name = "HDMI_HOSTLESS",
- .platform_name = "msm-pcm-hostless",
- .dynamic = 1,
- .dpcm_playback = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST},
- .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
- .ignore_suspend = 1,
- .ignore_pmdown_time = 1,
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- },
- {
- .name = "VoiceMMode2",
- .stream_name = "VoiceMMode2",
- .cpu_dai_name = "VoiceMMode2",
- .platform_name = "msm-pcm-voice",
- .dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST},
- .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
- .ignore_suspend = 1,
- .ignore_pmdown_time = 1,
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- .id = MSM_FRONTEND_DAI_VOICEMMODE2,
- },
- {
- .name = "INT_HFP_BT Hostless",
- .stream_name = "INT_HFP_BT Hostless",
- .cpu_dai_name = "INT_HFP_BT_HOSTLESS",
- .platform_name = "msm-pcm-hostless",
- .dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST},
- .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
- .ignore_suspend = 1,
- /* this dainlink has playback support */
- .ignore_pmdown_time = 1,
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- },
- {
- .name = "MSM8996 HFP TX",
- .stream_name = "MultiMedia6",
- .cpu_dai_name = "MultiMedia6",
- .platform_name = "msm-pcm-loopback",
- .dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- .trigger = {SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST},
- .ignore_suspend = 1,
- .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
- /* this dainlink has playback support */
- .ignore_pmdown_time = 1,
- .id = MSM_FRONTEND_DAI_MULTIMEDIA6,
- },
- /* LSM FE */
- {
- .name = "Listen 2 Audio Service",
- .stream_name = "Listen 2 Audio Service",
- .cpu_dai_name = "LSM2",
- .platform_name = "msm-lsm-client",
- .dynamic = 1,
- .dpcm_capture = 1,
- .trigger = { SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST },
- .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
- .ignore_suspend = 1,
- .ignore_pmdown_time = 1,
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- .id = MSM_FRONTEND_DAI_LSM2,
- },
- {
- .name = "Listen 3 Audio Service",
- .stream_name = "Listen 3 Audio Service",
- .cpu_dai_name = "LSM3",
- .platform_name = "msm-lsm-client",
- .dynamic = 1,
- .dpcm_capture = 1,
- .trigger = { SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST },
- .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
- .ignore_suspend = 1,
- .ignore_pmdown_time = 1,
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- .id = MSM_FRONTEND_DAI_LSM3,
- },
- {
- .name = "Listen 4 Audio Service",
- .stream_name = "Listen 4 Audio Service",
- .cpu_dai_name = "LSM4",
- .platform_name = "msm-lsm-client",
- .dynamic = 1,
- .dpcm_capture = 1,
- .trigger = { SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST },
- .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
- .ignore_suspend = 1,
- .ignore_pmdown_time = 1,
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- .id = MSM_FRONTEND_DAI_LSM4,
- },
- {
- .name = "Listen 5 Audio Service",
- .stream_name = "Listen 5 Audio Service",
- .cpu_dai_name = "LSM5",
- .platform_name = "msm-lsm-client",
- .dynamic = 1,
- .dpcm_capture = 1,
- .trigger = { SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST },
- .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
- .ignore_suspend = 1,
- .ignore_pmdown_time = 1,
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- .id = MSM_FRONTEND_DAI_LSM5,
- },
- {
- .name = "Listen 6 Audio Service",
- .stream_name = "Listen 6 Audio Service",
- .cpu_dai_name = "LSM6",
- .platform_name = "msm-lsm-client",
- .dynamic = 1,
- .dpcm_capture = 1,
- .trigger = { SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST },
- .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
- .ignore_suspend = 1,
- .ignore_pmdown_time = 1,
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- .id = MSM_FRONTEND_DAI_LSM6,
- },
- {
- .name = "Listen 7 Audio Service",
- .stream_name = "Listen 7 Audio Service",
- .cpu_dai_name = "LSM7",
- .platform_name = "msm-lsm-client",
- .dynamic = 1,
- .dpcm_capture = 1,
- .trigger = { SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST },
- .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
- .ignore_suspend = 1,
- .ignore_pmdown_time = 1,
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- .id = MSM_FRONTEND_DAI_LSM7,
- },
- {
- .name = "Listen 8 Audio Service",
- .stream_name = "Listen 8 Audio Service",
- .cpu_dai_name = "LSM8",
- .platform_name = "msm-lsm-client",
- .dynamic = 1,
- .dpcm_capture = 1,
- .trigger = { SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST },
- .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
- .ignore_suspend = 1,
- .ignore_pmdown_time = 1,
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- .id = MSM_FRONTEND_DAI_LSM8,
- },
- {
- .name = "MSM8996 Media9",
- .stream_name = "MultiMedia9",
- .cpu_dai_name = "MultiMedia9",
- .platform_name = "msm-pcm-dsp.0",
- .dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST},
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- .ignore_suspend = 1,
- /* this dainlink has playback support */
- .ignore_pmdown_time = 1,
- .id = MSM_FRONTEND_DAI_MULTIMEDIA9,
- },
- {
- .name = "VoWLAN",
- .stream_name = "VoWLAN",
- .cpu_dai_name = "VoWLAN",
- .platform_name = "msm-pcm-voice",
- .dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST},
- .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
- .ignore_suspend = 1,
- .ignore_pmdown_time = 1,
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- .id = MSM_FRONTEND_DAI_VOWLAN,
- },
- {
- .name = "MSM8996 Compress4",
- .stream_name = "Compress4",
- .cpu_dai_name = "MultiMedia11",
- .platform_name = "msm-compress-dsp",
- .dynamic = 1,
- .dpcm_playback = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST},
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- .ignore_suspend = 1,
- .ignore_pmdown_time = 1,
- /* this dainlink has playback support */
- .id = MSM_FRONTEND_DAI_MULTIMEDIA11,
- },
- {
- .name = "MSM8996 Compress5",
- .stream_name = "Compress5",
- .cpu_dai_name = "MultiMedia12",
- .platform_name = "msm-compress-dsp",
- .dynamic = 1,
- .dpcm_playback = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST},
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- .ignore_suspend = 1,
- .ignore_pmdown_time = 1,
- /* this dainlink has playback support */
- .id = MSM_FRONTEND_DAI_MULTIMEDIA12,
- },
- {
- .name = "MSM8996 Compress6",
- .stream_name = "Compress6",
- .cpu_dai_name = "MultiMedia13",
- .platform_name = "msm-compress-dsp",
- .dynamic = 1,
- .dpcm_playback = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST},
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- .ignore_suspend = 1,
- .ignore_pmdown_time = 1,
- /* this dainlink has playback support */
- .id = MSM_FRONTEND_DAI_MULTIMEDIA13,
- },
- {
- .name = "MSM8996 Compress7",
- .stream_name = "Compress7",
- .cpu_dai_name = "MultiMedia14",
- .platform_name = "msm-compress-dsp",
- .dynamic = 1,
- .dpcm_playback = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST},
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- .ignore_suspend = 1,
- .ignore_pmdown_time = 1,
- /* this dainlink has playback support */
- .id = MSM_FRONTEND_DAI_MULTIMEDIA14,
- },
- {
- .name = "MSM8996 Compress8",
- .stream_name = "Compress8",
- .cpu_dai_name = "MultiMedia15",
- .platform_name = "msm-compress-dsp",
- .dynamic = 1,
- .dpcm_playback = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST},
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- .ignore_suspend = 1,
- .ignore_pmdown_time = 1,
- /* this dainlink has playback support */
- .id = MSM_FRONTEND_DAI_MULTIMEDIA15,
- },
- {
- .name = "MSM8996 ULL NOIRQ_2",
- .stream_name = "MM_NOIRQ_2",
- .cpu_dai_name = "MultiMedia16",
- .platform_name = "msm-pcm-dsp-noirq",
- .dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST},
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- .ignore_suspend = 1,
- .ignore_pmdown_time = 1,
- /* this dainlink has playback support */
- .id = MSM_FRONTEND_DAI_MULTIMEDIA16,
- },
- {
- .name = "Circuit-Switch Voice",
- .stream_name = "CS-Voice",
- .cpu_dai_name = "CS-VOICE",
- .platform_name = "msm-pcm-voice",
- .dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- .trigger = {SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST},
- .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
- .ignore_suspend = 1,
- /* this dainlink has playback support */
- .ignore_pmdown_time = 1,
- .id = MSM_FRONTEND_DAI_CS_VOICE,
- },
- {
- .name = "Voice2",
- .stream_name = "Voice2",
- .cpu_dai_name = "Voice2",
- .platform_name = "msm-pcm-voice",
- .dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST},
- .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
- .ignore_suspend = 1,
- /* this dainlink has playback support */
- .ignore_pmdown_time = 1,
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- .id = MSM_FRONTEND_DAI_VOICE2,
- },
-};
-
-static struct snd_soc_dai_link msm8996_tasha_fe_dai_links[] = {
- {
- .name = LPASS_BE_SLIMBUS_4_TX,
- .stream_name = "Slimbus4 Capture",
- .cpu_dai_name = "msm-dai-q6-dev.16393",
- .platform_name = "msm-pcm-hostless",
- .codec_name = "tasha_codec",
- .codec_dai_name = "tasha_vifeedback",
- .id = MSM_BACKEND_DAI_SLIMBUS_4_TX,
- .be_hw_params_fixup = msm_slim_4_tx_be_hw_params_fixup,
- .ops = &msm8996_be_ops,
- .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
- .ignore_suspend = 1,
- },
- /* Ultrasound RX DAI Link */
- {
- .name = "SLIMBUS_2 Hostless Playback",
- .stream_name = "SLIMBUS_2 Hostless Playback",
- .cpu_dai_name = "msm-dai-q6-dev.16388",
- .platform_name = "msm-pcm-hostless",
- .codec_name = "tasha_codec",
- .codec_dai_name = "tasha_rx2",
- .ignore_suspend = 1,
- .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
- .ops = &msm8996_slimbus_2_be_ops,
- },
- /* Ultrasound TX DAI Link */
- {
- .name = "SLIMBUS_2 Hostless Capture",
- .stream_name = "SLIMBUS_2 Hostless Capture",
- .cpu_dai_name = "msm-dai-q6-dev.16389",
- .platform_name = "msm-pcm-hostless",
- .codec_name = "tasha_codec",
- .codec_dai_name = "tasha_tx2",
- .ignore_suspend = 1,
- .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
- .ops = &msm8996_slimbus_2_be_ops,
- },
- /* CPE LSM direct dai-link */
- {
- .name = "CPE Listen service",
- .stream_name = "CPE Listen Audio Service",
- .cpu_dai_name = "msm-dai-slim",
- .platform_name = "msm-cpe-lsm",
- .trigger = {SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST},
- .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
- .ignore_suspend = 1,
- .ignore_pmdown_time = 1,
- .codec_dai_name = "tasha_mad1",
- .codec_name = "tasha_codec",
- .ops = &msm8996_cpe_ops,
- },
- /* slimbus rx 6 hostless */
- {
- .name = "SLIMBUS_6 Hostless Playback",
- .stream_name = "SLIMBUS_6 Hostless",
- .cpu_dai_name = "SLIMBUS6_HOSTLESS",
- .platform_name = "msm-pcm-hostless",
- .dynamic = 1,
- .dpcm_playback = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST},
- .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
- .ignore_suspend = 1,
- /* this dailink has playback support */
- .ignore_pmdown_time = 1,
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- },
- /* CPE LSM EC PP direct dai-link */
- {
- .name = "CPE Listen service ECPP",
- .stream_name = "CPE Listen Audio Service ECPP",
- .cpu_dai_name = "CPE_LSM_NOHOST",
- .platform_name = "msm-cpe-lsm.3",
- .trigger = {SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST},
- .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
- .ignore_suspend = 1,
- .ignore_pmdown_time = 1,
- .codec_dai_name = "tasha_cpe",
- .codec_name = "tasha_codec",
- },
-};
-
-static struct snd_soc_dai_link msm8996_common_be_dai_links[] = {
- /* Backend AFE DAI Links */
- {
- .name = LPASS_BE_AFE_PCM_RX,
- .stream_name = "AFE Playback",
- .cpu_dai_name = "msm-dai-q6-dev.224",
- .platform_name = "msm-pcm-routing",
- .codec_name = "msm-stub-codec.1",
- .codec_dai_name = "msm-stub-rx",
- .no_pcm = 1,
- .dpcm_playback = 1,
- .id = MSM_BACKEND_DAI_AFE_PCM_RX,
- .be_hw_params_fixup = msm_proxy_rx_be_hw_params_fixup,
- /* this dainlink has playback support */
- .ignore_pmdown_time = 1,
- .ignore_suspend = 1,
- },
- {
- .name = LPASS_BE_AFE_PCM_TX,
- .stream_name = "AFE Capture",
- .cpu_dai_name = "msm-dai-q6-dev.225",
- .platform_name = "msm-pcm-routing",
- .codec_name = "msm-stub-codec.1",
- .codec_dai_name = "msm-stub-tx",
- .no_pcm = 1,
- .dpcm_capture = 1,
- .id = MSM_BACKEND_DAI_AFE_PCM_TX,
- .be_hw_params_fixup = msm_proxy_tx_be_hw_params_fixup,
- .ignore_suspend = 1,
- },
- /* Primary AUX PCM Backend DAI Links */
- {
- .name = LPASS_BE_AUXPCM_RX,
- .stream_name = "AUX PCM Playback",
- .cpu_dai_name = "msm-dai-q6-auxpcm.1",
- .platform_name = "msm-pcm-routing",
- .codec_name = "msm-stub-codec.1",
- .codec_dai_name = "msm-stub-rx",
- .no_pcm = 1,
- .dpcm_playback = 1,
- .id = MSM_BACKEND_DAI_AUXPCM_RX,
- .be_hw_params_fixup = msm_auxpcm_be_params_fixup,
- .ignore_pmdown_time = 1,
- .ignore_suspend = 1,
- /* this dainlink has playback support */
- },
- {
- .name = LPASS_BE_AUXPCM_TX,
- .stream_name = "AUX PCM Capture",
- .cpu_dai_name = "msm-dai-q6-auxpcm.1",
- .platform_name = "msm-pcm-routing",
- .codec_name = "msm-stub-codec.1",
- .codec_dai_name = "msm-stub-tx",
- .no_pcm = 1,
- .dpcm_capture = 1,
- .id = MSM_BACKEND_DAI_AUXPCM_TX,
- .be_hw_params_fixup = msm_auxpcm_be_params_fixup,
- .ignore_suspend = 1,
- },
- /* Incall Record Uplink BACK END DAI Link */
- {
- .name = LPASS_BE_INCALL_RECORD_TX,
- .stream_name = "Voice Uplink Capture",
- .cpu_dai_name = "msm-dai-q6-dev.32772",
- .platform_name = "msm-pcm-routing",
- .codec_name = "msm-stub-codec.1",
- .codec_dai_name = "msm-stub-tx",
- .no_pcm = 1,
- .dpcm_capture = 1,
- .id = MSM_BACKEND_DAI_INCALL_RECORD_TX,
- .be_hw_params_fixup = msm_be_hw_params_fixup,
- .ignore_suspend = 1,
- },
- /* Incall Record Downlink BACK END DAI Link */
- {
- .name = LPASS_BE_INCALL_RECORD_RX,
- .stream_name = "Voice Downlink Capture",
- .cpu_dai_name = "msm-dai-q6-dev.32771",
- .platform_name = "msm-pcm-routing",
- .codec_name = "msm-stub-codec.1",
- .codec_dai_name = "msm-stub-tx",
- .no_pcm = 1,
- .dpcm_capture = 1,
- .id = MSM_BACKEND_DAI_INCALL_RECORD_RX,
- .be_hw_params_fixup = msm_be_hw_params_fixup,
- .ignore_suspend = 1,
- },
- /* Incall Music BACK END DAI Link */
- {
- .name = LPASS_BE_VOICE_PLAYBACK_TX,
- .stream_name = "Voice Farend Playback",
- .cpu_dai_name = "msm-dai-q6-dev.32773",
- .platform_name = "msm-pcm-routing",
- .codec_name = "msm-stub-codec.1",
- .codec_dai_name = "msm-stub-rx",
- .no_pcm = 1,
- .dpcm_playback = 1,
- .id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
- .be_hw_params_fixup = msm_be_hw_params_fixup,
- .ignore_suspend = 1,
- },
- /* Incall Music 2 BACK END DAI Link */
- {
- .name = LPASS_BE_VOICE2_PLAYBACK_TX,
- .stream_name = "Voice2 Farend Playback",
- .cpu_dai_name = "msm-dai-q6-dev.32770",
- .platform_name = "msm-pcm-routing",
- .codec_name = "msm-stub-codec.1",
- .codec_dai_name = "msm-stub-rx",
- .no_pcm = 1,
- .dpcm_playback = 1,
- .id = MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX,
- .be_hw_params_fixup = msm_be_hw_params_fixup,
- .ignore_suspend = 1,
- },
- {
- .name = LPASS_BE_TERT_MI2S_TX,
- .stream_name = "Tertiary MI2S Capture",
- .cpu_dai_name = "msm-dai-q6-mi2s.2",
- .platform_name = "msm-pcm-routing",
- .codec_name = "msm-stub-codec.1",
- .codec_dai_name = "msm-stub-tx",
- .no_pcm = 1,
- .dpcm_capture = 1,
- .id = MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
- .be_hw_params_fixup = msm_tx_be_hw_params_fixup,
- .ops = &msm8996_mi2s_be_ops,
- .ignore_suspend = 1,
- }
-};
-
-static struct snd_soc_dai_link msm8996_tasha_be_dai_links[] = {
- /* Backend DAI Links */
- {
- .name = LPASS_BE_SLIMBUS_0_RX,
- .stream_name = "Slimbus Playback",
- .cpu_dai_name = "msm-dai-q6-dev.16384",
- .platform_name = "msm-pcm-routing",
- .codec_name = "tasha_codec",
- .codec_dai_name = "tasha_mix_rx1",
- .no_pcm = 1,
- .dpcm_playback = 1,
- .id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
- .init = &msm_audrx_init,
- .be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
- /* this dainlink has playback support */
- .ignore_pmdown_time = 1,
- .ignore_suspend = 1,
- .ops = &msm8996_be_ops,
- },
- {
- .name = LPASS_BE_SLIMBUS_0_TX,
- .stream_name = "Slimbus Capture",
- .cpu_dai_name = "msm-dai-q6-dev.16385",
- .platform_name = "msm-pcm-routing",
- .codec_name = "tasha_codec",
- .codec_dai_name = "tasha_tx1",
- .no_pcm = 1,
- .dpcm_capture = 1,
- .id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
- .be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
- .ignore_suspend = 1,
- .ops = &msm8996_be_ops,
- },
- {
- .name = LPASS_BE_SLIMBUS_1_RX,
- .stream_name = "Slimbus1 Playback",
- .cpu_dai_name = "msm-dai-q6-dev.16386",
- .platform_name = "msm-pcm-routing",
- .codec_name = "tasha_codec",
- .codec_dai_name = "tasha_mix_rx1",
- .no_pcm = 1,
- .dpcm_playback = 1,
- .id = MSM_BACKEND_DAI_SLIMBUS_1_RX,
- .be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
- .ops = &msm8996_be_ops,
- /* dai link has playback support */
- .ignore_pmdown_time = 1,
- .ignore_suspend = 1,
- },
- {
- .name = LPASS_BE_SLIMBUS_1_TX,
- .stream_name = "Slimbus1 Capture",
- .cpu_dai_name = "msm-dai-q6-dev.16387",
- .platform_name = "msm-pcm-routing",
- .codec_name = "tasha_codec",
- .codec_dai_name = "tasha_tx3",
- .no_pcm = 1,
- .dpcm_capture = 1,
- .id = MSM_BACKEND_DAI_SLIMBUS_1_TX,
- .be_hw_params_fixup = msm_slim_1_tx_be_hw_params_fixup,
- .ops = &msm8996_be_ops,
- .ignore_suspend = 1,
- },
- {
- .name = LPASS_BE_SLIMBUS_3_RX,
- .stream_name = "Slimbus3 Playback",
- .cpu_dai_name = "msm-dai-q6-dev.16390",
- .platform_name = "msm-pcm-routing",
- .codec_name = "tasha_codec",
- .codec_dai_name = "tasha_mix_rx1",
- .no_pcm = 1,
- .dpcm_playback = 1,
- .id = MSM_BACKEND_DAI_SLIMBUS_3_RX,
- .be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
- .ops = &msm8996_be_ops,
- /* dai link has playback support */
- .ignore_pmdown_time = 1,
- .ignore_suspend = 1,
- },
- {
- .name = LPASS_BE_SLIMBUS_3_TX,
- .stream_name = "Slimbus3 Capture",
- .cpu_dai_name = "msm-dai-q6-dev.16391",
- .platform_name = "msm-pcm-routing",
- .codec_name = "tasha_codec",
- .codec_dai_name = "tasha_tx1",
- .no_pcm = 1,
- .dpcm_capture = 1,
- .id = MSM_BACKEND_DAI_SLIMBUS_3_TX,
- .be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
- .ops = &msm8996_be_ops,
- .ignore_suspend = 1,
- },
- {
- .name = LPASS_BE_SLIMBUS_4_RX,
- .stream_name = "Slimbus4 Playback",
- .cpu_dai_name = "msm-dai-q6-dev.16392",
- .platform_name = "msm-pcm-routing",
- .codec_name = "tasha_codec",
- .codec_dai_name = "tasha_mix_rx1",
- .no_pcm = 1,
- .dpcm_playback = 1,
- .id = MSM_BACKEND_DAI_SLIMBUS_4_RX,
- .be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
- .ops = &msm8996_be_ops,
- /* dai link has playback support */
- .ignore_pmdown_time = 1,
- .ignore_suspend = 1,
- },
- {
- .name = LPASS_BE_SLIMBUS_5_RX,
- .stream_name = "Slimbus5 Playback",
- .cpu_dai_name = "msm-dai-q6-dev.16394",
- .platform_name = "msm-pcm-routing",
- .codec_name = "tasha_codec",
- .codec_dai_name = "tasha_rx3",
- .no_pcm = 1,
- .dpcm_playback = 1,
- .id = MSM_BACKEND_DAI_SLIMBUS_5_RX,
- .be_hw_params_fixup = msm_slim_5_rx_be_hw_params_fixup,
- .ops = &msm8996_be_ops,
- /* dai link has playback support */
- .ignore_pmdown_time = 1,
- .ignore_suspend = 1,
- },
- /* MAD BE */
- {
- .name = LPASS_BE_SLIMBUS_5_TX,
- .stream_name = "Slimbus5 Capture",
- .cpu_dai_name = "msm-dai-q6-dev.16395",
- .platform_name = "msm-pcm-routing",
- .codec_name = "tasha_codec",
- .codec_dai_name = "tasha_mad1",
- .no_pcm = 1,
- .dpcm_capture = 1,
- .id = MSM_BACKEND_DAI_SLIMBUS_5_TX,
- .be_hw_params_fixup = msm_slim_5_tx_be_hw_params_fixup,
- .ops = &msm8996_be_ops,
- .ignore_suspend = 1,
- },
- {
- .name = LPASS_BE_SLIMBUS_6_RX,
- .stream_name = "Slimbus6 Playback",
- .cpu_dai_name = "msm-dai-q6-dev.16396",
- .platform_name = "msm-pcm-routing",
- .codec_name = "tasha_codec",
- .codec_dai_name = "tasha_rx4",
- .no_pcm = 1,
- .dpcm_playback = 1,
- .id = MSM_BACKEND_DAI_SLIMBUS_6_RX,
- .be_hw_params_fixup = msm_slim_6_rx_be_hw_params_fixup,
- .ops = &msm8996_be_ops,
- /* dai link has playback support */
- .ignore_pmdown_time = 1,
- .ignore_suspend = 1,
- },
-};
-
-static struct snd_soc_dai_link msm8996_hdmi_dai_link[] = {
- /* HDMI BACK END DAI Link */
- {
- .name = LPASS_BE_HDMI,
- .stream_name = "HDMI Playback",
- .cpu_dai_name = "msm-dai-q6-hdmi.8",
- .platform_name = "msm-pcm-routing",
- .codec_name = "msm-hdmi-audio-codec-rx",
- .codec_dai_name = "msm_hdmi_audio_codec_rx_dai",
- .no_pcm = 1,
- .dpcm_playback = 1,
- .id = MSM_BACKEND_DAI_HDMI_RX,
- .be_hw_params_fixup = msm8996_hdmi_be_hw_params_fixup,
- .ignore_pmdown_time = 1,
- .ignore_suspend = 1,
- },
-};
-
-static struct snd_soc_dai_link msm8996_tasha_dai_links[
- ARRAY_SIZE(msm8996_common_dai_links) +
- ARRAY_SIZE(msm8996_tasha_fe_dai_links) +
- ARRAY_SIZE(msm8996_common_be_dai_links) +
- ARRAY_SIZE(msm8996_tasha_be_dai_links) +
- ARRAY_SIZE(msm8996_hdmi_dai_link)];
-
-static int msm8996_wsa881x_init(struct snd_soc_component *component)
-{
- u8 spkleft_ports[WSA881X_MAX_SWR_PORTS] = {100, 101, 102, 106};
- u8 spkright_ports[WSA881X_MAX_SWR_PORTS] = {103, 104, 105, 107};
- unsigned int ch_rate[WSA881X_MAX_SWR_PORTS] = {2400, 600, 300, 1200};
- unsigned int ch_mask[WSA881X_MAX_SWR_PORTS] = {0x1, 0xF, 0x3, 0x3};
- struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
- struct msm8996_asoc_mach_data *pdata;
- struct snd_soc_dapm_context *dapm;
-
- if (!codec) {
- pr_err("%s codec is NULL\n", __func__);
- return -EINVAL;
- }
-
- dapm = snd_soc_codec_get_dapm(codec);
-
- if (!strcmp(component->name_prefix, "SpkrLeft")) {
- dev_dbg(codec->dev, "%s: setting left ch map to codec %s\n",
- __func__, codec->component.name);
- wsa881x_set_channel_map(codec, &spkleft_ports[0],
- WSA881X_MAX_SWR_PORTS, &ch_mask[0],
- &ch_rate[0]);
- if (dapm->component) {
- snd_soc_dapm_ignore_suspend(dapm, "SpkrLeft IN");
- snd_soc_dapm_ignore_suspend(dapm, "SpkrLeft SPKR");
- }
- } else if (!strcmp(component->name_prefix, "SpkrRight")) {
- dev_dbg(codec->dev, "%s: setting right ch map to codec %s\n",
- __func__, codec->component.name);
- wsa881x_set_channel_map(codec, &spkright_ports[0],
- WSA881X_MAX_SWR_PORTS, &ch_mask[0],
- &ch_rate[0]);
- if (dapm->component) {
- snd_soc_dapm_ignore_suspend(dapm, "SpkrRight IN");
- snd_soc_dapm_ignore_suspend(dapm, "SpkrRight SPKR");
- }
- } else {
- dev_err(codec->dev, "%s: wrong codec name %s\n", __func__,
- codec->component.name);
- return -EINVAL;
- }
- pdata = snd_soc_card_get_drvdata(component->card);
- if (pdata && pdata->codec_root)
- wsa881x_codec_info_create_codec_entry(pdata->codec_root,
- codec);
-
- return 0;
-}
-
-struct snd_soc_card snd_soc_card_tasha_msm8996 = {
- .name = "msm8996-tasha-snd-card",
-};
-
-static int msm8996_populate_dai_link_component_of_node(
- struct snd_soc_card *card)
-{
- int i, index, ret = 0;
- struct device *cdev = card->dev;
- struct snd_soc_dai_link *dai_link = card->dai_link;
- struct device_node *np;
-
- if (!cdev) {
- pr_err("%s: Sound card device memory NULL\n", __func__);
- return -ENODEV;
- }
-
- for (i = 0; i < card->num_links; i++) {
- if (dai_link[i].platform_of_node && dai_link[i].cpu_of_node)
- continue;
-
- /* populate platform_of_node for snd card dai links */
- if (dai_link[i].platform_name &&
- !dai_link[i].platform_of_node) {
- index = of_property_match_string(cdev->of_node,
- "asoc-platform-names",
- dai_link[i].platform_name);
- if (index < 0) {
- pr_err("%s: No match found for platform name: %s\n",
- __func__, dai_link[i].platform_name);
- ret = index;
- goto err;
- }
- np = of_parse_phandle(cdev->of_node, "asoc-platform",
- index);
- if (!np) {
- pr_err("%s: retrieving phandle for platform %s, index %d failed\n",
- __func__, dai_link[i].platform_name,
- index);
- ret = -ENODEV;
- goto err;
- }
- dai_link[i].platform_of_node = np;
- dai_link[i].platform_name = NULL;
- }
-
- /* populate cpu_of_node for snd card dai links */
- if (dai_link[i].cpu_dai_name && !dai_link[i].cpu_of_node) {
- index = of_property_match_string(cdev->of_node,
- "asoc-cpu-names",
- dai_link[i].cpu_dai_name);
- if (index >= 0) {
- np = of_parse_phandle(cdev->of_node, "asoc-cpu",
- index);
- if (!np) {
- pr_err("%s: retrieving phandle for cpu dai %s failed\n",
- __func__,
- dai_link[i].cpu_dai_name);
- ret = -ENODEV;
- goto err;
- }
- dai_link[i].cpu_of_node = np;
- dai_link[i].cpu_dai_name = NULL;
- }
- }
-
- /* populate codec_of_node for snd card dai links */
- if (dai_link[i].codec_name && !dai_link[i].codec_of_node) {
- index = of_property_match_string(cdev->of_node,
- "asoc-codec-names",
- dai_link[i].codec_name);
- if (index < 0)
- continue;
- np = of_parse_phandle(cdev->of_node, "asoc-codec",
- index);
- if (!np) {
- pr_err("%s: retrieving phandle for codec %s failed\n",
- __func__, dai_link[i].codec_name);
- ret = -ENODEV;
- goto err;
- }
- dai_link[i].codec_of_node = np;
- dai_link[i].codec_name = NULL;
- }
- }
-
-err:
- return ret;
-}
-
-static int msm8996_prepare_us_euro(struct snd_soc_card *card)
-{
- struct msm8996_asoc_mach_data *pdata =
- snd_soc_card_get_drvdata(card);
- int ret;
-
- if (pdata->us_euro_gpio >= 0) {
- dev_dbg(card->dev, "%s: us_euro gpio request %d", __func__,
- pdata->us_euro_gpio);
- ret = gpio_request(pdata->us_euro_gpio, "TASHA_CODEC_US_EURO");
- if (ret) {
- dev_err(card->dev,
- "%s: Failed to request codec US/EURO gpio %d error %d\n",
- __func__, pdata->us_euro_gpio, ret);
- return ret;
- }
- }
-
- return 0;
-}
-
-static int msm8996_prepare_hifi(struct snd_soc_card *card)
-{
- struct msm8996_asoc_mach_data *pdata =
- snd_soc_card_get_drvdata(card);
- int ret;
-
- if (gpio_is_valid(pdata->hph_en1_gpio)) {
- dev_dbg(card->dev, "%s: hph_en1_gpio request %d\n", __func__,
- pdata->hph_en1_gpio);
- ret = gpio_request(pdata->hph_en1_gpio, "hph_en1_gpio");
- if (ret) {
- dev_err(card->dev,
- "%s: hph_en1_gpio request failed, ret:%d\n",
- __func__, ret);
- return ret;
- }
- }
- if (gpio_is_valid(pdata->hph_en0_gpio)) {
- dev_dbg(card->dev, "%s: hph_en0_gpio request %d\n", __func__,
- pdata->hph_en0_gpio);
- ret = gpio_request(pdata->hph_en0_gpio, "hph_en0_gpio");
- if (ret) {
- dev_err(card->dev,
- "%s: hph_en0_gpio request failed, ret:%d\n",
- __func__, ret);
- return ret;
- }
- }
- return 0;
-}
-
-static const struct of_device_id msm8996_asoc_machine_of_match[] = {
- { .compatible = "qcom,msm8996-asoc-snd-tasha",
- .data = "tasha_codec"},
- {},
-};
-
-static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
-{
- struct snd_soc_card *card = NULL;
- struct snd_soc_dai_link *dailink;
- int len_1, len_2, len_3, len_4;
- const struct of_device_id *match;
-
- match = of_match_node(msm8996_asoc_machine_of_match, dev->of_node);
- if (!match) {
- dev_err(dev, "%s: No DT match found for sound card\n",
- __func__);
- return NULL;
- }
-
- if (!strcmp(match->data, "tasha_codec")) {
- card = &snd_soc_card_tasha_msm8996;
- len_1 = ARRAY_SIZE(msm8996_common_dai_links);
- len_2 = len_1 + ARRAY_SIZE(msm8996_tasha_fe_dai_links);
- len_3 = len_2 + ARRAY_SIZE(msm8996_common_be_dai_links);
-
- memcpy(msm8996_tasha_dai_links,
- msm8996_common_dai_links,
- sizeof(msm8996_common_dai_links));
- memcpy(msm8996_tasha_dai_links + len_1,
- msm8996_tasha_fe_dai_links,
- sizeof(msm8996_tasha_fe_dai_links));
- memcpy(msm8996_tasha_dai_links + len_2,
- msm8996_common_be_dai_links,
- sizeof(msm8996_common_be_dai_links));
- memcpy(msm8996_tasha_dai_links + len_3,
- msm8996_tasha_be_dai_links,
- sizeof(msm8996_tasha_be_dai_links));
-
- dailink = msm8996_tasha_dai_links;
- len_4 = len_3 + ARRAY_SIZE(msm8996_tasha_be_dai_links);
- }
-
- if (of_property_read_bool(dev->of_node, "qcom,hdmi-audio-rx")) {
- dev_dbg(dev, "%s(): hdmi audio support present\n",
- __func__);
- memcpy(dailink + len_4, msm8996_hdmi_dai_link,
- sizeof(msm8996_hdmi_dai_link));
- len_4 += ARRAY_SIZE(msm8996_hdmi_dai_link);
- } else {
- dev_dbg(dev, "%s(): No hdmi audio support\n", __func__);
- }
-
- if (card) {
- card->dai_link = dailink;
- card->num_links = len_4;
- }
-
- return card;
-}
-
-static int msm8996_init_wsa_dev(struct platform_device *pdev,
- struct snd_soc_card *card)
-{
- struct device_node *wsa_of_node;
- u32 wsa_max_devs;
- u32 wsa_dev_cnt;
- char *dev_name_str = NULL;
- struct msm8996_wsa881x_dev_info *wsa881x_dev_info;
- const char *wsa_auxdev_name_prefix[1];
- int found = 0;
- int i;
- int ret;
-
- /* Get maximum WSA device count for this platform */
- ret = of_property_read_u32(pdev->dev.of_node,
- "qcom,wsa-max-devs", &wsa_max_devs);
- if (ret) {
- dev_dbg(&pdev->dev,
- "%s: wsa-max-devs property missing in DT %s, ret = %d\n",
- __func__, pdev->dev.of_node->full_name, ret);
- return 0;
- }
- if (wsa_max_devs == 0) {
- dev_warn(&pdev->dev,
- "%s: Max WSA devices is 0 for this target?\n",
- __func__);
- return 0;
- }
-
- /* Get count of WSA device phandles for this platform */
- wsa_dev_cnt = of_count_phandle_with_args(pdev->dev.of_node,
- "qcom,wsa-devs", NULL);
- if (wsa_dev_cnt == -ENOENT) {
- dev_warn(&pdev->dev, "%s: No wsa device defined in DT.\n",
- __func__);
- return 0;
- } else if (wsa_dev_cnt <= 0) {
- dev_err(&pdev->dev,
- "%s: Error reading wsa device from DT. wsa_dev_cnt = %d\n",
- __func__, wsa_dev_cnt);
- return -EINVAL;
- }
-
- /*
- * Expect total phandles count to be NOT less than maximum possible
- * WSA count. However, if it is less, then assign same value to
- * max count as well.
- */
- if (wsa_dev_cnt < wsa_max_devs) {
- dev_dbg(&pdev->dev,
- "%s: wsa_max_devs = %d cannot exceed wsa_dev_cnt = %d\n",
- __func__, wsa_max_devs, wsa_dev_cnt);
- wsa_max_devs = wsa_dev_cnt;
- }
-
- /* Make sure prefix string passed for each WSA device */
- ret = of_property_count_strings(pdev->dev.of_node,
- "qcom,wsa-aux-dev-prefix");
- if (ret != wsa_dev_cnt) {
- dev_err(&pdev->dev,
- "%s: expecting %d wsa prefix. Defined only %d in DT\n",
- __func__, wsa_dev_cnt, ret);
- return -EINVAL;
- }
-
- /*
- * Alloc mem to store phandle and index info of WSA device, if already
- * registered with ALSA core
- */
- wsa881x_dev_info = devm_kcalloc(&pdev->dev, wsa_max_devs,
- sizeof(struct msm8996_wsa881x_dev_info),
- GFP_KERNEL);
- if (!wsa881x_dev_info)
- return -ENOMEM;
-
- /*
- * search and check whether all WSA devices are already
- * registered with ALSA core or not. If found a node, store
- * the node and the index in a local array of struct for later
- * use.
- */
- for (i = 0; i < wsa_dev_cnt; i++) {
- wsa_of_node = of_parse_phandle(pdev->dev.of_node,
- "qcom,wsa-devs", i);
- if (unlikely(!wsa_of_node)) {
- /* we should not be here */
- dev_err(&pdev->dev,
- "%s: wsa dev node is not present\n",
- __func__);
- return -EINVAL;
- }
- if (soc_find_component(wsa_of_node, NULL)) {
- /* WSA device registered with ALSA core */
- wsa881x_dev_info[found].of_node = wsa_of_node;
- wsa881x_dev_info[found].index = i;
- found++;
- if (found == wsa_max_devs)
- break;
- }
- }
-
- if (found < wsa_max_devs) {
- dev_dbg(&pdev->dev,
- "%s: failed to find %d components. Found only %d\n",
- __func__, wsa_max_devs, found);
- return -EPROBE_DEFER;
- }
- dev_info(&pdev->dev,
- "%s: found %d wsa881x devices registered with ALSA core\n",
- __func__, found);
-
- card->num_aux_devs = wsa_max_devs;
- card->num_configs = wsa_max_devs;
-
- /* Alloc array of AUX devs struct */
- msm8996_aux_dev = devm_kcalloc(&pdev->dev, card->num_aux_devs,
- sizeof(struct snd_soc_aux_dev),
- GFP_KERNEL);
- if (!msm8996_aux_dev)
- return -ENOMEM;
-
- /* Alloc array of codec conf struct */
- msm8996_codec_conf = devm_kcalloc(&pdev->dev, card->num_aux_devs,
- sizeof(struct snd_soc_codec_conf),
- GFP_KERNEL);
- if (!msm8996_codec_conf)
- return -ENOMEM;
-
- for (i = 0; i < card->num_aux_devs; i++) {
- dev_name_str = devm_kzalloc(&pdev->dev, DEV_NAME_STR_LEN,
- GFP_KERNEL);
- if (!dev_name_str)
- return -ENOMEM;
-
- ret = of_property_read_string_index(pdev->dev.of_node,
- "qcom,wsa-aux-dev-prefix",
- wsa881x_dev_info[i].index,
- wsa_auxdev_name_prefix);
- if (ret) {
- dev_err(&pdev->dev,
- "%s: failed to read wsa aux dev prefix, ret = %d\n",
- __func__, ret);
- return -EINVAL;
- }
-
- snprintf(dev_name_str, strlen("wsa881x.%d"), "wsa881x.%d", i);
- msm8996_aux_dev[i].name = dev_name_str;
- msm8996_aux_dev[i].codec_name = NULL;
- msm8996_aux_dev[i].codec_of_node =
- wsa881x_dev_info[i].of_node;
- msm8996_aux_dev[i].init = msm8996_wsa881x_init;
- msm8996_codec_conf[i].dev_name = NULL;
- msm8996_codec_conf[i].name_prefix = wsa_auxdev_name_prefix[0];
- msm8996_codec_conf[i].of_node =
- wsa881x_dev_info[i].of_node;
- }
- card->codec_conf = msm8996_codec_conf;
- card->aux_dev = msm8996_aux_dev;
-
- return 0;
-}
-
-static int msm8996_asoc_machine_probe(struct platform_device *pdev)
-{
- struct snd_soc_card *card;
- struct msm8996_asoc_mach_data *pdata;
- const char *mbhc_audio_jack_type = NULL;
- char *mclk_freq_prop_name;
- const struct of_device_id *match;
- int ret;
-
- if (!pdev->dev.of_node) {
- dev_err(&pdev->dev, "No platform supplied from device tree\n");
- return -EINVAL;
- }
-
- pdata = devm_kzalloc(&pdev->dev,
- sizeof(struct msm8996_asoc_mach_data), GFP_KERNEL);
- if (!pdata)
- return -ENOMEM;
-
- card = populate_snd_card_dailinks(&pdev->dev);
- if (!card) {
- dev_err(&pdev->dev, "%s: Card uninitialized\n", __func__);
- ret = -EINVAL;
- goto err;
- }
- card->dev = &pdev->dev;
- platform_set_drvdata(pdev, card);
- snd_soc_card_set_drvdata(card, pdata);
-
- ret = snd_soc_of_parse_card_name(card, "qcom,model");
- if (ret) {
- dev_err(&pdev->dev, "parse card name failed, err:%d\n",
- ret);
- goto err;
- }
-
- ret = snd_soc_of_parse_audio_routing(card, "qcom,audio-routing");
- if (ret) {
- dev_err(&pdev->dev, "parse audio routing failed, err:%d\n",
- ret);
- goto err;
- }
-
- match = of_match_node(msm8996_asoc_machine_of_match,
- pdev->dev.of_node);
- if (!match) {
- dev_err(&pdev->dev, "%s: no matched codec is found.\n",
- __func__);
- goto err;
- }
-
- mclk_freq_prop_name = "qcom,tasha-mclk-clk-freq";
-
- ret = of_property_read_u32(pdev->dev.of_node,
- mclk_freq_prop_name, &pdata->mclk_freq);
- if (ret) {
- dev_err(&pdev->dev,
- "Looking up %s property in node %s failed, err%d\n",
- mclk_freq_prop_name,
- pdev->dev.of_node->full_name, ret);
- goto err;
- }
-
- if (pdata->mclk_freq != CODEC_EXT_CLK_RATE) {
- dev_err(&pdev->dev, "unsupported mclk freq %u\n",
- pdata->mclk_freq);
- ret = -EINVAL;
- goto err;
- }
-
- spdev = pdev;
-
- ret = msm8996_populate_dai_link_component_of_node(card);
- if (ret) {
- ret = -EPROBE_DEFER;
- goto err;
- }
-
- ret = msm8996_init_wsa_dev(pdev, card);
- if (ret)
- goto err;
-
- pdata->hph_en1_gpio = of_get_named_gpio(pdev->dev.of_node,
- "qcom,hph-en1-gpio", 0);
- if (pdata->hph_en1_gpio < 0) {
- dev_dbg(&pdev->dev, "%s: %s property not found %d\n",
- __func__, "qcom,hph-en1-gpio", pdata->hph_en1_gpio);
- }
-
- pdata->hph_en0_gpio = of_get_named_gpio(pdev->dev.of_node,
- "qcom,hph-en0-gpio", 0);
- if (pdata->hph_en0_gpio < 0) {
- dev_dbg(&pdev->dev, "%s: %s property not found %d\n",
- __func__, "qcom,hph-en0-gpio", pdata->hph_en0_gpio);
- }
- ret = msm8996_prepare_hifi(card);
- if (ret)
- dev_dbg(&pdev->dev, "msm8996_prepare_hifi failed (%d)\n",
- ret);
-
- ret = snd_soc_register_card(card);
- if (ret == -EPROBE_DEFER) {
- if (codec_reg_done)
- ret = -EINVAL;
- goto err;
- } else if (ret) {
- dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
- ret);
- goto err;
- }
- dev_info(&pdev->dev, "Sound card %s registered\n", card->name);
-
- ret = of_property_read_string(pdev->dev.of_node,
- "qcom,mbhc-audio-jack-type", &mbhc_audio_jack_type);
- if (ret) {
- dev_dbg(&pdev->dev, "Looking up %s property in node %s failed",
- "qcom,mbhc-audio-jack-type",
- pdev->dev.of_node->full_name);
- dev_dbg(&pdev->dev, "Jack type properties set to default");
- } else {
- if (!strcmp(mbhc_audio_jack_type, "4-pole-jack"))
- dev_dbg(&pdev->dev, "This hardware has 4 pole jack");
- else if (!strcmp(mbhc_audio_jack_type, "5-pole-jack"))
- dev_dbg(&pdev->dev, "This hardware has 5 pole jack");
- else if (!strcmp(mbhc_audio_jack_type, "6-pole-jack"))
- dev_dbg(&pdev->dev, "This hardware has 6 pole jack");
- else
- dev_dbg(&pdev->dev, "Unknown value, set to default");
- }
- /*
- * Parse US-Euro gpio info from DT. Report no error if us-euro
- * entry is not found in DT file as some targets do not support
- * US-Euro detection
- */
- pdata->us_euro_gpio = of_get_named_gpio(pdev->dev.of_node,
- "qcom,us-euro-gpios", 0);
- if (pdata->us_euro_gpio < 0) {
- dev_info(&pdev->dev, "property %s not detected in node %s",
- "qcom,us-euro-gpios",
- pdev->dev.of_node->full_name);
- } else {
- dev_dbg(&pdev->dev, "%s detected %d",
- "qcom,us-euro-gpios", pdata->us_euro_gpio);
- wcd_mbhc_cfg.swap_gnd_mic = msm8996_swap_gnd_mic;
- }
-
- ret = msm8996_prepare_us_euro(card);
- if (ret)
- dev_info(&pdev->dev, "msm8996_prepare_us_euro failed (%d)\n",
- ret);
- return 0;
-err:
- if (pdata->us_euro_gpio > 0) {
- dev_dbg(&pdev->dev, "%s free us_euro gpio %d\n",
- __func__, pdata->us_euro_gpio);
- gpio_free(pdata->us_euro_gpio);
- pdata->us_euro_gpio = 0;
- }
- if (pdata->hph_en1_gpio > 0) {
- dev_dbg(&pdev->dev, "%s free hph_en1_gpio %d\n",
- __func__, pdata->hph_en1_gpio);
- gpio_free(pdata->hph_en1_gpio);
- pdata->hph_en1_gpio = 0;
- }
- if (pdata->hph_en0_gpio > 0) {
- dev_dbg(&pdev->dev, "%s free hph_en0_gpio %d\n",
- __func__, pdata->hph_en0_gpio);
- gpio_free(pdata->hph_en0_gpio);
- pdata->hph_en0_gpio = 0;
- }
- devm_kfree(&pdev->dev, pdata);
- return ret;
-}
-
-static int msm8996_asoc_machine_remove(struct platform_device *pdev)
-{
- struct snd_soc_card *card = platform_get_drvdata(pdev);
- struct msm8996_asoc_mach_data *pdata =
- snd_soc_card_get_drvdata(card);
-
- if (gpio_is_valid(ext_us_amp_gpio))
- gpio_free(ext_us_amp_gpio);
-
- gpio_free(pdata->us_euro_gpio);
- gpio_free(pdata->hph_en1_gpio);
- gpio_free(pdata->hph_en0_gpio);
-
- if (msm8996_liquid_dock_dev != NULL) {
- switch_dev_unregister(&msm8996_liquid_dock_dev->audio_sdev);
-
- if (msm8996_liquid_dock_dev->dock_plug_irq)
- free_irq(msm8996_liquid_dock_dev->dock_plug_irq,
- msm8996_liquid_dock_dev);
-
- if (msm8996_liquid_dock_dev->dock_plug_gpio)
- gpio_free(msm8996_liquid_dock_dev->dock_plug_gpio);
-
- kfree(msm8996_liquid_dock_dev);
- msm8996_liquid_dock_dev = NULL;
- }
- snd_soc_unregister_card(card);
-
- return 0;
-}
-
-static struct platform_driver msm8996_asoc_machine_driver = {
- .driver = {
- .name = DRV_NAME,
- .owner = THIS_MODULE,
- .pm = &snd_soc_pm_ops,
- .of_match_table = msm8996_asoc_machine_of_match,
- },
- .probe = msm8996_asoc_machine_probe,
- .remove = msm8996_asoc_machine_remove,
-};
-module_platform_driver(msm8996_asoc_machine_driver);
-
-MODULE_DESCRIPTION("ALSA SoC msm");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:" DRV_NAME);
-MODULE_DEVICE_TABLE(of, msm8996_asoc_machine_of_match);
diff --git a/sound/soc/msm/msm8998.c b/sound/soc/msm/msm8998.c
index 174db28..05b7d30 100644
--- a/sound/soc/msm/msm8998.c
+++ b/sound/soc/msm/msm8998.c
@@ -5036,12 +5036,13 @@
.id = MSM_FRONTEND_DAI_MULTIMEDIA7,
},
{
- .name = MSM_DAILINK_NAME(Compress3),
- .stream_name = "Compress3",
+ .name = MSM_DAILINK_NAME(MultiMedia10),
+ .stream_name = "MultiMedia10",
.cpu_dai_name = "MultiMedia10",
- .platform_name = "msm-compress-dsp",
+ .platform_name = "msm-pcm-dsp.1",
.dynamic = 1,
.dpcm_playback = 1,
+ .dpcm_capture = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
.codec_dai_name = "snd-soc-dummy-dai",
diff --git a/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.c
index 9f08222..9b845ee 100644
--- a/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.c
@@ -154,7 +154,7 @@
MAX_INBAND_PARAM_SZ,
"VIRT ENABLE", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_VIRTUALIZER;
*updt_params++ =
@@ -182,7 +182,7 @@
MAX_INBAND_PARAM_SZ,
"VIRT STRENGTH", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_VIRTUALIZER;
*updt_params++ =
@@ -210,7 +210,7 @@
MAX_INBAND_PARAM_SZ,
"VIRT OUT_TYPE", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_VIRTUALIZER;
*updt_params++ =
@@ -238,7 +238,7 @@
MAX_INBAND_PARAM_SZ,
"VIRT GAIN_ADJUST", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_VIRTUALIZER;
*updt_params++ =
@@ -316,7 +316,7 @@
MAX_INBAND_PARAM_SZ,
"REVERB_ENABLE", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_REVERB;
*updt_params++ =
@@ -344,7 +344,7 @@
MAX_INBAND_PARAM_SZ,
"REVERB_MODE", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_REVERB;
*updt_params++ =
@@ -372,7 +372,7 @@
MAX_INBAND_PARAM_SZ,
"REVERB_PRESET", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_REVERB;
*updt_params++ =
@@ -400,7 +400,7 @@
MAX_INBAND_PARAM_SZ,
"REVERB_WET_MIX", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_REVERB;
*updt_params++ =
@@ -428,7 +428,7 @@
MAX_INBAND_PARAM_SZ,
"REVERB_GAIN_ADJUST", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_REVERB;
*updt_params++ =
@@ -456,7 +456,7 @@
MAX_INBAND_PARAM_SZ,
"REVERB_ROOM_LEVEL", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_REVERB;
*updt_params++ =
@@ -484,7 +484,7 @@
MAX_INBAND_PARAM_SZ,
"REVERB_ROOM_HF_LEVEL", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_REVERB;
*updt_params++ =
@@ -512,7 +512,7 @@
MAX_INBAND_PARAM_SZ,
"REVERB_DECAY_TIME", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_REVERB;
*updt_params++ =
@@ -540,7 +540,7 @@
MAX_INBAND_PARAM_SZ,
"REVERB_DECAY_HF_RATIO", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_REVERB;
*updt_params++ =
@@ -568,7 +568,7 @@
MAX_INBAND_PARAM_SZ,
"REVERB_REFLECTIONS_LEVEL", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_REVERB;
*updt_params++ =
@@ -596,7 +596,7 @@
MAX_INBAND_PARAM_SZ,
"REVERB_REFLECTIONS_DELAY", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_REVERB;
*updt_params++ =
@@ -624,7 +624,7 @@
MAX_INBAND_PARAM_SZ,
"REVERB_LEVEL", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_REVERB;
*updt_params++ =
@@ -652,7 +652,7 @@
MAX_INBAND_PARAM_SZ,
"REVERB_DELAY", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_REVERB;
*updt_params++ =
@@ -680,7 +680,7 @@
MAX_INBAND_PARAM_SZ,
"REVERB_DIFFUSION", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_REVERB;
*updt_params++ =
@@ -708,7 +708,7 @@
MAX_INBAND_PARAM_SZ,
"REVERB_DENSITY", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_REVERB;
*updt_params++ =
@@ -787,7 +787,7 @@
MAX_INBAND_PARAM_SZ,
"BASS_BOOST_ENABLE", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_BASS_BOOST;
*updt_params++ =
@@ -815,7 +815,7 @@
MAX_INBAND_PARAM_SZ,
"BASS_BOOST_MODE", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_BASS_BOOST;
*updt_params++ =
@@ -843,7 +843,7 @@
MAX_INBAND_PARAM_SZ,
"BASS_BOOST_STRENGTH", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_BASS_BOOST;
*updt_params++ =
@@ -920,7 +920,7 @@
MAX_INBAND_PARAM_SZ,
"PBE_ENABLE", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_PBE;
*updt_params++ =
@@ -946,7 +946,7 @@
MAX_INBAND_PARAM_SZ,
"PBE_PARAM", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_PBE;
*updt_params++ =
@@ -1031,7 +1031,7 @@
MAX_INBAND_PARAM_SZ,
"EQ_ENABLE", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_POPLESS_EQUALIZER;
*updt_params++ =
@@ -1099,7 +1099,7 @@
MAX_INBAND_PARAM_SZ,
"EQ_CONFIG", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_POPLESS_EQUALIZER;
*updt_params++ =
@@ -1150,7 +1150,7 @@
MAX_INBAND_PARAM_SZ,
"EQ_BAND_INDEX", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_POPLESS_EQUALIZER;
*updt_params++ =
@@ -1182,7 +1182,7 @@
MAX_INBAND_PARAM_SZ,
"EQ_SINGLE_BAND_FREQ", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_POPLESS_EQUALIZER;
*updt_params++ =
@@ -1271,7 +1271,7 @@
"VOLUME/VOLUME2_GAIN_2CH",
rc);
if (rc != 0)
- break;
+ goto invalid_config;
if (instance == SOFT_VOLUME_INSTANCE_2)
*updt_params++ =
ASM_MODULE_ID_VOL_CTRL2;
@@ -1320,7 +1320,7 @@
"VOLUME/VOLUME2_GAIN_MASTER",
rc);
if (rc != 0)
- break;
+ goto invalid_config;
if (instance == SOFT_VOLUME_INSTANCE_2)
*updt_params++ =
ASM_MODULE_ID_VOL_CTRL2;
diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
index c885265..503af58 100644
--- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
@@ -1282,6 +1282,9 @@
.step = SOFT_VOLUME_STEP,
.rampingcurve = SOFT_VOLUME_CURVE_LINEAR,
};
+ struct snd_kcontrol *kctl;
+ struct snd_ctl_elem_value kctl_elem_value;
+ uint16_t target_asm_bit_width = 0;
pr_debug("%s: stream_id %d\n", __func__, ac->stream_id);
stream_index = STREAM_ARRAY_INDEX(ac->stream_id);
@@ -1290,6 +1293,23 @@
return -EINVAL;
}
+ kctl = snd_soc_card_get_kcontrol(soc_prtd->card,
+ DSP_BIT_WIDTH_MIXER_CTL);
+ if (kctl) {
+ kctl->get(kctl, &kctl_elem_value);
+ target_asm_bit_width = kctl_elem_value.value.integer.value[0];
+ if (target_asm_bit_width > 0) {
+ pr_debug("%s enforce ASM bitwidth to %d from %d\n",
+ __func__,
+ target_asm_bit_width,
+ bits_per_sample);
+ bits_per_sample = target_asm_bit_width;
+ }
+ } else {
+ pr_info("%s: failed to get mixer ctl for %s.\n",
+ __func__, DSP_BIT_WIDTH_MIXER_CTL);
+ }
+
if ((prtd->codec_param.codec.format == SNDRV_PCM_FORMAT_S24_LE) ||
(prtd->codec_param.codec.format == SNDRV_PCM_FORMAT_S24_3LE))
bits_per_sample = 24;
diff --git a/sound/soc/msm/qdsp6v2/msm-lsm-client.c b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
index 3a6cbe6..ef3475c 100644
--- a/sound/soc/msm/qdsp6v2/msm-lsm-client.c
+++ b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
@@ -1682,7 +1682,7 @@
dev_err(rtd->dev,
"%s REG_SND_MODEL failed err %d\n",
__func__, err);
- return err;
+ goto done;
}
break;
case SNDRV_LSM_SET_PARAMS: {
@@ -1852,13 +1852,15 @@
dev_err(rtd->dev,
"%s: Invalid params event_status_v3\n",
__func__);
- return -EINVAL;
+ err = -EINVAL;
+ goto done;
}
if (copy_from_user(&userarg, arg, sizeof(userarg))) {
dev_err(rtd->dev,
"%s: err copyuser event_status_v3\n",
__func__);
- return -EFAULT;
+ err = -EFAULT;
+ goto done;
}
if (userarg.payload_size >
@@ -1866,7 +1868,8 @@
pr_err("%s: payload_size %d is invalid, max allowed = %d\n",
__func__, userarg.payload_size,
LISTEN_MAX_STATUS_PAYLOAD_SIZE);
- return -EINVAL;
+ err = -EINVAL;
+ goto done;
}
size = sizeof(struct snd_lsm_event_status_v3) +
@@ -1876,7 +1879,8 @@
dev_err(rtd->dev,
"%s: Allocation failed event status size %d\n",
__func__, size);
- return -EFAULT;
+ err = -EFAULT;
+ goto done;
}
user->payload_size = userarg.payload_size;
err = msm_lsm_ioctl_shared(substream, cmd, user);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index ef50d92..16f82ce 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -1093,7 +1093,7 @@
port_type = MSM_AFE_PORT_TYPE_RX;
} else if (stream_type == SNDRV_PCM_STREAM_CAPTURE) {
session_type = SESSION_TYPE_TX;
- if (passthr_mode != LEGACY_PCM)
+ if ((passthr_mode != LEGACY_PCM) && (passthr_mode != LISTEN))
path_type = ADM_PATH_COMPRESSED_TX;
else
path_type = ADM_PATH_LIVE_REC;
@@ -3645,6 +3645,11 @@
msm_route_ec_ref_rx_enum[0],
msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put);
+static const struct snd_kcontrol_new ext_ec_ref_mux_ul10 =
+ SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL10 MUX Mux",
+ msm_route_ec_ref_rx_enum[0],
+ msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put);
+
static const struct snd_kcontrol_new ext_ec_ref_mux_ul17 =
SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL17 MUX Mux",
msm_route_ec_ref_rx_enum[0],
@@ -7251,6 +7256,59 @@
msm_routing_put_audio_mixer),
};
+static const struct snd_kcontrol_new mmul10_mixer_controls[] = {
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("VOC_REC_DL", MSM_BACKEND_DAI_INCALL_RECORD_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("VOC_REC_UL", MSM_BACKEND_DAI_INCALL_RECORD_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SLIM_6_TX", MSM_BACKEND_DAI_SLIMBUS_6_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("USB_AUDIO_TX", MSM_BACKEND_DAI_USB_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
static const struct snd_kcontrol_new mmul17_mixer_controls[] = {
SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
@@ -11489,6 +11547,7 @@
SND_SOC_DAPM_AIF_OUT("MM_UL6", "MultiMedia6 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL8", "MultiMedia8 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL9", "MultiMedia9 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("MM_UL10", "MultiMedia10 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL16", "MultiMedia16 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL17", "MultiMedia17 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL18", "MultiMedia18 Capture", 0, 0, 0, 0),
@@ -12225,6 +12284,8 @@
mmul8_mixer_controls, ARRAY_SIZE(mmul8_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia9 Mixer", SND_SOC_NOPM, 0, 0,
mmul9_mixer_controls, ARRAY_SIZE(mmul9_mixer_controls)),
+ SND_SOC_DAPM_MIXER("MultiMedia10 Mixer", SND_SOC_NOPM, 0, 0,
+ mmul10_mixer_controls, ARRAY_SIZE(mmul10_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia16 Mixer", SND_SOC_NOPM, 0, 0,
mmul16_mixer_controls, ARRAY_SIZE(mmul16_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia17 Mixer", SND_SOC_NOPM, 0, 0,
@@ -12557,6 +12618,8 @@
&ext_ec_ref_mux_ul8),
SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL9 MUX", SND_SOC_NOPM, 0, 0,
&ext_ec_ref_mux_ul9),
+ SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL10 MUX", SND_SOC_NOPM, 0, 0,
+ &ext_ec_ref_mux_ul10),
SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL16 MUX", SND_SOC_NOPM, 0, 0,
&ext_ec_ref_mux_ul16),
SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL17 MUX", SND_SOC_NOPM, 0, 0,
@@ -12810,9 +12873,11 @@
{"MultiMedia8 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
{"MultiMedia3 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia5 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+ {"MultiMedia10 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia16 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia5 Mixer", "SLIM_7_TX", "SLIMBUS_7_TX"},
{"MultiMedia5 Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"},
+ {"MultiMedia10 Mixer", "SLIM_7_TX", "SLIMBUS_7_TX"},
{"MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
@@ -13379,6 +13444,7 @@
{"MultiMedia2 Mixer", "MI2S_TX", "MI2S_TX"},
{"MultiMedia3 Mixer", "MI2S_TX", "MI2S_TX"},
{"MultiMedia5 Mixer", "MI2S_TX", "MI2S_TX"},
+ {"MultiMedia10 Mixer", "MI2S_TX", "MI2S_TX"},
{"MultiMedia16 Mixer", "MI2S_TX", "MI2S_TX"},
{"MultiMedia1 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
{"MultiMedia2 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
@@ -13395,17 +13461,21 @@
{"MultiMedia1 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
{"MultiMedia3 Mixer", "AUX_PCM_TX", "AUX_PCM_TX"},
{"MultiMedia5 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+ {"MultiMedia10 Mixer", "AUX_PCM_TX", "AUX_PCM_TX"},
{"MultiMedia1 Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
{"MultiMedia3 Mixer", "SEC_AUX_PCM_TX", "SEC_AUX_PCM_TX"},
{"MultiMedia5 Mixer", "SEC_AUX_PCM_TX", "SEC_AUX_PCM_TX"},
+ {"MultiMedia10 Mixer", "SEC_AUX_PCM_TX", "SEC_AUX_PCM_TX"},
{"MultiMedia16 Mixer", "AUX_PCM_TX", "AUX_PCM_TX"},
{"MultiMedia16 Mixer", "SEC_AUX_PCM_TX", "SEC_AUX_PCM_TX"},
{"MultiMedia1 Mixer", "TERT_AUXPCM_UL_TX", "TERT_AUX_PCM_TX"},
{"MultiMedia3 Mixer", "TERT_AUX_PCM_TX", "TERT_AUX_PCM_TX"},
{"MultiMedia5 Mixer", "TERT_AUX_PCM_TX", "TERT_AUX_PCM_TX"},
+ {"MultiMedia10 Mixer", "TERT_AUX_PCM_TX", "TERT_AUX_PCM_TX"},
{"MultiMedia1 Mixer", "QUAT_AUXPCM_UL_TX", "QUAT_AUX_PCM_TX"},
{"MultiMedia3 Mixer", "QUAT_AUX_PCM_TX", "QUAT_AUX_PCM_TX"},
{"MultiMedia5 Mixer", "QUAT_AUX_PCM_TX", "QUAT_AUX_PCM_TX"},
+ {"MultiMedia10 Mixer", "QUAT_AUX_PCM_TX", "QUAT_AUX_PCM_TX"},
{"MultiMedia16 Mixer", "QUAT_AUX_PCM_TX", "QUAT_AUX_PCM_TX"},
{"MultiMedia2 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia2 Mixer", "SLIM_6_TX", "SLIMBUS_6_TX"},
@@ -13418,13 +13488,16 @@
{"MultiMedia6 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
{"MultiMedia3 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
{"MultiMedia5 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"MultiMedia10 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
{"MultiMedia6 Mixer", "INT2_MI2S_TX", "INT2_MI2S_TX"},
{"MultiMedia3 Mixer", "INT2_MI2S_TX", "INT2_MI2S_TX"},
{"MultiMedia5 Mixer", "INT2_MI2S_TX", "INT2_MI2S_TX"},
+ {"MultiMedia10 Mixer", "INT2_MI2S_TX", "INT2_MI2S_TX"},
{"MultiMedia16 Mixer", "INT2_MI2S_TX", "INT2_MI2S_TX"},
{"MultiMedia6 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
{"MultiMedia3 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
{"MultiMedia5 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
+ {"MultiMedia10 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
{"MultiMedia16 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
{"MultiMedia6 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
{"MultiMedia6 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
@@ -13559,6 +13632,14 @@
{"MultiMedia9 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
{"MultiMedia9 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+ {"MultiMedia10 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
+ {"MultiMedia10 Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"},
+ {"MultiMedia10 Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"},
+ {"MultiMedia10 Mixer", "TERT_TDM_TX_3", "TERT_TDM_TX_3"},
+ {"MultiMedia10 Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+ {"MultiMedia10 Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+ {"MultiMedia10 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+ {"MultiMedia10 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
{"MultiMedia20 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
{"MultiMedia20 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
{"MultiMedia20 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
@@ -13586,6 +13667,7 @@
{"MultiMedia5 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"},
{"MultiMedia6 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"},
{"MultiMedia8 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"},
+ {"MultiMedia10 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"},
{"MultiMedia16 Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"},
{"MultiMedia16 Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"},
@@ -13682,6 +13764,7 @@
{"MultiMedia1 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"MultiMedia3 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"MultiMedia4 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"MultiMedia10 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"MultiMedia17 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"MultiMedia18 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"MultiMedia19 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
@@ -13701,6 +13784,7 @@
{"MultiMedia1 Mixer", "AFE_PCM_TX", "PCM_TX"},
{"MultiMedia3 Mixer", "AFE_PCM_TX", "PCM_TX"},
{"MultiMedia4 Mixer", "AFE_PCM_TX", "PCM_TX"},
+ {"MultiMedia10 Mixer", "AFE_PCM_TX", "PCM_TX"},
{"MultiMedia17 Mixer", "AFE_PCM_TX", "PCM_TX"},
{"MultiMedia18 Mixer", "AFE_PCM_TX", "PCM_TX"},
{"MultiMedia19 Mixer", "AFE_PCM_TX", "PCM_TX"},
@@ -13716,6 +13800,7 @@
{"MM_UL6", NULL, "MultiMedia6 Mixer"},
{"MM_UL8", NULL, "MultiMedia8 Mixer"},
{"MM_UL9", NULL, "MultiMedia9 Mixer"},
+ {"MM_UL10", NULL, "MultiMedia10 Mixer"},
{"MM_UL16", NULL, "MultiMedia16 Mixer"},
{"MM_UL17", NULL, "MultiMedia17 Mixer"},
{"MM_UL18", NULL, "MultiMedia18 Mixer"},
@@ -14104,6 +14189,16 @@
{"AUDIO_REF_EC_UL9 MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"},
{"AUDIO_REF_EC_UL9 MUX", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"AUDIO_REF_EC_UL10 MUX", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"AUDIO_REF_EC_UL10 MUX", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"AUDIO_REF_EC_UL10 MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"AUDIO_REF_EC_UL10 MUX", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"AUDIO_REF_EC_UL10 MUX", "SLIM_1_TX", "SLIMBUS_1_TX"},
+ {"AUDIO_REF_EC_UL10 MUX", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+ {"AUDIO_REF_EC_UL10 MUX", "QUAT_TDM_RX_0", "QUAT_TDM_RX_0"},
+ {"AUDIO_REF_EC_UL10 MUX", "QUAT_TDM_RX_1", "QUAT_TDM_RX_1"},
+ {"AUDIO_REF_EC_UL10 MUX", "QUAT_TDM_RX_2", "QUAT_TDM_RX_2"},
+ {"AUDIO_REF_EC_UL10 MUX", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
{"AUDIO_REF_EC_UL17 MUX", "PRI_MI2S_TX", "PRI_MI2S_TX"},
{"AUDIO_REF_EC_UL17 MUX", "SEC_MI2S_TX", "SEC_MI2S_TX"},
{"AUDIO_REF_EC_UL17 MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"},
@@ -14127,6 +14222,7 @@
{"MM_UL6", NULL, "AUDIO_REF_EC_UL6 MUX"},
{"MM_UL8", NULL, "AUDIO_REF_EC_UL8 MUX"},
{"MM_UL9", NULL, "AUDIO_REF_EC_UL9 MUX"},
+ {"MM_UL10", NULL, "AUDIO_REF_EC_UL10 MUX"},
{"MM_UL16", NULL, "AUDIO_REF_EC_UL16 MUX"},
{"MM_UL17", NULL, "AUDIO_REF_EC_UL17 MUX"},
{"MM_UL18", NULL, "AUDIO_REF_EC_UL18 MUX"},
diff --git a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c
index a885e1e..53826fe 100644
--- a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c
+++ b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c
@@ -392,6 +392,7 @@
static int msm_afe_quat_mi2s_lb_vol_ctrl;
static int msm_afe_slimbus_7_lb_vol_ctrl;
static int msm_afe_slimbus_8_lb_vol_ctrl;
+static int msm_asm_bit_width;
static const DECLARE_TLV_DB_LINEAR(fm_rx_vol_gain, 0, INT_RX_VOL_MAX_STEPS);
static const DECLARE_TLV_DB_LINEAR(afe_lb_vol_gain, 0, INT_RX_VOL_MAX_STEPS);
@@ -412,6 +413,38 @@
return 0;
}
+static int msm_asm_bit_width_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s get ASM bitwidth = %d\n",
+ __func__, msm_asm_bit_width);
+
+ ucontrol->value.integer.value[0] = msm_asm_bit_width;
+
+ return 0;
+}
+
+static int msm_asm_bit_width_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 16:
+ msm_asm_bit_width = 16;
+ break;
+ case 24:
+ msm_asm_bit_width = 24;
+ break;
+ case 32:
+ msm_asm_bit_width = 32;
+ break;
+ default:
+ msm_asm_bit_width = 0;
+ break;
+ }
+
+ return 0;
+}
+
static int msm_qti_pp_get_pri_mi2s_lb_vol_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -1132,6 +1165,11 @@
msm_qti_pp_set_quat_mi2s_fm_vol_mixer, fm_rx_vol_gain),
};
+static const struct snd_kcontrol_new dsp_bit_width_controls[] = {
+ SOC_SINGLE_EXT(DSP_BIT_WIDTH_MIXER_CTL, SND_SOC_NOPM, 0, 0x20,
+ 0, msm_asm_bit_width_get, msm_asm_bit_width_put),
+};
+
static const struct snd_kcontrol_new pri_mi2s_lb_vol_mixer_controls[] = {
SOC_SINGLE_EXT_TLV("PRI MI2S LOOPBACK Volume", SND_SOC_NOPM, 0,
INT_RX_VOL_GAIN, 0, msm_qti_pp_get_pri_mi2s_lb_vol_mixer,
@@ -1403,5 +1441,8 @@
snd_soc_add_platform_controls(platform, msm_multichannel_ec_controls,
ARRAY_SIZE(msm_multichannel_ec_controls));
+
+ snd_soc_add_platform_controls(platform, dsp_bit_width_controls,
+ ARRAY_SIZE(dsp_bit_width_controls));
}
#endif /* CONFIG_QTI_PP */
diff --git a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h
index b67e873..ec69d37 100644
--- a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h
+++ b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h
@@ -13,6 +13,7 @@
#define _MSM_QTI_PP_H_
#include <sound/soc.h>
+#define DSP_BIT_WIDTH_MIXER_CTL "ASM Bit Width"
int msm_adsp_inform_mixer_ctl(struct snd_soc_pcm_runtime *rtd,
uint32_t *payload);
int msm_adsp_init_mixer_ctl_pp_event_queue(struct snd_soc_pcm_runtime *rtd);
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index 1590605..fc0917f 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -2388,7 +2388,8 @@
struct adm_cmd_device_open_v5 open;
struct adm_cmd_device_open_v6 open_v6;
int ret = 0;
- int port_idx, copp_idx, flags;
+ int port_idx, flags;
+ int copp_idx = -1;
int tmp_port = q6audio_get_port_id(port_id);
pr_debug("%s:port %#x path:%d rate:%d mode:%d perf_mode:%d,topo_id %d\n",
@@ -2437,13 +2438,22 @@
flags = ADM_LEGACY_DEVICE_SESSION;
}
- if ((topology == VPM_TX_SM_ECNS_COPP_TOPOLOGY) ||
+ if ((topology == VPM_TX_SM_ECNS_V2_COPP_TOPOLOGY) ||
(topology == VPM_TX_DM_FLUENCE_COPP_TOPOLOGY) ||
(topology == VPM_TX_DM_RFECNS_COPP_TOPOLOGY))
rate = 16000;
- copp_idx = adm_get_idx_if_copp_exists(port_idx, topology, perf_mode,
- rate, bit_width, app_type);
+ /*
+ * Routing driver reuses the same adm for streams with the same
+ * app_type, sample_rate etc.
+ * This isn't allowed for ULL streams as per the DSP interface
+ */
+ if (perf_mode != ULTRA_LOW_LATENCY_PCM_MODE)
+ copp_idx = adm_get_idx_if_copp_exists(port_idx, topology,
+ perf_mode,
+ rate, bit_width,
+ app_type);
+
if (copp_idx < 0) {
copp_idx = adm_get_next_available_copp(port_idx);
if (copp_idx >= MAX_COPPS_PER_PORT) {
diff --git a/sound/soc/msm/qdsp6v2/q6core.c b/sound/soc/msm/qdsp6v2/q6core.c
index 3aaaa35..4c3a3a1 100644
--- a/sound/soc/msm/qdsp6v2/q6core.c
+++ b/sound/soc/msm/qdsp6v2/q6core.c
@@ -21,6 +21,8 @@
#include <linux/qdsp6v2/apr.h>
#include <sound/q6core.h>
#include <sound/audio_cal_utils.h>
+#include <sound/adsp_err.h>
+#include <sound/apr_audio-v2.h>
#define TIMEOUT_MS 1000
/*
@@ -36,16 +38,30 @@
CORE_MAX_CAL
};
+enum ver_query_status {
+ VER_QUERY_UNATTEMPTED,
+ VER_QUERY_UNSUPPORTED,
+ VER_QUERY_SUPPORTED
+};
+
+struct q6core_avcs_ver_info {
+ enum ver_query_status status;
+ struct avcs_fwk_ver_info ver_info;
+};
+
struct q6core_str {
struct apr_svc *core_handle_q;
wait_queue_head_t bus_bw_req_wait;
wait_queue_head_t cmd_req_wait;
+ wait_queue_head_t avcs_fwk_ver_req_wait;
u32 bus_bw_resp_received;
enum cmd_flags {
FLAG_NONE,
FLAG_CMDRSP_LICENSE_RESULT
} cmd_resp_received_flag;
+ u32 avcs_fwk_ver_resp_received;
struct mutex cmd_lock;
+ struct mutex ver_lock;
union {
struct avcs_cmdrsp_get_license_validation_result
cmdrsp_license_result;
@@ -54,6 +70,7 @@
struct cal_type_data *cal_data[CORE_MAX_CAL];
uint32_t mem_map_cal_handle;
int32_t adsp_status;
+ struct q6core_avcs_ver_info q6core_avcs_ver_info;
};
static struct q6core_str q6core_lcl;
@@ -65,9 +82,61 @@
};
static struct generic_get_data_ *generic_get_data;
+static int parse_fwk_version_info(uint32_t *payload)
+{
+ size_t fwk_ver_size;
+ size_t svc_size;
+ int num_services;
+ int ret = 0;
+
+ pr_debug("%s: Payload info num services %d\n",
+ __func__, payload[4]);
+ /*
+ * payload1[4] is the number of services running on DSP
+ * Based on this info, we copy the payload into core
+ * avcs version info structure.
+ */
+ num_services = payload[4];
+ q6core_lcl.q6core_avcs_ver_info.ver_info.avcs_fwk_version.
+ num_services = num_services;
+ if (num_services > VSS_MAX_AVCS_NUM_SERVICES) {
+ pr_err("%s: num_services: %d greater than max services: %d\n",
+ __func__, num_services, VSS_MAX_AVCS_NUM_SERVICES);
+ ret = -EINVAL;
+ goto done;
+ }
+ fwk_ver_size = sizeof(struct avcs_get_fwk_version);
+ svc_size = num_services * sizeof(struct avs_svc_api_info);
+ /*
+ * Dynamically allocate memory for all
+ * the services based on num_services
+ */
+ q6core_lcl.q6core_avcs_ver_info.ver_info.services = NULL;
+ q6core_lcl.q6core_avcs_ver_info.ver_info.services =
+ kzalloc(svc_size, GFP_ATOMIC);
+ if (q6core_lcl.q6core_avcs_ver_info.ver_info.services == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ /*
+ * memcpy is done twice because the memory allocated for
+ * q6core_lcl.q6core_avcs_ver_info.ver_info is not
+ * contiguous.
+ */
+ memcpy(&q6core_lcl.q6core_avcs_ver_info.ver_info,
+ (uint8_t *)payload, fwk_ver_size);
+ memcpy(q6core_lcl.q6core_avcs_ver_info.ver_info.services,
+ (uint8_t *)&payload[sizeof(struct avcs_get_fwk_version)/
+ sizeof(uint32_t)], svc_size);
+ ret = 0;
+done:
+ return ret;
+}
+
static int32_t aprv2_core_fn_q(struct apr_client_data *data, void *priv)
{
uint32_t *payload1;
+ int ret = 0;
if (data == NULL) {
pr_err("%s: data argument is null\n", __func__);
@@ -118,6 +187,17 @@
q6core_lcl.bus_bw_resp_received = 1;
wake_up(&q6core_lcl.bus_bw_req_wait);
break;
+ case AVCS_CMD_GET_FWK_VERSION:
+ pr_debug("%s: Cmd = AVCS_CMD_GET_FWK_VERSION status[%s]\n",
+ __func__, adsp_err_get_err_str(payload1[1]));
+ /* ADSP status to match Linux error standard */
+ q6core_lcl.adsp_status = -payload1[1];
+ if (payload1[1] == ADSP_EUNSUPPORTED)
+ q6core_lcl.q6core_avcs_ver_info.status =
+ VER_QUERY_UNSUPPORTED;
+ q6core_lcl.avcs_fwk_ver_resp_received = 1;
+ wake_up(&q6core_lcl.avcs_fwk_ver_req_wait);
+ break;
default:
pr_err("%s: Invalid cmd rsp[0x%x][0x%x] opcode %d\n",
__func__,
@@ -130,7 +210,7 @@
case RESET_EVENTS:{
pr_debug("%s: Reset event received in Core service\n",
__func__);
- apr_reset(q6core_lcl.core_handle_q);
+ /* no reset done as the data will not change after SSR*/
q6core_lcl.core_handle_q = NULL;
break;
}
@@ -161,6 +241,18 @@
q6core_lcl.cmd_resp_received_flag = FLAG_CMDRSP_LICENSE_RESULT;
wake_up(&q6core_lcl.cmd_req_wait);
break;
+ case AVCS_CMDRSP_GET_FWK_VERSION:
+ pr_debug("%s: Received AVCS_CMDRSP_GET_FWK_VERSION\n",
+ __func__);
+ payload1 = data->payload;
+ q6core_lcl.q6core_avcs_ver_info.status = VER_QUERY_SUPPORTED;
+ q6core_lcl.avcs_fwk_ver_resp_received = 1;
+ ret = parse_fwk_version_info(payload1);
+ if (ret < 0)
+ pr_err("%s: Failed to parse payload:%d\n",
+ __func__, ret);
+ wake_up(&q6core_lcl.avcs_fwk_ver_req_wait);
+ break;
default:
pr_err("%s: Message id from adsp core svc: 0x%x\n",
__func__, data->opcode);
@@ -217,6 +309,157 @@
return NULL;
}
+static int q6core_send_get_avcs_fwk_ver_cmd(void)
+{
+ struct apr_hdr avcs_ver_cmd;
+ int ret;
+
+ avcs_ver_cmd.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ avcs_ver_cmd.pkt_size = sizeof(struct apr_hdr);
+ avcs_ver_cmd.src_port = 0;
+ avcs_ver_cmd.dest_port = 0;
+ avcs_ver_cmd.token = 0;
+ avcs_ver_cmd.opcode = AVCS_CMD_GET_FWK_VERSION;
+
+ q6core_lcl.adsp_status = 0;
+ q6core_lcl.avcs_fwk_ver_resp_received = 0;
+
+ ret = apr_send_pkt(q6core_lcl.core_handle_q,
+ (uint32_t *) &avcs_ver_cmd);
+ if (ret < 0) {
+ pr_err("%s: failed to send apr packet, ret=%d\n", __func__,
+ ret);
+ goto done;
+ }
+
+ ret = wait_event_timeout(q6core_lcl.avcs_fwk_ver_req_wait,
+ (q6core_lcl.avcs_fwk_ver_resp_received == 1),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout for AVCS fwk version info\n",
+ __func__);
+ ret = -ETIMEDOUT;
+ goto done;
+ }
+
+ if (q6core_lcl.adsp_status < 0) {
+ /*
+ * adsp_err_get_err_str expects a positive value but we store
+ * the DSP error as negative to match the Linux error standard.
+ * Pass in the negated value so adsp_err_get_err_str returns
+ * the correct string.
+ */
+ pr_err("%s: DSP returned error[%s]\n", __func__,
+ adsp_err_get_err_str(-q6core_lcl.adsp_status));
+ ret = adsp_err_get_lnx_err_code(q6core_lcl.adsp_status);
+ goto done;
+ }
+
+ ret = 0;
+
+done:
+ return ret;
+}
+
+int q6core_get_service_version(uint32_t service_id,
+ struct avcs_fwk_ver_info *ver_info,
+ size_t size)
+{
+ int i;
+ uint32_t num_services;
+ size_t svc_size;
+
+ svc_size = q6core_get_avcs_service_size(service_id);
+ if (svc_size != size) {
+ pr_err("%s: Expected size: %ld, Provided size: %ld",
+ __func__, svc_size, size);
+ return -EINVAL;
+ }
+
+ num_services =
+ q6core_lcl.q6core_avcs_ver_info.ver_info.
+ avcs_fwk_version.num_services;
+
+ if (ver_info == NULL) {
+ pr_err("%s: NULL parameter ver_info\n", __func__);
+ return -EINVAL;
+ }
+
+ memcpy(ver_info, &q6core_lcl.q6core_avcs_ver_info.
+ ver_info.avcs_fwk_version, sizeof(struct avcs_get_fwk_version));
+
+ if (service_id == AVCS_SERVICE_ID_ALL) {
+ memcpy(&ver_info->services[0], &q6core_lcl.
+ q6core_avcs_ver_info.ver_info.services[0],
+ (num_services * sizeof(struct avs_svc_api_info)));
+ } else {
+ for (i = 0; i < num_services; i++) {
+ if (q6core_lcl.q6core_avcs_ver_info.
+ ver_info.services[i].service_id == service_id) {
+ memcpy(&ver_info->services[0],
+ &q6core_lcl.q6core_avcs_ver_info.
+ ver_info.services[i], size);
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(q6core_get_service_version);
+
+size_t q6core_get_avcs_service_size(uint32_t service_id)
+{
+ int ret = 0;
+ uint32_t num_services;
+
+ num_services =
+ q6core_lcl.q6core_avcs_ver_info.ver_info.
+ avcs_fwk_version.num_services;
+
+ mutex_lock(&(q6core_lcl.ver_lock));
+ pr_debug("%s: q6core_avcs_ver_info.status(%d)\n", __func__,
+ q6core_lcl.q6core_avcs_ver_info.status);
+
+ switch (q6core_lcl.q6core_avcs_ver_info.status) {
+ case VER_QUERY_SUPPORTED:
+ pr_debug("%s: AVCS FWK version query already attempted\n",
+ __func__);
+ ret = num_services * sizeof(struct avs_svc_api_info);
+ break;
+ case VER_QUERY_UNSUPPORTED:
+ ret = -EOPNOTSUPP;
+ break;
+ case VER_QUERY_UNATTEMPTED:
+ pr_debug("%s: Attempting AVCS FWK version query\n", __func__);
+ if (q6core_is_adsp_ready()) {
+ ret = q6core_send_get_avcs_fwk_ver_cmd();
+ if (ret == 0)
+ ret = num_services *
+ sizeof(struct avs_svc_api_info);
+ } else {
+ pr_err("%s: ADSP is not ready to query version\n",
+ __func__);
+ ret = -ENODEV;
+ }
+ break;
+ default:
+ pr_err("%s: Invalid version query status %d\n", __func__,
+ q6core_lcl.q6core_avcs_ver_info.status);
+ ret = -EINVAL;
+ break;
+ }
+ mutex_unlock(&(q6core_lcl.ver_lock));
+
+ if (service_id != AVCS_SERVICE_ID_ALL)
+ return sizeof(struct avs_svc_api_info);
+
+ return ret;
+}
+EXPORT_SYMBOL(q6core_get_avcs_service_size);
+
int32_t core_set_license(uint32_t key, uint32_t module_id)
{
struct avcs_cmd_set_license *cmd_setl = NULL;
@@ -827,18 +1070,16 @@
static int __init core_init(void)
{
+ memset(&q6core_lcl, 0, sizeof(struct q6core_str));
init_waitqueue_head(&q6core_lcl.bus_bw_req_wait);
- q6core_lcl.bus_bw_resp_received = 0;
-
- q6core_lcl.core_handle_q = NULL;
-
init_waitqueue_head(&q6core_lcl.cmd_req_wait);
+ init_waitqueue_head(&q6core_lcl.avcs_fwk_ver_req_wait);
q6core_lcl.cmd_resp_received_flag = FLAG_NONE;
mutex_init(&q6core_lcl.cmd_lock);
- q6core_lcl.mem_map_cal_handle = 0;
- q6core_lcl.adsp_status = 0;
+ mutex_init(&q6core_lcl.ver_lock);
q6core_init_cal_data();
+
return 0;
}
module_init(core_init);
@@ -846,6 +1087,7 @@
static void __exit core_exit(void)
{
mutex_destroy(&q6core_lcl.cmd_lock);
+ mutex_destroy(&q6core_lcl.ver_lock);
q6core_delete_cal_data();
}
module_exit(core_exit);
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
index 15c9e13..a85e0fd 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -21,6 +21,7 @@
#include <soc/qcom/socinfo.h>
#include <linux/qdsp6v2/apr_tal.h>
+#include "sound/q6core.h"
#include "sound/q6audio-v2.h"
#include "sound/apr_audio-v2.h"
#include "sound/q6afe-v2.h"
@@ -33,6 +34,9 @@
#define CMD_STATUS_SUCCESS 0
#define CMD_STATUS_FAIL 1
+#define NUM_CHANNELS_MONO 1
+#define NUM_CHANNELS_STEREO 2
+#define CVP_VERSION_2 2
enum {
VOC_TOKEN_NONE,
@@ -83,6 +87,11 @@
static int voice_send_cvp_media_format_cmd(struct voice_data *v,
uint32_t param_type);
static int voice_send_cvp_topology_commit_cmd(struct voice_data *v);
+static int voice_send_cvp_channel_info_cmd(struct voice_data *v);
+static int voice_send_cvp_channel_info_v2(struct voice_data *v,
+ uint32_t param_type);
+static int voice_get_avcs_version_per_service(uint32_t service_id);
+
static int voice_cvs_stop_playback(struct voice_data *v);
static int voice_cvs_start_playback(struct voice_data *v);
@@ -3793,6 +3802,295 @@
return result;
}
+static int voice_send_cvp_channel_info_v2(struct voice_data *v,
+ uint32_t param_type)
+{
+ int ret;
+ struct cvp_set_channel_info_cmd_v2 cvp_set_channel_info_cmd;
+ void *apr_cvp;
+ u16 cvp_handle;
+ struct vss_icommon_param_data_channel_info_v2_t
+ *channel_info_param_data =
+ &cvp_set_channel_info_cmd.
+ cvp_set_ch_info_param_v2.param_data;
+ struct vss_param_vocproc_dev_channel_info_t *channel_info =
+ &channel_info_param_data->channel_info;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ apr_cvp = common.apr_q6_cvp;
+ if (!apr_cvp) {
+ pr_err("%s: apr_cvp is NULL\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ cvp_handle = voice_get_cvp_handle(v);
+ memset(&cvp_set_channel_info_cmd, 0, sizeof(cvp_set_channel_info_cmd));
+
+ cvp_set_channel_info_cmd.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvp_set_channel_info_cmd.hdr.pkt_size =
+ APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvp_set_channel_info_cmd) - APR_HDR_SIZE);
+ cvp_set_channel_info_cmd.hdr.src_svc = 0;
+ cvp_set_channel_info_cmd.hdr.src_domain = APR_DOMAIN_APPS;
+ cvp_set_channel_info_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ cvp_set_channel_info_cmd.hdr.dest_svc = 0;
+ cvp_set_channel_info_cmd.hdr.dest_domain = APR_DOMAIN_ADSP;
+ cvp_set_channel_info_cmd.hdr.dest_port = cvp_handle;
+ cvp_set_channel_info_cmd.hdr.token = 0;
+ cvp_set_channel_info_cmd.hdr.opcode = VSS_ICOMMON_CMD_SET_PARAM_V2;
+
+ cvp_set_channel_info_cmd.cvp_set_ch_info_param_v2.mem_size =
+ sizeof(struct vss_icommon_param_data_channel_info_v2_t);
+
+ channel_info_param_data->module_id = VSS_MODULE_CVD_GENERIC;
+ channel_info_param_data->param_size =
+ sizeof(struct vss_param_vocproc_dev_channel_info_t);
+
+ /* Device specific data */
+ switch (param_type) {
+ case RX_PATH:
+ channel_info_param_data->param_id =
+ VSS_PARAM_VOCPROC_RX_CHANNEL_INFO;
+ channel_info->num_channels = v->dev_rx.no_of_channels;
+ channel_info->bits_per_sample = v->dev_rx.bits_per_sample;
+ break;
+
+ case TX_PATH:
+ channel_info_param_data->param_id =
+ VSS_PARAM_VOCPROC_TX_CHANNEL_INFO;
+ channel_info->num_channels = v->dev_tx.no_of_channels;
+ channel_info->bits_per_sample = v->dev_tx.bits_per_sample;
+ break;
+
+ case EC_REF_PATH:
+ channel_info_param_data->param_id =
+ VSS_PARAM_VOCPROC_EC_REF_CHANNEL_INFO;
+ channel_info->num_channels = v->dev_rx.no_of_channels;
+ channel_info->bits_per_sample = v->dev_rx.bits_per_sample;
+ break;
+ default:
+ pr_err("%s: Invalid param type\n",
+ __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (channel_info->num_channels == NUM_CHANNELS_MONO) {
+ channel_info->channel_mapping[0] = PCM_CHANNEL_FC;
+ } else if (channel_info->num_channels == NUM_CHANNELS_STEREO) {
+ channel_info->channel_mapping[0] = PCM_CHANNEL_FL;
+ channel_info->channel_mapping[1] = PCM_CHANNEL_FR;
+ } else {
+ pr_err("%s: Unsupported num channels: %d\n",
+ __func__, channel_info->num_channels);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ v->cvp_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_set_channel_info_cmd);
+ if (ret < 0) {
+ pr_err("%s: Failed to send VSS_ICOMMON_CMD_SET_PARAM_V2\n",
+ __func__);
+ goto done;
+ }
+
+ ret = wait_event_timeout(v->cvp_wait,
+ (v->cvp_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ ret = -ETIMEDOUT;
+ goto done;
+ }
+
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s] handle = %d\n", __func__,
+ adsp_err_get_err_str(v->async_err), cvp_handle);
+ ret = adsp_err_get_lnx_err_code(v->async_err);
+ goto done;
+ }
+ ret = 0;
+done:
+ return ret;
+}
+
+static int voice_send_cvp_channel_info_cmd(struct voice_data *v)
+{
+ int ret = 0;
+
+ ret = voice_send_cvp_channel_info_v2(v, RX_PATH);
+ if (ret < 0) {
+ pr_err("%s: Error in sending cvp_channel_info RX: %d\n",
+ __func__, ret);
+ goto done;
+ }
+
+ ret = voice_send_cvp_channel_info_v2(v, TX_PATH);
+ if (ret < 0) {
+ pr_err("%s: Error in sending cvp_channel_info TX: %d\n",
+ __func__, ret);
+ goto done;
+ }
+
+ ret = voice_send_cvp_channel_info_v2(v, EC_REF_PATH);
+ if (ret < 0) {
+ pr_err("%s: Error in sending cvp_channel_info EC Ref: %d\n",
+ __func__, ret);
+ goto done;
+ }
+done:
+ return ret;
+}
+
+static int voice_send_cvp_mfc_config_v2(struct voice_data *v)
+{
+ int ret;
+ struct cvp_set_mfc_config_cmd_v2 cvp_set_mfc_config_cmd;
+ void *apr_cvp;
+ u16 cvp_handle;
+ struct vss_icommon_param_data_mfc_config_v2_t *cvp_config_param_data =
+ &cvp_set_mfc_config_cmd.cvp_set_mfc_param_v2.param_data;
+ struct vss_param_mfc_config_info_t *mfc_config_info =
+ &cvp_config_param_data->mfc_config_info;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ apr_cvp = common.apr_q6_cvp;
+ if (!apr_cvp) {
+ pr_err("%s: apr_cvp is NULL\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ cvp_handle = voice_get_cvp_handle(v);
+ memset(&cvp_set_mfc_config_cmd, 0, sizeof(cvp_set_mfc_config_cmd));
+
+ cvp_set_mfc_config_cmd.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvp_set_mfc_config_cmd.hdr.pkt_size =
+ APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvp_set_mfc_config_cmd) - APR_HDR_SIZE);
+ cvp_set_mfc_config_cmd.hdr.src_svc = 0;
+ cvp_set_mfc_config_cmd.hdr.src_domain = APR_DOMAIN_APPS;
+ cvp_set_mfc_config_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ cvp_set_mfc_config_cmd.hdr.dest_svc = 0;
+ cvp_set_mfc_config_cmd.hdr.dest_domain = APR_DOMAIN_ADSP;
+ cvp_set_mfc_config_cmd.hdr.dest_port = cvp_handle;
+ cvp_set_mfc_config_cmd.hdr.token = 0;
+ cvp_set_mfc_config_cmd.hdr.opcode = VSS_ICOMMON_CMD_SET_PARAM_V2;
+ cvp_set_mfc_config_cmd.cvp_set_mfc_param_v2.mem_size =
+ sizeof(struct vss_icommon_param_data_mfc_config_v2_t);
+
+ cvp_config_param_data->module_id = AUDPROC_MODULE_ID_MFC;
+ cvp_config_param_data->param_id =
+ AUDPROC_PARAM_ID_MFC_OUTPUT_MEDIA_FORMAT;
+ cvp_config_param_data->param_size =
+ sizeof(struct vss_param_mfc_config_info_t);
+
+ mfc_config_info->num_channels = v->dev_rx.no_of_channels;
+ mfc_config_info->bits_per_sample = 16;
+ mfc_config_info->sample_rate = v->dev_rx.sample_rate;
+
+ if (mfc_config_info->num_channels == NUM_CHANNELS_MONO) {
+ mfc_config_info->channel_type[0] = PCM_CHANNEL_FC;
+ } else if (mfc_config_info->num_channels == NUM_CHANNELS_STEREO) {
+ mfc_config_info->channel_type[0] = PCM_CHANNEL_FL;
+ mfc_config_info->channel_type[1] = PCM_CHANNEL_FR;
+ } else {
+ pr_err("%s: Unsupported num channels: %d\n",
+ __func__, mfc_config_info->num_channels);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ v->cvp_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(apr_cvp, (uint32_t *)&cvp_set_mfc_config_cmd);
+ if (ret < 0) {
+ pr_err("%s: Failed to send VSS_ICOMMON_CMD_SET_PARAM_V2 %d\n",
+ __func__, ret);
+ goto done;
+ }
+ ret = wait_event_timeout(v->cvp_wait,
+ (v->cvp_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ ret = -ETIMEDOUT;
+ goto done;
+ }
+
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s] handle = %d\n", __func__,
+ adsp_err_get_err_str(v->async_err), cvp_handle);
+ ret = adsp_err_get_lnx_err_code(v->async_err);
+ goto done;
+ }
+ ret = 0;
+done:
+ return ret;
+}
+
+static int voice_send_cvp_mfc_config_cmd(struct voice_data *v)
+{
+ int ret = 0;
+
+ if (common.cvp_version >= CVP_VERSION_2) {
+ ret = voice_send_cvp_mfc_config_v2(v);
+ } else {
+ pr_warn("%s: CVP Version not supported\n", __func__);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int voice_get_avcs_version_per_service(uint32_t service_id)
+{
+ int ret = 0;
+ size_t svc_size;
+ struct avcs_fwk_ver_info ver_info = {{0}, NULL};
+
+ if (service_id == AVCS_SERVICE_ID_ALL) {
+ pr_err("%s: Invalid service id: %d", __func__,
+ AVCS_SERVICE_ID_ALL);
+ return -EINVAL;
+ }
+
+ svc_size = sizeof(struct avs_svc_api_info);
+ ver_info.services = kzalloc(svc_size, GFP_KERNEL);
+ if (ver_info.services == NULL)
+ return -ENOMEM;
+
+ ret = q6core_get_service_version(service_id, &ver_info, svc_size);
+ if (ret < 0)
+ goto done;
+
+ ret = ver_info.services[0].api_version;
+ common.is_avcs_version_queried = true;
+done:
+ kfree(ver_info.services);
+ return ret;
+}
+
static int voice_setup_vocproc(struct voice_data *v)
{
int ret = 0;
@@ -3803,6 +4101,18 @@
goto fail;
}
+ if (common.is_avcs_version_queried == false)
+ common.cvp_version = voice_get_avcs_version_per_service(
+ APRV2_IDS_SERVICE_ID_ADSP_CVP_V);
+
+ if (common.cvp_version < 0) {
+ pr_err("%s: Invalid CVP version %d\n",
+ __func__, common.cvp_version);
+ ret = -EINVAL;
+ goto fail;
+ }
+ pr_debug("%s: CVP Version %d\n", __func__, common.cvp_version);
+
ret = voice_send_cvp_media_fmt_info_cmd(v);
if (ret < 0) {
pr_err("%s: Set media format info failed err:%d\n", __func__,
@@ -3817,6 +4127,15 @@
goto fail;
}
+ /* Send MFC config only when the no of channels are more than 1 */
+ if (v->dev_rx.no_of_channels > NUM_CHANNELS_MONO) {
+ ret = voice_send_cvp_mfc_config_cmd(v);
+ if (ret < 0) {
+ pr_warn("%s: Set mfc config failed err:%d\n",
+ __func__, ret);
+ }
+ }
+
voice_send_cvs_register_cal_cmd(v);
voice_send_cvp_register_dev_cfg_cmd(v);
voice_send_cvp_register_cal_cmd(v);
@@ -3962,11 +4281,18 @@
static int voice_send_cvp_media_fmt_info_cmd(struct voice_data *v)
{
- int ret;
+ int ret = 0;
- ret = voice_send_cvp_device_channels_cmd(v);
- if (ret < 0)
+ if (common.cvp_version < CVP_VERSION_2)
+ ret = voice_send_cvp_device_channels_cmd(v);
+ else
+ ret = voice_send_cvp_channel_info_cmd(v);
+
+ if (ret < 0) {
+ pr_err("%s: Set channel info failed err: %d\n", __func__,
+ ret);
goto done;
+ }
if (voice_get_cvd_int_version(common.cvd_version) >=
CVD_INT_VERSION_2_3) {
@@ -3994,7 +4320,7 @@
void *apr_cvp;
u16 cvp_handle;
struct vss_icommon_param_data_t *media_fmt_param_data =
- &cvp_set_media_format_cmd.cvp_set_param_v2.param_data;
+ &cvp_set_media_format_cmd.cvp_set_media_param_v2.param_data;
struct vss_param_endpoint_media_format_info_t *media_fmt_info =
&media_fmt_param_data->media_format_info;
@@ -4032,7 +4358,7 @@
cvp_set_media_format_cmd.hdr.opcode = VSS_ICOMMON_CMD_SET_PARAM_V2;
/* Fill param data */
- cvp_set_media_format_cmd.cvp_set_param_v2.mem_size =
+ cvp_set_media_format_cmd.cvp_set_media_param_v2.mem_size =
sizeof(struct vss_icommon_param_data_t);
media_fmt_param_data->module_id = VSS_MODULE_CVD_GENERIC;
media_fmt_param_data->param_size =
@@ -6197,6 +6523,15 @@
goto done;
}
+ /* Send MFC config only when the no of channels are > 1 */
+ if (v->dev_rx.no_of_channels > NUM_CHANNELS_MONO) {
+ ret = voice_send_cvp_mfc_config_cmd(v);
+ if (ret < 0) {
+ pr_warn("%s: Set mfc config failed err: %d\n",
+ __func__, ret);
+ }
+ }
+
voice_send_cvp_register_dev_cfg_cmd(v);
voice_send_cvp_register_cal_cmd(v);
voice_send_cvp_register_vol_cal_cmd(v);
@@ -7054,7 +7389,8 @@
case VSS_ICOMMON_CMD_SET_PARAM_V2:
switch (data->token) {
case VOC_SET_MEDIA_FORMAT_PARAM_TOKEN:
- pr_debug("%s: VSS_ICOMMON_CMD_SET_PARAM_V2 called by voice_send_cvp_media_format_cmd\n",
+ case VOC_GENERIC_SET_PARAM_TOKEN:
+ pr_debug("%s: VSS_ICOMMON_CMD_SET_PARAM_V2 called\n",
__func__);
v->cvp_state = CMD_STATUS_SUCCESS;
v->async_err = ptr[1];
@@ -7702,7 +8038,7 @@
if (topology_idx == CVP_VOC_RX_TOPOLOGY_CAL) {
topology = VSS_IVOCPROC_TOPOLOGY_ID_RX_DEFAULT;
} else if (topology_idx == CVP_VOC_TX_TOPOLOGY_CAL) {
- topology = VSS_IVOCPROC_TOPOLOGY_ID_TX_SM_ECNS;
+ topology = VSS_IVOCPROC_TOPOLOGY_ID_TX_SM_ECNS_V2;
} else {
pr_err("%s: cal index %x is invalid!\n",
__func__, topology_idx);
@@ -8566,7 +8902,8 @@
common.default_vol_step_val = 0;
common.default_vol_ramp_duration_ms = DEFAULT_VOLUME_RAMP_DURATION;
common.default_mute_ramp_duration_ms = DEFAULT_MUTE_RAMP_DURATION;
-
+ common.cvp_version = 0;
+ common.is_avcs_version_queried = false;
/* Initialize EC Ref media format info */
common.ec_ref_ext = false;
common.ec_media_fmt_info.port_id = AFE_PORT_INVALID;
diff --git a/sound/soc/msm/qdsp6v2/q6voice.h b/sound/soc/msm/qdsp6v2/q6voice.h
index 74d80be..8a83996e 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.h
+++ b/sound/soc/msm/qdsp6v2/q6voice.h
@@ -124,7 +124,7 @@
};
enum {
- VOC_NO_SET_PARAM_TOKEN = 0,
+ VOC_GENERIC_SET_PARAM_TOKEN = 0,
VOC_RTAC_SET_PARAM_TOKEN,
VOC_SET_MEDIA_FORMAT_PARAM_TOKEN,
VOC_SET_PARAM_TOKEN_MAX
@@ -239,6 +239,19 @@
uint8_t channel_mapping[VSS_NUM_CHANNELS_MAX];
} __packed;
+struct vss_param_vocproc_dev_channel_info_t {
+ uint32_t num_channels;
+ uint32_t bits_per_sample;
+ uint8_t channel_mapping[VSS_NUM_CHANNELS_MAX];
+} __packed;
+
+struct vss_param_mfc_config_info_t {
+ uint32_t sample_rate;
+ uint16_t bits_per_sample;
+ uint16_t num_channels;
+ uint16_t channel_type[VSS_NUM_CHANNELS_MAX];
+} __packed;
+
struct vss_icommon_param_data_t {
/* Valid ID of the module. */
uint32_t module_id;
@@ -260,6 +273,88 @@
};
} __packed;
+struct vss_icommon_param_data_channel_info_v2_t {
+ /* Valid ID of the module. */
+ uint32_t module_id;
+ /* Valid ID of the parameter. */
+ uint32_t param_id;
+ /*
+ * Data size of the structure relating to the param_id/module_id
+ * combination in uint8_t bytes.
+ */
+ uint16_t param_size;
+ /* This field must be set to zero. */
+ uint16_t reserved;
+ struct vss_param_vocproc_dev_channel_info_t channel_info;
+} __packed;
+
+struct vss_icommon_cmd_set_param_channel_info_v2_t {
+ /*
+ * Pointer to the unique identifier for an address (physical/virtual).
+ *
+ * If the parameter data payload is within the message payload
+ * (in-band), set this field to 0. The parameter data begins at the
+ * specified data payload address.
+ *
+ * If the parameter data is out-of-band, this field is the handle to
+ * the physical address in the shared memory that holds the parameter
+ * data.
+ */
+ uint32_t mem_handle;
+ /*
+ * Location of the parameter data payload.
+ *
+ * The payload is an array of vss_icommon_param_data_t. If the
+ * mem_handle is 0, this field is ignored.
+ */
+ uint64_t mem_address;
+ /* Size of the parameter data payload in bytes. */
+ uint32_t mem_size;
+ struct vss_icommon_param_data_channel_info_v2_t param_data;
+} __packed;
+
+struct vss_icommon_param_data_mfc_config_v2_t {
+ /* Valid ID of the module. */
+ uint32_t module_id;
+ /* Valid ID of the parameter. */
+ uint32_t param_id;
+ /*
+ * Data size of the structure relating to the param_id/module_id
+ * combination in uint8_t bytes.
+ */
+ uint16_t param_size;
+ /* This field must be set to zero. */
+ uint16_t reserved;
+ struct vss_param_mfc_config_info_t mfc_config_info;
+} __packed;
+
+struct vss_icommon_cmd_set_param_mfc_config_v2_t {
+ /*
+ * Pointer to the unique identifier for an address (physical/virtual).
+ *
+ * If the parameter data payload is within the message payload
+ * (in-band), set this field to 0. The parameter data begins at the
+ * specified data payload address.
+ *
+ * If the parameter data is out-of-band, this field is the handle to
+ * the physical address in the shared memory that holds the parameter
+ * data.
+ */
+
+ uint32_t mem_handle;
+ /*
+ * Location of the parameter data payload.
+ *
+ * The payload is an array of vss_icommon_param_data_t. If the
+ * mem_handle is 0, this field is ignored.
+ */
+ uint64_t mem_address;
+ /* Size of the parameter data payload in bytes. */
+ uint32_t mem_size;
+
+ struct vss_icommon_param_data_mfc_config_v2_t param_data;
+} __packed;
+
/* Payload structure for the VSS_ICOMMON_CMD_SET_PARAM_V2 command. */
struct vss_icommon_cmd_set_param_v2_t {
/*
@@ -674,6 +769,12 @@
#define VSS_IRECORD_MODE_TX_RX_MIXING 0x00010F7B
/* Select mixed Tx and Rx paths. */
+#define VSS_PARAM_VOCPROC_TX_CHANNEL_INFO 0x0001328E
+
+#define VSS_PARAM_VOCPROC_RX_CHANNEL_INFO 0x0001328F
+
+#define VSS_PARAM_VOCPROC_EC_REF_CHANNEL_INFO 0x00013290
+
#define VSS_PARAM_TX_PORT_ENDPOINT_MEDIA_INFO 0x00013253
#define VSS_PARAM_RX_PORT_ENDPOINT_MEDIA_INFO 0x00013254
@@ -1117,7 +1218,7 @@
#define VSS_IVOCPROC_CMD_DEREGISTER_DYNAMIC_CALIBRATION_DATA 0x0001307C
#define VSS_IVOCPROC_TOPOLOGY_ID_NONE 0x00010F70
-#define VSS_IVOCPROC_TOPOLOGY_ID_TX_SM_ECNS 0x00010F71
+#define VSS_IVOCPROC_TOPOLOGY_ID_TX_SM_ECNS_V2 0x00010F89
#define VSS_IVOCPROC_TOPOLOGY_ID_TX_DM_FLUENCE 0x00010F72
#define VSS_IVOCPROC_TOPOLOGY_ID_RX_DEFAULT 0x00010F77
@@ -1485,7 +1586,18 @@
struct cvp_set_media_format_cmd {
struct apr_hdr hdr;
- struct vss_icommon_cmd_set_param_v2_t cvp_set_param_v2;
+ struct vss_icommon_cmd_set_param_v2_t cvp_set_media_param_v2;
+} __packed;
+
+struct cvp_set_channel_info_cmd_v2 {
+ struct apr_hdr hdr;
+ struct vss_icommon_cmd_set_param_channel_info_v2_t
+ cvp_set_ch_info_param_v2;
+} __packed;
+
+struct cvp_set_mfc_config_cmd_v2 {
+ struct apr_hdr hdr;
+ struct vss_icommon_cmd_set_param_mfc_config_v2_t cvp_set_mfc_param_v2;
} __packed;
struct cvp_set_vp3_data_cmd {
@@ -1756,6 +1868,8 @@
bool srvcc_rec_flag;
bool is_destroy_cvd;
char cvd_version[CVD_VERSION_STRING_MAX_SIZE];
+ int cvp_version;
+ bool is_avcs_version_queried;
bool is_per_vocoder_cal_enabled;
bool is_sound_focus_resp_success;
bool is_source_tracking_resp_success;
diff --git a/sound/soc/msm/sdm660-common.c b/sound/soc/msm/sdm660-common.c
index b34b04b..16f137e 100644
--- a/sound/soc/msm/sdm660-common.c
+++ b/sound/soc/msm/sdm660-common.c
@@ -44,6 +44,8 @@
EXT_DISP_RX_IDX_MAX,
};
+bool codec_reg_done;
+
/* TDM default config */
static struct dev_config tdm_rx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = {
{ /* PRI TDM */
@@ -2016,6 +2018,12 @@
}
EXPORT_SYMBOL(msm_common_snd_controls_size);
+void msm_set_codec_reg_done(bool done)
+{
+ codec_reg_done = done;
+}
+EXPORT_SYMBOL(msm_set_codec_reg_done);
+
static inline int param_is_mask(int p)
{
return (p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) &&
@@ -3027,6 +3035,12 @@
.data = "tasha_codec"},
{ .compatible = "qcom,sdm660-asoc-snd-tavil",
.data = "tavil_codec"},
+ { .compatible = "qcom,sdm670-asoc-snd",
+ .data = "internal_codec"},
+ { .compatible = "qcom,sdm670-asoc-snd-tasha",
+ .data = "tasha_codec"},
+ { .compatible = "qcom,sdm670-asoc-snd-tavil",
+ .data = "tavil_codec"},
{},
};
@@ -3044,6 +3058,7 @@
if (!pdata)
return -ENOMEM;
+ msm_set_codec_reg_done(false);
match = of_match_node(sdm660_asoc_machine_of_match,
pdev->dev.of_node);
if (!match)
@@ -3171,8 +3186,6 @@
gpio_free(pdata->hph_en0_gpio);
pdata->hph_en0_gpio = 0;
}
- if (pdata->snd_card_val != INT_SND_CARD)
- msm_ext_cdc_deinit(pdata);
devm_kfree(&pdev->dev, pdata);
return ret;
}
@@ -3184,10 +3197,8 @@
if (pdata->snd_card_val == INT_SND_CARD)
mutex_destroy(&pdata->cdc_int_mclk0_mutex);
- else
- msm_ext_cdc_deinit(pdata);
- msm_free_auxdev_mem(pdev);
+ msm_free_auxdev_mem(pdev);
gpio_free(pdata->us_euro_gpio);
gpio_free(pdata->hph_en1_gpio);
gpio_free(pdata->hph_en0_gpio);
diff --git a/sound/soc/msm/sdm660-common.h b/sound/soc/msm/sdm660-common.h
index bca8cd7..f4787ae 100644
--- a/sound/soc/msm/sdm660-common.h
+++ b/sound/soc/msm/sdm660-common.h
@@ -78,14 +78,6 @@
EXT_SND_CARD_TAVIL,
};
-struct msm_snd_interrupt {
- void __iomem *mpm_wakeup;
- void __iomem *intr1_cfg_apps;
- void __iomem *lpi_gpio_intr_cfg;
- void __iomem *lpi_gpio_cfg;
- void __iomem *lpi_gpio_inout;
-};
-
struct msm_asoc_mach_data {
int us_euro_gpio; /* used by gpio driver API */
int hph_en1_gpio;
@@ -112,7 +104,6 @@
struct mutex cdc_int_mclk0_mutex;
struct delayed_work disable_int_mclk0_work;
struct afe_clk_set digital_cdc_core_clk;
- struct msm_snd_interrupt msm_snd_intr_lpi;
};
int msm_common_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
@@ -122,4 +113,5 @@
int msm_mi2s_snd_startup(struct snd_pcm_substream *substream);
void msm_mi2s_snd_shutdown(struct snd_pcm_substream *substream);
int msm_common_snd_controls_size(void);
+void msm_set_codec_reg_done(bool done);
#endif
diff --git a/sound/soc/msm/sdm660-ext-dai-links.c b/sound/soc/msm/sdm660-ext-dai-links.c
index 6ff29c9..68a0f37 100644
--- a/sound/soc/msm/sdm660-ext-dai-links.c
+++ b/sound/soc/msm/sdm660-ext-dai-links.c
@@ -29,8 +29,15 @@
#define WCN_CDC_SLIM_RX_CH_MAX 2
#define WCN_CDC_SLIM_TX_CH_MAX 3
-static struct snd_soc_card snd_soc_card_msm_card_tavil;
-static struct snd_soc_card snd_soc_card_msm_card_tasha;
+static struct snd_soc_card snd_soc_card_msm_card_tavil = {
+ .name = "sdm670-tavil-snd-card",
+ .late_probe = msm_snd_card_tavil_late_probe,
+};
+
+static struct snd_soc_card snd_soc_card_msm_card_tasha = {
+ .name = "sdm670-tasha-snd-card",
+ .late_probe = msm_snd_card_tasha_late_probe,
+};
static struct snd_soc_ops msm_ext_slimbus_be_ops = {
.hw_params = msm_snd_hw_params,
@@ -990,13 +997,14 @@
.id = MSM_FRONTEND_DAI_MULTIMEDIA7,
},
{/* hw:x,16 */
- .name = MSM_DAILINK_NAME(Compress3),
- .stream_name = "Compress3",
+ .name = MSM_DAILINK_NAME(MultiMedia10),
+ .stream_name = "MultiMedia10",
.cpu_dai_name = "MultiMedia10",
- .platform_name = "msm-compress-dsp",
+ .platform_name = "msm-pcm-dsp.1",
.dynamic = 1,
.dpcm_capture = 1,
.dpcm_playback = 1,
+ .dpcm_capture = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
.codec_dai_name = "snd-soc-dummy-dai",
diff --git a/sound/soc/msm/sdm660-external.c b/sound/soc/msm/sdm660-external.c
index 426c150..6bf9e58 100644
--- a/sound/soc/msm/sdm660-external.c
+++ b/sound/soc/msm/sdm660-external.c
@@ -34,28 +34,11 @@
#define CODEC_EXT_CLK_RATE 9600000
#define ADSP_STATE_READY_TIMEOUT_MS 3000
-#define TLMM_CENTER_MPM_WAKEUP_INT_EN_0 0x03596000
-#define LPI_GPIO_22_WAKEUP_VAL 0x00000002
-
-#define TLMM_LPI_DIR_CONN_INTR1_CFG_APPS 0x0359D004
-#define LPI_GPIO_22_INTR1_CFG_VAL 0x01
-#define LPI_GPIO_22_INTR1_CFG_MASK 0x03
-
-#define TLMM_LPI_GPIO_INTR_CFG1 0x0359B004
-#define LPI_GPIO_INTR_CFG1_VAL 0x00000113
-
-#define TLMM_LPI_GPIO22_CFG 0x15078040
-#define LPI_GPIO22_CFG_VAL 0x0000009
-
-#define TLMM_LPI_GPIO22_INOUT 0x179D1318
-#define LPI_GPIO22_INOUT_VAL 0x0020000
-
#define WSA8810_NAME_1 "wsa881x.20170211"
#define WSA8810_NAME_2 "wsa881x.20170212"
static int msm_ext_spk_control = 1;
static struct wcd_mbhc_config *wcd_mbhc_cfg_ptr;
-bool codec_reg_done;
struct msm_asoc_wcd93xx_codec {
void* (*get_afe_config_fn)(struct snd_soc_codec *codec,
@@ -603,23 +586,23 @@
static void *def_ext_mbhc_cal(void)
{
- void *tavil_wcd_cal;
+ void *wcd_mbhc_cal;
struct wcd_mbhc_btn_detect_cfg *btn_cfg;
u16 *btn_high;
- tavil_wcd_cal = kzalloc(WCD_MBHC_CAL_SIZE(WCD_MBHC_DEF_BUTTONS,
+ wcd_mbhc_cal = kzalloc(WCD_MBHC_CAL_SIZE(WCD_MBHC_DEF_BUTTONS,
WCD9XXX_MBHC_DEF_RLOADS), GFP_KERNEL);
- if (!tavil_wcd_cal)
+ if (!wcd_mbhc_cal)
return NULL;
-#define S(X, Y) ((WCD_MBHC_CAL_PLUG_TYPE_PTR(tavil_wcd_cal)->X) = (Y))
+#define S(X, Y) ((WCD_MBHC_CAL_PLUG_TYPE_PTR(wcd_mbhc_cal)->X) = (Y))
S(v_hs_max, 1600);
#undef S
-#define S(X, Y) ((WCD_MBHC_CAL_BTN_DET_PTR(tavil_wcd_cal)->X) = (Y))
+#define S(X, Y) ((WCD_MBHC_CAL_BTN_DET_PTR(wcd_mbhc_cal)->X) = (Y))
S(num_btn, WCD_MBHC_DEF_BUTTONS);
#undef S
- btn_cfg = WCD_MBHC_CAL_BTN_DET_PTR(tavil_wcd_cal);
+ btn_cfg = WCD_MBHC_CAL_BTN_DET_PTR(wcd_mbhc_cal);
btn_high = ((void *)&btn_cfg->_v_btn_low) +
(sizeof(btn_cfg->_v_btn_low[0]) * btn_cfg->num_btn);
@@ -632,7 +615,7 @@
btn_high[6] = 500;
btn_high[7] = 500;
- return tavil_wcd_cal;
+ return wcd_mbhc_cal;
}
static inline int param_is_mask(int p)
@@ -1209,28 +1192,6 @@
afe_clear_config(AFE_SLIMBUS_SLAVE_CONFIG);
}
-static void msm_snd_interrupt_config(struct msm_asoc_mach_data *pdata)
-{
- int val;
-
- val = ioread32(pdata->msm_snd_intr_lpi.mpm_wakeup);
- val |= LPI_GPIO_22_WAKEUP_VAL;
- iowrite32(val, pdata->msm_snd_intr_lpi.mpm_wakeup);
-
- val = ioread32(pdata->msm_snd_intr_lpi.intr1_cfg_apps);
- val &= ~(LPI_GPIO_22_INTR1_CFG_MASK);
- val |= LPI_GPIO_22_INTR1_CFG_VAL;
- iowrite32(val, pdata->msm_snd_intr_lpi.intr1_cfg_apps);
-
- iowrite32(LPI_GPIO_INTR_CFG1_VAL,
- pdata->msm_snd_intr_lpi.lpi_gpio_intr_cfg);
- iowrite32(LPI_GPIO22_CFG_VAL,
- pdata->msm_snd_intr_lpi.lpi_gpio_cfg);
- val = ioread32(pdata->msm_snd_intr_lpi.lpi_gpio_inout);
- val |= LPI_GPIO22_INOUT_VAL;
- iowrite32(val, pdata->msm_snd_intr_lpi.lpi_gpio_inout);
-}
-
static int msm_adsp_power_up_config(struct snd_soc_codec *codec)
{
int ret = 0;
@@ -1262,7 +1223,6 @@
ret = -ETIMEDOUT;
goto err_fail;
}
- msm_snd_interrupt_config(pdata);
ret = msm_afe_set_config(codec);
if (ret)
@@ -1478,6 +1438,79 @@
{"MIC BIAS4", NULL, "MCLK"},
};
+int msm_snd_card_tasha_late_probe(struct snd_soc_card *card)
+{
+ const char *be_dl_name = LPASS_BE_SLIMBUS_0_RX;
+ struct snd_soc_pcm_runtime *rtd;
+ int ret = 0;
+ void *mbhc_calibration;
+
+ rtd = snd_soc_get_pcm_runtime(card, be_dl_name);
+ if (!rtd) {
+ dev_err(card->dev,
+ "%s: snd_soc_get_pcm_runtime for %s failed!\n",
+ __func__, be_dl_name);
+ ret = -EINVAL;
+ goto err_pcm_runtime;
+ }
+
+ mbhc_calibration = def_ext_mbhc_cal();
+ if (!mbhc_calibration) {
+ ret = -ENOMEM;
+ goto err_mbhc_cal;
+ }
+ wcd_mbhc_cfg_ptr->calibration = mbhc_calibration;
+ ret = tasha_mbhc_hs_detect(rtd->codec, wcd_mbhc_cfg_ptr);
+ if (ret) {
+ dev_err(card->dev, "%s: mbhc hs detect failed, err:%d\n",
+ __func__, ret);
+ goto err_hs_detect;
+ }
+ return 0;
+
+err_hs_detect:
+ kfree(mbhc_calibration);
+err_mbhc_cal:
+err_pcm_runtime:
+ return ret;
+}
+
+int msm_snd_card_tavil_late_probe(struct snd_soc_card *card)
+{
+ const char *be_dl_name = LPASS_BE_SLIMBUS_0_RX;
+ struct snd_soc_pcm_runtime *rtd;
+ int ret = 0;
+ void *mbhc_calibration;
+
+ rtd = snd_soc_get_pcm_runtime(card, be_dl_name);
+ if (!rtd) {
+ dev_err(card->dev,
+ "%s: snd_soc_get_pcm_runtime for %s failed!\n",
+ __func__, be_dl_name);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ mbhc_calibration = def_ext_mbhc_cal();
+ if (!mbhc_calibration) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ wcd_mbhc_cfg_ptr->calibration = mbhc_calibration;
+ ret = tavil_mbhc_hs_detect(rtd->codec, wcd_mbhc_cfg_ptr);
+ if (ret) {
+ dev_err(card->dev, "%s: mbhc hs detect failed, err:%d\n",
+ __func__, ret);
+ goto err_free_mbhc_cal;
+ }
+ return 0;
+
+err_free_mbhc_cal:
+ kfree(mbhc_calibration);
+err:
+ return ret;
+}
+
/**
* msm_audrx_init - Audio init function of sound card instantiate.
*
@@ -1698,7 +1731,6 @@
if (!entry) {
pr_debug("%s: Cannot create codecs module entry\n",
__func__);
- pdata->codec_root = NULL;
goto done;
}
pdata->codec_root = entry;
@@ -1721,50 +1753,17 @@
if (!entry) {
pr_debug("%s: Cannot create codecs module entry\n",
__func__);
- ret = 0;
- goto err_snd_module;
+ goto done;
}
pdata->codec_root = entry;
tasha_codec_info_create_codec_entry(pdata->codec_root, codec);
tasha_mbhc_zdet_gpio_ctrl(msm_config_hph_en0_gpio, rtd->codec);
}
-
- wcd_mbhc_cfg_ptr->calibration = def_ext_mbhc_cal();
- if (!strcmp(dev_name(codec_dai->dev), "tavil_codec")) {
- if (wcd_mbhc_cfg_ptr->calibration) {
- pdata->codec = codec;
- ret = tavil_mbhc_hs_detect(codec, wcd_mbhc_cfg_ptr);
- if (ret < 0)
- pr_err("%s: Failed to intialise mbhc %d\n",
- __func__, ret);
- } else {
- pr_err("%s: wcd_mbhc_cfg calibration is NULL\n",
- __func__);
- ret = -ENOMEM;
- goto err_mbhc_cal;
- }
- } else {
- if (wcd_mbhc_cfg_ptr->calibration) {
- pdata->codec = codec;
- ret = tasha_mbhc_hs_detect(codec, wcd_mbhc_cfg_ptr);
- if (ret < 0)
- pr_err("%s: Failed to intialise mbhc %d\n",
- __func__, ret);
- } else {
- pr_err("%s: wcd_mbhc_cfg calibration is NULL\n",
- __func__);
- ret = -ENOMEM;
- goto err_mbhc_cal;
- }
-
- }
- codec_reg_done = true;
done:
+ msm_set_codec_reg_done(true);
return 0;
-err_snd_module:
err_afe_cfg:
-err_mbhc_cal:
return ret;
}
EXPORT_SYMBOL(msm_audrx_init);
@@ -1844,36 +1843,7 @@
ret);
ret = 0;
}
- pdata->msm_snd_intr_lpi.mpm_wakeup =
- ioremap(TLMM_CENTER_MPM_WAKEUP_INT_EN_0, 4);
- pdata->msm_snd_intr_lpi.intr1_cfg_apps =
- ioremap(TLMM_LPI_DIR_CONN_INTR1_CFG_APPS, 4);
- pdata->msm_snd_intr_lpi.lpi_gpio_intr_cfg =
- ioremap(TLMM_LPI_GPIO_INTR_CFG1, 4);
- pdata->msm_snd_intr_lpi.lpi_gpio_cfg =
- ioremap(TLMM_LPI_GPIO22_CFG, 4);
- pdata->msm_snd_intr_lpi.lpi_gpio_inout =
- ioremap(TLMM_LPI_GPIO22_INOUT, 4);
err:
return ret;
}
EXPORT_SYMBOL(msm_ext_cdc_init);
-
-/**
- * msm_ext_cdc_deinit - external codec machine specific deinit.
- */
-void msm_ext_cdc_deinit(struct msm_asoc_mach_data *pdata)
-{
- if (pdata->msm_snd_intr_lpi.mpm_wakeup)
- iounmap(pdata->msm_snd_intr_lpi.mpm_wakeup);
- if (pdata->msm_snd_intr_lpi.intr1_cfg_apps)
- iounmap(pdata->msm_snd_intr_lpi.intr1_cfg_apps);
- if (pdata->msm_snd_intr_lpi.lpi_gpio_intr_cfg)
- iounmap(pdata->msm_snd_intr_lpi.lpi_gpio_intr_cfg);
- if (pdata->msm_snd_intr_lpi.lpi_gpio_cfg)
- iounmap(pdata->msm_snd_intr_lpi.lpi_gpio_cfg);
- if (pdata->msm_snd_intr_lpi.lpi_gpio_inout)
- iounmap(pdata->msm_snd_intr_lpi.lpi_gpio_inout);
-
-}
-EXPORT_SYMBOL(msm_ext_cdc_deinit);
diff --git a/sound/soc/msm/sdm660-external.h b/sound/soc/msm/sdm660-external.h
index acf5735..0648c01 100644
--- a/sound/soc/msm/sdm660-external.h
+++ b/sound/soc/msm/sdm660-external.h
@@ -30,11 +30,12 @@
int snd_card_val);
int msm_ext_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params);
+int msm_snd_card_tavil_late_probe(struct snd_soc_card *card);
+int msm_snd_card_tasha_late_probe(struct snd_soc_card *card);
#ifdef CONFIG_SND_SOC_EXT_CODEC
int msm_ext_cdc_init(struct platform_device *, struct msm_asoc_mach_data *,
struct snd_soc_card **, struct wcd_mbhc_config *);
void msm_ext_register_audio_notifier(struct platform_device *pdev);
-void msm_ext_cdc_deinit(struct msm_asoc_mach_data *pdata);
#else
inline int msm_ext_cdc_init(struct platform_device *pdev,
struct msm_asoc_mach_data *pdata,
@@ -47,8 +48,5 @@
inline void msm_ext_register_audio_notifier(struct platform_device *pdev)
{
}
-inline void msm_ext_cdc_deinit(void)
-{
-}
#endif
#endif
diff --git a/sound/soc/msm/sdm660-internal.c b/sound/soc/msm/sdm660-internal.c
index 4b9334b..14e7308 100644
--- a/sound/soc/msm/sdm660-internal.c
+++ b/sound/soc/msm/sdm660-internal.c
@@ -1314,6 +1314,7 @@
msm_dig_codec_info_create_codec_entry(codec_root, dig_cdc);
msm_anlg_codec_info_create_codec_entry(codec_root, ana_cdc);
done:
+ msm_set_codec_reg_done(true);
return 0;
}
@@ -1914,13 +1915,14 @@
.id = MSM_FRONTEND_DAI_MULTIMEDIA7,
},
{/* hw:x,16 */
- .name = MSM_DAILINK_NAME(Compress3),
- .stream_name = "Compress3",
+ .name = MSM_DAILINK_NAME(MultiMedia10),
+ .stream_name = "MultiMedia10",
.cpu_dai_name = "MultiMedia10",
- .platform_name = "msm-compress-dsp",
+ .platform_name = "msm-pcm-dsp.1",
.dynamic = 1,
.dpcm_capture = 1,
.dpcm_playback = 1,
+ .dpcm_capture = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
.codec_dai_name = "snd-soc-dummy-dai",
diff --git a/sound/soc/msm/sdm845.c b/sound/soc/msm/sdm845.c
index 03a4938..7a5ccd8 100644
--- a/sound/soc/msm/sdm845.c
+++ b/sound/soc/msm/sdm845.c
@@ -134,6 +134,13 @@
u32 msm_is_mi2s_master;
};
+static u32 mi2s_ebit_clk[MI2S_MAX] = {
+ Q6AFE_LPASS_CLK_ID_PRI_MI2S_EBIT,
+ Q6AFE_LPASS_CLK_ID_SEC_MI2S_EBIT,
+ Q6AFE_LPASS_CLK_ID_TER_MI2S_EBIT,
+ Q6AFE_LPASS_CLK_ID_QUAD_MI2S_EBIT
+};
+
struct auxpcm_conf {
struct mutex lock;
u32 ref_cnt;
@@ -434,6 +441,7 @@
"Five", "Six", "Seven",
"Eight"};
static const char *const hifi_text[] = {"Off", "On"};
+static const char *const qos_text[] = {"Disable", "Enable"};
static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_chs, slim_rx_ch_text);
static SOC_ENUM_SINGLE_EXT_DECL(slim_2_rx_chs, slim_rx_ch_text);
@@ -498,9 +506,11 @@
static SOC_ENUM_SINGLE_EXT_DECL(aux_pcm_rx_format, bit_format_text);
static SOC_ENUM_SINGLE_EXT_DECL(aux_pcm_tx_format, bit_format_text);
static SOC_ENUM_SINGLE_EXT_DECL(hifi_function, hifi_text);
+static SOC_ENUM_SINGLE_EXT_DECL(qos_vote, qos_text);
static struct platform_device *spdev;
static int msm_hifi_control;
+static int qos_vote_status;
static bool is_initial_boot;
static bool codec_reg_done;
@@ -2628,6 +2638,72 @@
return 0;
}
+static s32 msm_qos_value(struct snd_pcm_runtime *runtime)
+{
+ s32 usecs;
+
+ if (!runtime->rate)
+ return -EINVAL;
+
+ /* take 75% of period time as the deadline */
+ usecs = (750000 / runtime->rate) * runtime->period_size;
+ usecs += ((750000 % runtime->rate) * runtime->period_size) /
+ runtime->rate;
+
+ return usecs;
+}
+
+static int msm_qos_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.enumerated.item[0] = qos_vote_status;
+
+ return 0;
+}
+
+static int msm_qos_ctl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct snd_soc_card *card = codec->component.card;
+ const char *be_name = MSM_DAILINK_NAME(LowLatency);
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_pcm_substream *substream;
+ s32 usecs;
+
+ rtd = snd_soc_get_pcm_runtime(card, be_name);
+ if (!rtd) {
+ pr_err("%s: fail to get pcm runtime for %s\n",
+ __func__, be_name);
+ return -EINVAL;
+ }
+
+ substream = rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+ if (!substream) {
+ pr_err("%s: substream is null\n", __func__);
+ return -EINVAL;
+ }
+
+ qos_vote_status = ucontrol->value.enumerated.item[0];
+ if (qos_vote_status) {
+ if (pm_qos_request_active(&substream->latency_pm_qos_req))
+ pm_qos_remove_request(&substream->latency_pm_qos_req);
+ if (!substream->runtime) {
+ pr_err("%s: runtime is null\n", __func__);
+ return -EINVAL;
+ }
+ usecs = msm_qos_value(substream->runtime);
+ if (usecs >= 0)
+ pm_qos_add_request(&substream->latency_pm_qos_req,
+ PM_QOS_CPU_DMA_LATENCY, usecs);
+ } else {
+ if (pm_qos_request_active(&substream->latency_pm_qos_req))
+ pm_qos_remove_request(&substream->latency_pm_qos_req);
+ }
+
+ return 0;
+}
+
static const struct snd_kcontrol_new msm_snd_controls[] = {
SOC_ENUM_EXT("SLIM_0_RX Channels", slim_0_rx_chs,
msm_slim_rx_ch_get, msm_slim_rx_ch_put),
@@ -2857,6 +2933,8 @@
msm_aux_pcm_tx_format_get, msm_aux_pcm_tx_format_put),
SOC_ENUM_EXT("HiFi Function", hifi_function, msm_hifi_get,
msm_hifi_put),
+ SOC_ENUM_EXT("MultiMedia5_RX QOS Vote", qos_vote, msm_qos_ctl_get,
+ msm_qos_ctl_put),
};
static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec,
@@ -4176,9 +4254,6 @@
mi2s_clk[dai_id].clk_freq_in_hz =
mi2s_tx_cfg[dai_id].sample_rate * 2 * bit_per_sample;
}
-
- if (!mi2s_intf_conf[dai_id].msm_is_mi2s_master)
- mi2s_clk[dai_id].clk_freq_in_hz = 0;
}
static int msm_mi2s_set_sclk(struct snd_pcm_substream *substream, bool enable)
@@ -4529,6 +4604,11 @@
*/
mutex_lock(&mi2s_intf_conf[index].lock);
if (++mi2s_intf_conf[index].ref_cnt == 1) {
+ /* Check if msm needs to provide the clock to the interface */
+ if (!mi2s_intf_conf[index].msm_is_mi2s_master) {
+ mi2s_clk[index].clk_id = mi2s_ebit_clk[index];
+ fmt = SND_SOC_DAIFMT_CBM_CFM;
+ }
ret = msm_mi2s_set_sclk(substream, true);
if (ret < 0) {
dev_err(rtd->card->dev,
@@ -4548,9 +4628,6 @@
ret = -EINVAL;
goto clk_off;
}
- /* Check if msm needs to provide the clock to the interface */
- if (!mi2s_intf_conf[index].msm_is_mi2s_master)
- fmt = SND_SOC_DAIFMT_CBM_CFM;
ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
if (ret < 0) {
pr_err("%s: set fmt cpu dai failed for MI2S (%d), err:%d\n",
@@ -5049,12 +5126,13 @@
.id = MSM_FRONTEND_DAI_MULTIMEDIA7,
},
{
- .name = MSM_DAILINK_NAME(Compress3),
- .stream_name = "Compress3",
+ .name = MSM_DAILINK_NAME(MultiMedia10),
+ .stream_name = "MultiMedia10",
.cpu_dai_name = "MultiMedia10",
- .platform_name = "msm-compress-dsp",
+ .platform_name = "msm-pcm-dsp.1",
.dynamic = 1,
.dpcm_playback = 1,
+ .dpcm_capture = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
.codec_dai_name = "snd-soc-dummy-dai",
@@ -6619,16 +6697,18 @@
ret = of_property_read_u32(pdev->dev.of_node,
"qcom,wsa-max-devs", &wsa_max_devs);
if (ret) {
- dev_dbg(&pdev->dev,
+ dev_info(&pdev->dev,
"%s: wsa-max-devs property missing in DT %s, ret = %d\n",
__func__, pdev->dev.of_node->full_name, ret);
- goto err;
+ card->num_aux_devs = 0;
+ return 0;
}
if (wsa_max_devs == 0) {
dev_warn(&pdev->dev,
"%s: Max WSA devices is 0 for this target?\n",
__func__);
- goto err;
+ card->num_aux_devs = 0;
+ return 0;
}
/* Get count of WSA device phandles for this platform */
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 6b23bf5..4f6c777 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -3326,7 +3326,8 @@
*/
void snd_soc_card_change_online_state(struct snd_soc_card *soc_card, int online)
{
- snd_card_change_online_state(soc_card->snd_card, online);
+ if (soc_card && soc_card->snd_card)
+ snd_card_change_online_state(soc_card->snd_card, online);
}
EXPORT_SYMBOL(snd_soc_card_change_online_state);
diff --git a/sound/usb/card.c b/sound/usb/card.c
index eaf18aa..a87a526 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -619,7 +619,7 @@
assoc = intf->intf_assoc;
if (assoc && assoc->bFunctionClass == USB_CLASS_AUDIO &&
assoc->bFunctionProtocol == UAC_VERSION_3 &&
- assoc->bFunctionSubClass == FULL_ADC_PROFILE) {
+ assoc->bFunctionSubClass == FULL_ADC_3_0) {
dev_info(&dev->dev, "No support for full-fledged ADC 3.0 yet!!\n");
return -EINVAL;
}
diff --git a/techpack/.gitignore b/techpack/.gitignore
new file mode 100644
index 0000000..58da0b8
--- /dev/null
+++ b/techpack/.gitignore
@@ -0,0 +1,2 @@
+# ignore all subdirs except stub
+!/stub/
diff --git a/techpack/Kbuild b/techpack/Kbuild
new file mode 100644
index 0000000..3c7c8e6
--- /dev/null
+++ b/techpack/Kbuild
@@ -0,0 +1,5 @@
+techpack-dirs := $(shell find $(srctree)/$(src) -maxdepth 1 -mindepth 1 -type d -not -name ".*")
+obj-y += stub/ $(addsuffix /,$(subst $(srctree)/$(src)/,,$(techpack-dirs)))
+
+techpack-header-dirs := $(shell find $(srctree)/techpack -maxdepth 1 -mindepth 1 -type d -not -name ".*")
+header-y += $(addsuffix /include/uapi/,$(subst $(srctree)/techpack/,,$(techpack-header-dirs)))
diff --git a/techpack/stub/Makefile b/techpack/stub/Makefile
new file mode 100644
index 0000000..184b5c7
--- /dev/null
+++ b/techpack/stub/Makefile
@@ -0,0 +1,2 @@
+ccflags-y := -Wno-unused-function
+obj-y := stub.o
diff --git a/techpack/stub/include/uapi/Kbuild b/techpack/stub/include/uapi/Kbuild
new file mode 100644
index 0000000..87bfa65
--- /dev/null
+++ b/techpack/stub/include/uapi/Kbuild
@@ -0,0 +1 @@
+#Stub place holder
diff --git a/techpack/stub/stub.c b/techpack/stub/stub.c
new file mode 100644
index 0000000..6024341
--- /dev/null
+++ b/techpack/stub/stub.c
@@ -0,0 +1,3 @@
+static void _techpack_stub(void)
+{
+}
diff --git a/tools/lib/lockdep/uinclude/linux/lockdep.h b/tools/lib/lockdep/uinclude/linux/lockdep.h
index c808c7d..d302142 100644
--- a/tools/lib/lockdep/uinclude/linux/lockdep.h
+++ b/tools/lib/lockdep/uinclude/linux/lockdep.h
@@ -8,7 +8,7 @@
#include <linux/utsname.h>
#include <linux/compiler.h>
-#define MAX_LOCK_DEPTH 2000UL
+#define MAX_LOCK_DEPTH 63UL
#define asmlinkage
#define __visible
diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c
index 3eb3edb..a130901 100644
--- a/tools/perf/ui/browser.c
+++ b/tools/perf/ui/browser.c
@@ -702,7 +702,7 @@
ui_browser__gotorc(browser, row, column + 1);
SLsmg_draw_hline(2);
- if (row++ == 0)
+ if (++row == 0)
goto out;
} else
row = 0;
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
index 04387ab..7e27207 100644
--- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
+++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
@@ -64,6 +64,25 @@
INTEL_PT_STATE_FUP_NO_TIP,
};
+static inline bool intel_pt_sample_time(enum intel_pt_pkt_state pkt_state)
+{
+ switch (pkt_state) {
+ case INTEL_PT_STATE_NO_PSB:
+ case INTEL_PT_STATE_NO_IP:
+ case INTEL_PT_STATE_ERR_RESYNC:
+ case INTEL_PT_STATE_IN_SYNC:
+ case INTEL_PT_STATE_TNT:
+ return true;
+ case INTEL_PT_STATE_TIP:
+ case INTEL_PT_STATE_TIP_PGD:
+ case INTEL_PT_STATE_FUP:
+ case INTEL_PT_STATE_FUP_NO_TIP:
+ return false;
+ default:
+ return true;
+ };
+}
+
#ifdef INTEL_PT_STRICT
#define INTEL_PT_STATE_ERR1 INTEL_PT_STATE_NO_PSB
#define INTEL_PT_STATE_ERR2 INTEL_PT_STATE_NO_PSB
@@ -92,6 +111,7 @@
bool have_tma;
bool have_cyc;
bool fixup_last_mtc;
+ bool have_last_ip;
uint64_t pos;
uint64_t last_ip;
uint64_t ip;
@@ -99,6 +119,7 @@
uint64_t timestamp;
uint64_t tsc_timestamp;
uint64_t ref_timestamp;
+ uint64_t sample_timestamp;
uint64_t ret_addr;
uint64_t ctc_timestamp;
uint64_t ctc_delta;
@@ -139,6 +160,7 @@
unsigned int fup_tx_flags;
unsigned int tx_flags;
uint64_t timestamp_insn_cnt;
+ uint64_t sample_insn_cnt;
uint64_t stuck_ip;
int no_progress;
int stuck_ip_prd;
@@ -398,6 +420,7 @@
static inline void intel_pt_set_last_ip(struct intel_pt_decoder *decoder)
{
decoder->last_ip = intel_pt_calc_ip(&decoder->packet, decoder->last_ip);
+ decoder->have_last_ip = true;
}
static inline void intel_pt_set_ip(struct intel_pt_decoder *decoder)
@@ -898,6 +921,7 @@
decoder->tot_insn_cnt += insn_cnt;
decoder->timestamp_insn_cnt += insn_cnt;
+ decoder->sample_insn_cnt += insn_cnt;
decoder->period_insn_cnt += insn_cnt;
if (err) {
@@ -1444,7 +1468,8 @@
case INTEL_PT_FUP:
decoder->pge = true;
- intel_pt_set_last_ip(decoder);
+ if (decoder->packet.count)
+ intel_pt_set_last_ip(decoder);
break;
case INTEL_PT_MODE_TSX:
@@ -1648,6 +1673,8 @@
break;
case INTEL_PT_PSB:
+ decoder->last_ip = 0;
+ decoder->have_last_ip = true;
intel_pt_clear_stack(&decoder->stack);
err = intel_pt_walk_psbend(decoder);
if (err == -EAGAIN)
@@ -1728,8 +1755,9 @@
static inline bool intel_pt_have_ip(struct intel_pt_decoder *decoder)
{
- return decoder->last_ip || decoder->packet.count == 0 ||
- decoder->packet.count == 3 || decoder->packet.count == 6;
+ return decoder->packet.count &&
+ (decoder->have_last_ip || decoder->packet.count == 3 ||
+ decoder->packet.count == 6);
}
/* Walk PSB+ packets to get in sync. */
@@ -1852,14 +1880,10 @@
break;
case INTEL_PT_FUP:
- if (decoder->overflow) {
- if (intel_pt_have_ip(decoder))
- intel_pt_set_ip(decoder);
- if (decoder->ip)
- return 0;
- }
- if (decoder->packet.count)
- intel_pt_set_last_ip(decoder);
+ if (intel_pt_have_ip(decoder))
+ intel_pt_set_ip(decoder);
+ if (decoder->ip)
+ return 0;
break;
case INTEL_PT_MTC:
@@ -1908,6 +1932,9 @@
break;
case INTEL_PT_PSB:
+ decoder->last_ip = 0;
+ decoder->have_last_ip = true;
+ intel_pt_clear_stack(&decoder->stack);
err = intel_pt_walk_psb(decoder);
if (err)
return err;
@@ -1933,6 +1960,8 @@
{
int err;
+ decoder->set_fup_tx_flags = false;
+
intel_pt_log("Scanning for full IP\n");
err = intel_pt_walk_to_ip(decoder);
if (err)
@@ -2041,6 +2070,7 @@
decoder->pge = false;
decoder->continuous_period = false;
+ decoder->have_last_ip = false;
decoder->last_ip = 0;
decoder->ip = 0;
intel_pt_clear_stack(&decoder->stack);
@@ -2049,6 +2079,7 @@
if (err)
return err;
+ decoder->have_last_ip = true;
decoder->pkt_state = INTEL_PT_STATE_NO_IP;
err = intel_pt_walk_psb(decoder);
@@ -2067,7 +2098,7 @@
static uint64_t intel_pt_est_timestamp(struct intel_pt_decoder *decoder)
{
- uint64_t est = decoder->timestamp_insn_cnt << 1;
+ uint64_t est = decoder->sample_insn_cnt << 1;
if (!decoder->cbr || !decoder->max_non_turbo_ratio)
goto out;
@@ -2075,7 +2106,7 @@
est *= decoder->max_non_turbo_ratio;
est /= decoder->cbr;
out:
- return decoder->timestamp + est;
+ return decoder->sample_timestamp + est;
}
const struct intel_pt_state *intel_pt_decode(struct intel_pt_decoder *decoder)
@@ -2091,7 +2122,9 @@
err = intel_pt_sync(decoder);
break;
case INTEL_PT_STATE_NO_IP:
+ decoder->have_last_ip = false;
decoder->last_ip = 0;
+ decoder->ip = 0;
/* Fall through */
case INTEL_PT_STATE_ERR_RESYNC:
err = intel_pt_sync_ip(decoder);
@@ -2128,15 +2161,24 @@
}
} while (err == -ENOLINK);
- decoder->state.err = err ? intel_pt_ext_err(err) : 0;
- decoder->state.timestamp = decoder->timestamp;
+ if (err) {
+ decoder->state.err = intel_pt_ext_err(err);
+ decoder->state.from_ip = decoder->ip;
+ decoder->sample_timestamp = decoder->timestamp;
+ decoder->sample_insn_cnt = decoder->timestamp_insn_cnt;
+ } else {
+ decoder->state.err = 0;
+ if (intel_pt_sample_time(decoder->pkt_state)) {
+ decoder->sample_timestamp = decoder->timestamp;
+ decoder->sample_insn_cnt = decoder->timestamp_insn_cnt;
+ }
+ }
+
+ decoder->state.timestamp = decoder->sample_timestamp;
decoder->state.est_timestamp = intel_pt_est_timestamp(decoder);
decoder->state.cr3 = decoder->cr3;
decoder->state.tot_insn_cnt = decoder->tot_insn_cnt;
- if (err)
- decoder->state.from_ip = decoder->ip;
-
return &decoder->state;
}
diff --git a/tools/testing/selftests/capabilities/test_execve.c b/tools/testing/selftests/capabilities/test_execve.c
index 10a21a9..763f37f 100644
--- a/tools/testing/selftests/capabilities/test_execve.c
+++ b/tools/testing/selftests/capabilities/test_execve.c
@@ -138,9 +138,6 @@
if (chdir(cwd) != 0)
err(1, "chdir to private tmpfs");
-
- if (umount2(".", MNT_DETACH) != 0)
- err(1, "detach private tmpfs");
}
static void copy_fromat_to(int fromfd, const char *fromname, const char *toname)
@@ -248,7 +245,7 @@
err(1, "chown");
if (chmod("validate_cap_sgidnonroot", S_ISGID | 0710) != 0)
err(1, "chmod");
-}
+ }
capng_get_caps_process();
@@ -384,7 +381,7 @@
} else {
printf("[RUN]\tNon-root +ia, sgidnonroot => i\n");
exec_other_validate_cap("./validate_cap_sgidnonroot",
- false, false, true, false);
+ false, false, true, false);
if (fork_wait()) {
printf("[RUN]\tNon-root +ia, sgidroot => i\n");
diff --git a/virt/kvm/vfio.c b/virt/kvm/vfio.c
index 1dd087d..111e09c 100644
--- a/virt/kvm/vfio.c
+++ b/virt/kvm/vfio.c
@@ -47,6 +47,22 @@
return vfio_group;
}
+static bool kvm_vfio_external_group_match_file(struct vfio_group *group,
+ struct file *filep)
+{
+ bool ret, (*fn)(struct vfio_group *, struct file *);
+
+ fn = symbol_get(vfio_external_group_match_file);
+ if (!fn)
+ return false;
+
+ ret = fn(group, filep);
+
+ symbol_put(vfio_external_group_match_file);
+
+ return ret;
+}
+
static void kvm_vfio_group_put_external_user(struct vfio_group *vfio_group)
{
void (*fn)(struct vfio_group *);
@@ -171,18 +187,13 @@
if (!f.file)
return -EBADF;
- vfio_group = kvm_vfio_group_get_external_user(f.file);
- fdput(f);
-
- if (IS_ERR(vfio_group))
- return PTR_ERR(vfio_group);
-
ret = -ENOENT;
mutex_lock(&kv->lock);
list_for_each_entry(kvg, &kv->group_list, node) {
- if (kvg->vfio_group != vfio_group)
+ if (!kvm_vfio_external_group_match_file(kvg->vfio_group,
+ f.file))
continue;
list_del(&kvg->node);
@@ -196,7 +207,7 @@
mutex_unlock(&kv->lock);
- kvm_vfio_group_put_external_user(vfio_group);
+ fdput(f);
kvm_vfio_update_coherency(dev);