[ALPS04079775] Platform: Kernel-4.14 Migration
[Detail] Code merged from yocto MTK-Commit-Id: 4d1482911601922594964945fb3b831a66b762ae Change-Id: I89df40172a12826b990d4899a227edae1ee9647e CR-Id: ALPS04079775 Feature: [Module]Kernel Maintenance Signed-off-by: season chen <season.chen@mediatek.com> (cherry-pick from 1a3ac023e6ba213a6f43e5ec432763b77579ee63)
This commit is contained in:
@@ -36,24 +36,33 @@ each local arbiter.
|
||||
like display, video decode, and camera. And there are different ports
|
||||
in each larb. Take a example, There are many ports like MC, PP, VLD in the
|
||||
video decode local arbiter, all these ports are according to the video HW.
|
||||
In some Socs, there may be a GALS(Global Async Local Sync) module between
|
||||
smi-common and m4u, and additional GALS module between smi-larb and
|
||||
smi-common. GALS can been seen as a "asynchronous fifo" which could help
|
||||
synchronize for the modules in different clock frequence.
|
||||
|
||||
Required properties:
|
||||
- compatible : must be one of the following string:
|
||||
"mediatek,mt2701-m4u" for mt2701 which uses generation one m4u HW.
|
||||
"mediatek,mt2712-m4u" for mt2712 which uses generation two m4u HW.
|
||||
"mediatek,mt8173-m4u" for mt8173 which uses generation two m4u HW.
|
||||
"mediatek,mt8183-m4u" for mt8183 which uses generation two m4u HW.
|
||||
- reg : m4u register base and size.
|
||||
- interrupts : the interrupt of m4u.
|
||||
- clocks : must contain one entry for each clock-names.
|
||||
- clock-names : must be "bclk", It is the block clock of m4u.
|
||||
- clock-names : Only 1 optional clock:
|
||||
- "bclk": the block clock of m4u.
|
||||
Note that m4u use EMI clock which always has been enabled before kernel if
|
||||
there is no this "bclk", like mt8183.
|
||||
- mediatek,larbs : List of phandle to the local arbiters in the current Socs.
|
||||
Refer to bindings/memory-controllers/mediatek,smi-larb.txt. It must sort
|
||||
according to the local arbiter index, like larb0, larb1, larb2...
|
||||
- iommu-cells : must be 1. This is the mtk_m4u_id according to the HW.
|
||||
Specifies the mtk_m4u_id as defined in
|
||||
dt-binding/memory/mt2701-larb-port.h for mt2701,
|
||||
dt-binding/memory/mt2712-larb-port.h for mt2712, and
|
||||
dt-binding/memory/mt8173-larb-port.h for mt8173.
|
||||
dt-binding/memory/mt2712-larb-port.h for mt2712,
|
||||
dt-binding/memory/mt8173-larb-port.h for mt8173, and
|
||||
dt-binding/memory/mt8183-larb-port.h for mt8183.
|
||||
|
||||
Example:
|
||||
iommu: iommu@10205000 {
|
||||
|
||||
65
Documentation/devicetree/bindings/mailbox/mtk-gce.txt
Normal file
65
Documentation/devicetree/bindings/mailbox/mtk-gce.txt
Normal file
@@ -0,0 +1,65 @@
|
||||
MediaTek GCE
|
||||
===============
|
||||
|
||||
The Global Command Engine (GCE) is used to help read/write registers with
|
||||
critical time limitation, such as updating display configuration during the
|
||||
vblank. The GCE can be used to implement the Command Queue (CMDQ) driver.
|
||||
|
||||
CMDQ driver uses mailbox framework for communication. Please refer to
|
||||
mailbox.txt for generic information about mailbox device-tree bindings.
|
||||
|
||||
Required properties:
|
||||
- compatible: Must be "mediatek,mt8173-gce"
|
||||
- reg: Address range of the GCE unit
|
||||
- interrupts: The interrupt signal from the GCE block
|
||||
- clock: Clocks according to the common clock binding
|
||||
- clock-names: Must be "gce" to stand for GCE clock
|
||||
- thread-num: Maximum threads count of GCE.
|
||||
- #mbox-cells: Should be 4.
|
||||
<&phandle channel timeout priority atomic_exec>
|
||||
phandle: Label name of a gce node.
|
||||
channel: Channel of mailbox. Be equal to the thread id of GCE.
|
||||
timeout: Maximum time of software waiting GCE processing done, in unit
|
||||
of millisecond.
|
||||
priority: Priority of GCE thread.
|
||||
atomic_exec: GCE processing continuous packets of commands in atomic
|
||||
way.
|
||||
|
||||
Required properties for a client device:
|
||||
- mboxes: Client use mailbox to communicate with GCE, it should have this
|
||||
property and list of phandle, mailbox specifiers.
|
||||
- gce-subsys: Specify the sub-system id which is corresponding to the register
|
||||
address.
|
||||
|
||||
Optional properties for a client device:
|
||||
- gce-event: Specify the event if the client has any. Because the event is
|
||||
parsed by client, so client can replace 'gce-event' with other meaningful
|
||||
name.
|
||||
|
||||
Some vaules of properties are defined in 'dt-bindings/gce/mt8173-gce.h'. Such as
|
||||
thread number, sub-system ids, thread priority, event ids.
|
||||
|
||||
Example:
|
||||
|
||||
gce: gce@10212000 {
|
||||
compatible = "mediatek,mt8173-gce";
|
||||
reg = <0 0x10212000 0 0x1000>;
|
||||
interrupts = <GIC_SPI 135 IRQ_TYPE_LEVEL_LOW>;
|
||||
clocks = <&infracfg CLK_INFRA_GCE>;
|
||||
clock-names = "gce";
|
||||
thread-num = CMDQ_THR_MAX_COUNT;
|
||||
#mbox-cells = <4>;
|
||||
};
|
||||
|
||||
Example for a client device:
|
||||
|
||||
mmsys: clock-controller@14000000 {
|
||||
compatible = "mediatek,mt8173-mmsys";
|
||||
mboxes = <&gce 0 2000 CMDQ_THR_PRIO_LOWEST 1>,
|
||||
<&gce 1 2000 CMDQ_THR_PRIO_LOWEST 1>;
|
||||
gce-subsys = <SUBSYS_1400XXXX>;
|
||||
mutex-event-eof = <CMDQ_EVENT_MUTEX0_STREAM_EOF
|
||||
CMDQ_EVENT_MUTEX1_STREAM_EOF>;
|
||||
|
||||
...
|
||||
};
|
||||
@@ -2,9 +2,10 @@ SMI (Smart Multimedia Interface) Common
|
||||
|
||||
The hardware block diagram please check bindings/iommu/mediatek,iommu.txt
|
||||
|
||||
Mediatek SMI have two generations of HW architecture, mt2712 and mt8173 use
|
||||
the second generation of SMI HW while mt2701 uses the first generation HW of
|
||||
SMI.
|
||||
Mediatek SMI have two generations of HW architecture, here is the list
|
||||
which generation the Socs use:
|
||||
generation 1: mt2701.
|
||||
generation 2: mt2712, mt8173 and mt8183.
|
||||
|
||||
There's slight differences between the two SMI, for generation 2, the
|
||||
register which control the iommu port is at each larb's register base. But
|
||||
@@ -18,6 +19,7 @@ Required properties:
|
||||
"mediatek,mt2701-smi-common"
|
||||
"mediatek,mt2712-smi-common"
|
||||
"mediatek,mt8173-smi-common"
|
||||
"mediatek,mt8183-smi-common"
|
||||
- reg : the register and size of the SMI block.
|
||||
- power-domains : a phandle to the power domain of this local arbiter.
|
||||
- clocks : Must contain an entry for each entry in clock-names.
|
||||
@@ -29,6 +31,11 @@ Required properties:
|
||||
They may be the same if both source clocks are the same.
|
||||
- "async" : asynchronous clock, it help transform the smi clock into the emi
|
||||
clock domain, this clock is only needed by generation 1 smi HW.
|
||||
and these 2 option clocks for generation 2 smi HW:
|
||||
- "gals0": the path0 clock of GALS(Global Async Local Sync).
|
||||
- "gals1": the path1 clock of GALS(Global Async Local Sync).
|
||||
Note that "gals0" and "gals1" clock only exist while the SMI HW has "GALS"
|
||||
modules.
|
||||
|
||||
Example:
|
||||
smi_common: smi@14022000 {
|
||||
|
||||
@@ -7,6 +7,7 @@ Required properties:
|
||||
"mediatek,mt2701-smi-larb"
|
||||
"mediatek,mt2712-smi-larb"
|
||||
"mediatek,mt8173-smi-larb"
|
||||
"mediatek,mt8183-smi-larb"
|
||||
- reg : the register and size of this local arbiter.
|
||||
- mediatek,smi : a phandle to the smi_common node.
|
||||
- power-domains : a phandle to the power domain of this local arbiter.
|
||||
@@ -15,6 +16,8 @@ Required properties:
|
||||
- "apb" : Advanced Peripheral Bus clock, It's the clock for setting
|
||||
the register.
|
||||
- "smi" : It's the clock for transfer data and command.
|
||||
and this optional clock name:
|
||||
- "gals": the clock for gals(Global Async Local Sync).
|
||||
|
||||
Required property for mt2701 and mt2712:
|
||||
- mediatek,larb-id :the hardware id of this larb.
|
||||
|
||||
@@ -14,6 +14,7 @@ Required properties:
|
||||
"mediatek,mt2712-mmc": for mmc host ip compatible with mt2712
|
||||
"mediatek,mt7622-mmc": for MT7622 SoC
|
||||
"mediatek,mt7623-mmc", "mediatek,mt2701-mmc": for MT7623 SoC
|
||||
"mediatek,mt8183-mmc": for mmc host ip compatible with mt8183
|
||||
|
||||
- reg: physical base address of the controller and length
|
||||
- interrupts: Should contain MSDC interrupt number
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
dtb-$(CONFIG_ARCH_MEDIATEK) += aiv8183m1v2.dtb
|
||||
dtb-$(CONFIG_ARCH_MEDIATEK) += aiv8183m1v2-clkitg.dtb
|
||||
dtb-$(CONFIG_ARCH_MEDIATEK) += mt2712-evb.dtb
|
||||
dtb-$(CONFIG_ARCH_MEDIATEK) += mt6755-evb.dtb
|
||||
dtb-$(CONFIG_ARCH_MEDIATEK) += mt6795-evb.dtb
|
||||
dtb-$(CONFIG_ARCH_MEDIATEK) += mt6797-evb.dtb
|
||||
dtb-$(CONFIG_ARCH_MEDIATEK) += mt7622-rfb1.dtb
|
||||
dtb-$(CONFIG_ARCH_MEDIATEK) += mt8173-evb.dtb
|
||||
dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-clkitg.dtb
|
||||
dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-evb.dtb
|
||||
|
||||
ifeq ($(strip $(CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE)), y)
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <dt-bindings/phy/phy.h>
|
||||
#include <dt-bindings/power/mt8173-power.h>
|
||||
#include <dt-bindings/reset/mt8173-resets.h>
|
||||
#include <dt-bindings/gce/mt8173-gce.h>
|
||||
#include "mt8173-pinfunc.h"
|
||||
|
||||
/ {
|
||||
@@ -429,6 +430,16 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
gce: gce@10212000 {
|
||||
compatible = "mediatek,mt8173-gce";
|
||||
reg = <0 0x10212000 0 0x1000>;
|
||||
interrupts = <GIC_SPI 135 IRQ_TYPE_LEVEL_LOW>;
|
||||
clocks = <&infracfg CLK_INFRA_GCE>;
|
||||
clock-names = "gce";
|
||||
thread-num = <CMDQ_THR_MAX_COUNT>;
|
||||
#mbox-cells = <4>;
|
||||
};
|
||||
|
||||
mipi_tx0: mipi-dphy@10215000 {
|
||||
compatible = "mediatek,mt8173-mipi-tx";
|
||||
reg = <0 0x10215000 0 0x1000>;
|
||||
|
||||
@@ -1688,6 +1688,11 @@ static struct pdev_drv pderv[] = {
|
||||
PDEV_DRV("clkdbg-pd8"),
|
||||
PDEV_DRV("clkdbg-pd9"),
|
||||
PDEV_DRV("clkdbg-pd10"),
|
||||
PDEV_DRV("clkdbg-pd11"),
|
||||
PDEV_DRV("clkdbg-pd12"),
|
||||
PDEV_DRV("clkdbg-pd13"),
|
||||
PDEV_DRV("clkdbg-pd14"),
|
||||
PDEV_DRV("clkdbg-pd15"),
|
||||
};
|
||||
|
||||
static void reg_pdev_drv(const char *pdname, struct seq_file *s)
|
||||
|
||||
@@ -13,6 +13,8 @@ mediatek-drm-y := mtk_disp_color.o \
|
||||
mtk_mipi_tx.o \
|
||||
mtk_dpi.o
|
||||
|
||||
mediatek-drm-$(CONFIG_DRM_FBDEV_EMULATION) += mtk_drm_fbdev.o
|
||||
|
||||
obj-$(CONFIG_DRM_MEDIATEK) += mediatek-drm.o
|
||||
|
||||
mediatek-drm-hdmi-objs := mtk_cec.o \
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "mtk_drm_ddp_comp.h"
|
||||
#include "mtk_drm_drv.h"
|
||||
#include "mtk_drm_fb.h"
|
||||
#include "mtk_drm_fbdev.h"
|
||||
#include "mtk_drm_gem.h"
|
||||
|
||||
#define DRIVER_NAME "mediatek"
|
||||
@@ -127,10 +128,20 @@ static int mtk_atomic_commit(struct drm_device *drm,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mtk_drm_mode_output_poll_changed(struct drm_device *dev)
|
||||
{
|
||||
struct mtk_drm_private *priv = dev->dev_private;
|
||||
struct drm_fb_helper *fb_helper = &priv->fb_helper;
|
||||
|
||||
if (fb_helper)
|
||||
drm_fb_helper_hotplug_event(fb_helper);
|
||||
}
|
||||
|
||||
static const struct drm_mode_config_funcs mtk_drm_mode_config_funcs = {
|
||||
.fb_create = mtk_drm_mode_fb_create,
|
||||
.atomic_check = drm_atomic_helper_check,
|
||||
.atomic_commit = mtk_atomic_commit,
|
||||
.output_poll_changed = mtk_drm_mode_output_poll_changed,
|
||||
};
|
||||
|
||||
static const enum mtk_ddp_comp_id mt2701_mtk_ddp_main[] = {
|
||||
@@ -257,8 +268,14 @@ static int mtk_drm_kms_init(struct drm_device *drm)
|
||||
drm_kms_helper_poll_init(drm);
|
||||
drm_mode_config_reset(drm);
|
||||
|
||||
ret = mtk_fbdev_init(drm);
|
||||
if (ret)
|
||||
goto err_kms_helper_poll_fini;
|
||||
|
||||
return 0;
|
||||
|
||||
err_kms_helper_poll_fini:
|
||||
drm_kms_helper_poll_fini(drm);
|
||||
err_component_unbind:
|
||||
component_unbind_all(drm->dev, drm);
|
||||
err_config_cleanup:
|
||||
@@ -269,6 +286,7 @@ err_config_cleanup:
|
||||
|
||||
static void mtk_drm_kms_deinit(struct drm_device *drm)
|
||||
{
|
||||
mtk_fbdev_fini(drm);
|
||||
drm_kms_helper_poll_fini(drm);
|
||||
|
||||
component_unbind_all(drm->dev, drm);
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#ifndef MTK_DRM_DRV_H
|
||||
#define MTK_DRM_DRV_H
|
||||
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <linux/io.h>
|
||||
#include "mtk_drm_ddp_comp.h"
|
||||
|
||||
@@ -24,7 +25,6 @@ struct device;
|
||||
struct device_node;
|
||||
struct drm_crtc;
|
||||
struct drm_device;
|
||||
struct drm_fb_helper;
|
||||
struct drm_property;
|
||||
struct regmap;
|
||||
|
||||
@@ -56,6 +56,8 @@ struct mtk_drm_private {
|
||||
} commit;
|
||||
|
||||
struct drm_atomic_state *suspend_state;
|
||||
struct drm_fb_helper fb_helper;
|
||||
struct drm_gem_object *fbdev_bo;
|
||||
};
|
||||
|
||||
extern struct platform_driver mtk_ddp_driver;
|
||||
|
||||
@@ -96,6 +96,19 @@ static struct mtk_drm_fb *mtk_drm_framebuffer_init(struct drm_device *dev,
|
||||
return mtk_fb;
|
||||
}
|
||||
|
||||
struct drm_framebuffer *mtk_drm_framebuffer_create(struct drm_device *dev,
|
||||
const struct drm_mode_fb_cmd2 *mode,
|
||||
struct drm_gem_object *obj)
|
||||
{
|
||||
struct mtk_drm_fb *mtk_fb;
|
||||
|
||||
mtk_fb = mtk_drm_framebuffer_init(dev, mode, obj);
|
||||
if (IS_ERR(mtk_fb))
|
||||
return ERR_CAST(mtk_fb);
|
||||
|
||||
return &mtk_fb->base;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait for any exclusive fence in fb's gem object's reservation object.
|
||||
*
|
||||
|
||||
@@ -19,5 +19,8 @@ int mtk_fb_wait(struct drm_framebuffer *fb);
|
||||
struct drm_framebuffer *mtk_drm_mode_fb_create(struct drm_device *dev,
|
||||
struct drm_file *file,
|
||||
const struct drm_mode_fb_cmd2 *cmd);
|
||||
struct drm_framebuffer *mtk_drm_framebuffer_create(struct drm_device *dev,
|
||||
const struct drm_mode_fb_cmd2 *mode,
|
||||
struct drm_gem_object *obj);
|
||||
|
||||
#endif /* MTK_DRM_FB_H */
|
||||
|
||||
183
drivers/gpu/drm/mediatek/mtk_drm_fbdev.c
Normal file
183
drivers/gpu/drm/mediatek/mtk_drm_fbdev.c
Normal file
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright (c) 2016 MediaTek Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_gem.h>
|
||||
|
||||
#include "mtk_drm_drv.h"
|
||||
#include "mtk_drm_fb.h"
|
||||
#include "mtk_drm_gem.h"
|
||||
|
||||
#define to_drm_private(x) \
|
||||
container_of(x, struct mtk_drm_private, fb_helper)
|
||||
|
||||
static int mtk_drm_fbdev_mmap(struct fb_info *info, struct vm_area_struct *vma)
|
||||
{
|
||||
struct drm_fb_helper *helper = info->par;
|
||||
struct mtk_drm_private *private = to_drm_private(helper);
|
||||
|
||||
return mtk_drm_gem_mmap_buf(private->fbdev_bo, vma);
|
||||
}
|
||||
|
||||
static struct fb_ops mtk_fbdev_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.fb_fillrect = drm_fb_helper_cfb_fillrect,
|
||||
.fb_copyarea = drm_fb_helper_cfb_copyarea,
|
||||
.fb_imageblit = drm_fb_helper_cfb_imageblit,
|
||||
.fb_check_var = drm_fb_helper_check_var,
|
||||
.fb_set_par = drm_fb_helper_set_par,
|
||||
.fb_blank = drm_fb_helper_blank,
|
||||
.fb_pan_display = drm_fb_helper_pan_display,
|
||||
.fb_setcmap = drm_fb_helper_setcmap,
|
||||
.fb_mmap = mtk_drm_fbdev_mmap,
|
||||
};
|
||||
|
||||
static int mtk_fbdev_probe(struct drm_fb_helper *helper,
|
||||
struct drm_fb_helper_surface_size *sizes)
|
||||
{
|
||||
struct drm_device *dev = helper->dev;
|
||||
struct mtk_drm_private *private = to_drm_private(helper);
|
||||
struct drm_mode_fb_cmd2 mode = { 0 };
|
||||
struct mtk_drm_gem_obj *mtk_gem;
|
||||
struct fb_info *info;
|
||||
struct drm_framebuffer *fb;
|
||||
unsigned int bytes_per_pixel;
|
||||
unsigned long offset;
|
||||
size_t size;
|
||||
int err;
|
||||
|
||||
bytes_per_pixel = DIV_ROUND_UP(sizes->surface_bpp, 8);
|
||||
|
||||
mode.width = sizes->surface_width;
|
||||
mode.height = sizes->surface_height;
|
||||
mode.pitches[0] = sizes->surface_width * bytes_per_pixel;
|
||||
mode.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
|
||||
sizes->surface_depth);
|
||||
|
||||
size = mode.pitches[0] * mode.height;
|
||||
|
||||
mtk_gem = mtk_drm_gem_create(dev, size, true);
|
||||
if (IS_ERR(mtk_gem))
|
||||
return PTR_ERR(mtk_gem);
|
||||
|
||||
private->fbdev_bo = &mtk_gem->base;
|
||||
|
||||
info = drm_fb_helper_alloc_fbi(helper);
|
||||
if (IS_ERR(info)) {
|
||||
err = PTR_ERR(info);
|
||||
dev_err(dev->dev, "failed to allocate framebuffer info, %d\n",
|
||||
err);
|
||||
goto err_gem_free_object;
|
||||
}
|
||||
|
||||
fb = mtk_drm_framebuffer_create(dev, &mode, private->fbdev_bo);
|
||||
if (IS_ERR(fb)) {
|
||||
err = PTR_ERR(fb);
|
||||
dev_err(dev->dev, "failed to allocate DRM framebuffer, %d\n",
|
||||
err);
|
||||
goto err_release_fbi;
|
||||
}
|
||||
helper->fb = fb;
|
||||
|
||||
info->par = helper;
|
||||
info->flags = FBINFO_FLAG_DEFAULT;
|
||||
info->fbops = &mtk_fbdev_ops;
|
||||
|
||||
drm_fb_helper_fill_fix(info, fb->pitches[0], fb->format->depth);
|
||||
drm_fb_helper_fill_var(info, helper, sizes->fb_width, sizes->fb_height);
|
||||
|
||||
offset = info->var.xoffset * bytes_per_pixel;
|
||||
offset += info->var.yoffset * fb->pitches[0];
|
||||
|
||||
dev->mode_config.fb_base = 0;
|
||||
info->screen_base = mtk_gem->kvaddr + offset;
|
||||
info->screen_size = size;
|
||||
info->fix.smem_len = size;
|
||||
|
||||
DRM_DEBUG_KMS("FB [%ux%u]-%u offset=%lu size=%zd\n",
|
||||
fb->width, fb->height, fb->format->depth, offset, size);
|
||||
|
||||
info->skip_vt_switch = true;
|
||||
|
||||
return 0;
|
||||
|
||||
err_release_fbi:
|
||||
err_gem_free_object:
|
||||
mtk_drm_gem_free_object(&mtk_gem->base);
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct drm_fb_helper_funcs mtk_drm_fb_helper_funcs = {
|
||||
.fb_probe = mtk_fbdev_probe,
|
||||
};
|
||||
|
||||
int mtk_fbdev_init(struct drm_device *dev)
|
||||
{
|
||||
struct mtk_drm_private *priv = dev->dev_private;
|
||||
struct drm_fb_helper *helper = &priv->fb_helper;
|
||||
int ret;
|
||||
|
||||
if (!dev->mode_config.num_crtc || !dev->mode_config.num_connector)
|
||||
return -EINVAL;
|
||||
|
||||
drm_fb_helper_prepare(dev, helper, &mtk_drm_fb_helper_funcs);
|
||||
|
||||
ret = drm_fb_helper_init(dev, helper,
|
||||
dev->mode_config.num_connector);
|
||||
if (ret) {
|
||||
dev_err(dev->dev, "failed to initialize DRM FB helper, %d\n",
|
||||
ret);
|
||||
goto fini;
|
||||
}
|
||||
|
||||
ret = drm_fb_helper_single_add_all_connectors(helper);
|
||||
if (ret) {
|
||||
dev_err(dev->dev, "failed to add connectors, %d\n", ret);
|
||||
goto fini;
|
||||
}
|
||||
|
||||
/* disable all the possible outputs/crtcs before entering KMS mode */
|
||||
if (!drm_drv_uses_atomic_modeset(dev))
|
||||
drm_helper_disable_unused_functions(dev);
|
||||
|
||||
ret = drm_fb_helper_initial_config(helper, 32);
|
||||
if (ret) {
|
||||
dev_err(dev->dev, "failed to set initial configuration, %d\n",
|
||||
ret);
|
||||
goto fini;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fini:
|
||||
drm_fb_helper_fini(helper);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void mtk_fbdev_fini(struct drm_device *dev)
|
||||
{
|
||||
struct mtk_drm_private *priv = dev->dev_private;
|
||||
struct drm_fb_helper *helper = &priv->fb_helper;
|
||||
|
||||
drm_fb_helper_unregister_fbi(helper);
|
||||
|
||||
if (helper->fb) {
|
||||
drm_framebuffer_unregister_private(helper->fb);
|
||||
drm_framebuffer_remove(helper->fb);
|
||||
}
|
||||
|
||||
drm_fb_helper_fini(helper);
|
||||
}
|
||||
32
drivers/gpu/drm/mediatek/mtk_drm_fbdev.h
Normal file
32
drivers/gpu/drm/mediatek/mtk_drm_fbdev.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2016 MediaTek Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef MTK_DRM_FBDEV_H
|
||||
#define MTK_DRM_FBDEV_H
|
||||
|
||||
#ifdef CONFIG_DRM_FBDEV_EMULATION
|
||||
int mtk_fbdev_init(struct drm_device *dev);
|
||||
void mtk_fbdev_fini(struct drm_device *dev);
|
||||
#else
|
||||
int mtk_fbdev_init(struct drm_device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mtk_fbdev_fini(struct drm_device *dev)
|
||||
{
|
||||
|
||||
}
|
||||
#endif /* CONFIG_DRM_FBDEV_EMULATION */
|
||||
|
||||
#endif /* MTK_DRM_FBDEV_H */
|
||||
@@ -124,7 +124,9 @@
|
||||
#define ARM_V7S_TEX_MASK 0x7
|
||||
#define ARM_V7S_ATTR_TEX(val) (((val) & ARM_V7S_TEX_MASK) << ARM_V7S_TEX_SHIFT)
|
||||
|
||||
#define ARM_V7S_ATTR_MTK_4GB BIT(9) /* MTK extend it for 4GB mode */
|
||||
/* MTK extend the two bits below for over 4GB mode */
|
||||
#define ARM_V7S_ATTR_MTK_PA_BIT32 BIT(9)
|
||||
#define ARM_V7S_ATTR_MTK_PA_BIT33 BIT(4)
|
||||
|
||||
/* *well, except for TEX on level 2 large pages, of course :( */
|
||||
#define ARM_V7S_CONT_PAGE_TEX_SHIFT 6
|
||||
@@ -263,7 +265,8 @@ static void __arm_v7s_set_pte(arm_v7s_iopte *ptep, arm_v7s_iopte pte,
|
||||
}
|
||||
|
||||
static arm_v7s_iopte arm_v7s_prot_to_pte(int prot, int lvl,
|
||||
struct io_pgtable_cfg *cfg)
|
||||
struct io_pgtable_cfg *cfg,
|
||||
phys_addr_t paddr) /* Only for MTK */
|
||||
{
|
||||
bool ap = !(cfg->quirks & IO_PGTABLE_QUIRK_NO_PERMS);
|
||||
arm_v7s_iopte pte = ARM_V7S_ATTR_NG | ARM_V7S_ATTR_S;
|
||||
@@ -290,8 +293,12 @@ static arm_v7s_iopte arm_v7s_prot_to_pte(int prot, int lvl,
|
||||
if (lvl == 1 && (cfg->quirks & IO_PGTABLE_QUIRK_ARM_NS))
|
||||
pte |= ARM_V7S_ATTR_NS_SECTION;
|
||||
|
||||
if (cfg->quirks & IO_PGTABLE_QUIRK_ARM_MTK_4GB)
|
||||
pte |= ARM_V7S_ATTR_MTK_4GB;
|
||||
if (cfg->quirks & IO_PGTABLE_QUIRK_ARM_MTK_4GB) {
|
||||
if (paddr & BIT_ULL(32))
|
||||
pte |= ARM_V7S_ATTR_MTK_PA_BIT32;
|
||||
if (paddr & BIT_ULL(33))
|
||||
pte |= ARM_V7S_ATTR_MTK_PA_BIT33;
|
||||
}
|
||||
|
||||
return pte;
|
||||
}
|
||||
@@ -387,7 +394,7 @@ static int arm_v7s_init_pte(struct arm_v7s_io_pgtable *data,
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
pte = arm_v7s_prot_to_pte(prot, lvl, cfg);
|
||||
pte = arm_v7s_prot_to_pte(prot, lvl, cfg, paddr);
|
||||
if (num_entries > 1)
|
||||
pte = arm_v7s_pte_to_cont(pte, lvl);
|
||||
|
||||
@@ -479,7 +486,11 @@ static int arm_v7s_map(struct io_pgtable_ops *ops, unsigned long iova,
|
||||
if (!(prot & (IOMMU_READ | IOMMU_WRITE)))
|
||||
return 0;
|
||||
|
||||
if (WARN_ON(upper_32_bits(iova) || upper_32_bits(paddr)))
|
||||
if (WARN_ON(upper_32_bits(iova)))
|
||||
return -ERANGE;
|
||||
|
||||
if (WARN_ON(upper_32_bits(paddr) &&
|
||||
!(iop->cfg.quirks & IO_PGTABLE_QUIRK_ARM_MTK_4GB)))
|
||||
return -ERANGE;
|
||||
|
||||
ret = __arm_v7s_map(data, iova, paddr, size, prot, 1, data->pgd);
|
||||
@@ -557,7 +568,7 @@ static int arm_v7s_split_blk_unmap(struct arm_v7s_io_pgtable *data,
|
||||
num_entries = size >> ARM_V7S_LVL_SHIFT(2);
|
||||
unmap_idx = ARM_V7S_LVL_IDX(iova, 2);
|
||||
|
||||
pte = arm_v7s_prot_to_pte(arm_v7s_pte_to_prot(blk_pte, 1), 2, cfg);
|
||||
pte = arm_v7s_prot_to_pte(arm_v7s_pte_to_prot(blk_pte, 1), 2, cfg, 0);
|
||||
if (num_entries > 1)
|
||||
pte = arm_v7s_pte_to_cont(pte, 2);
|
||||
|
||||
@@ -671,7 +682,9 @@ static phys_addr_t arm_v7s_iova_to_phys(struct io_pgtable_ops *ops,
|
||||
unsigned long iova)
|
||||
{
|
||||
struct arm_v7s_io_pgtable *data = io_pgtable_ops_to_data(ops);
|
||||
struct io_pgtable_cfg *cfg = &data->iop.cfg;
|
||||
arm_v7s_iopte *ptep = data->pgd, pte;
|
||||
phys_addr_t paddr;
|
||||
int lvl = 0;
|
||||
u32 mask;
|
||||
|
||||
@@ -687,7 +700,16 @@ static phys_addr_t arm_v7s_iova_to_phys(struct io_pgtable_ops *ops,
|
||||
mask = ARM_V7S_LVL_MASK(lvl);
|
||||
if (arm_v7s_pte_is_cont(pte, lvl))
|
||||
mask *= ARM_V7S_CONT_PAGES;
|
||||
return (pte & mask) | (iova & ~mask);
|
||||
paddr = (pte & mask) | (iova & ~mask);
|
||||
|
||||
if (IS_ENABLED(CONFIG_PHYS_ADDR_T_64BIT) &&
|
||||
cfg->quirks & IO_PGTABLE_QUIRK_ARM_MTK_4GB) {
|
||||
if (pte & ARM_V7S_ATTR_MTK_PA_BIT32)
|
||||
paddr |= BIT_ULL(32);
|
||||
if (pte & ARM_V7S_ATTR_MTK_PA_BIT33)
|
||||
paddr |= BIT_ULL(33);
|
||||
}
|
||||
return paddr;
|
||||
}
|
||||
|
||||
static struct io_pgtable *arm_v7s_alloc_pgtable(struct io_pgtable_cfg *cfg,
|
||||
|
||||
@@ -62,10 +62,10 @@ struct io_pgtable_cfg {
|
||||
* (unmapped) entries but the hardware might do so anyway, perform
|
||||
* TLB maintenance when mapping as well as when unmapping.
|
||||
*
|
||||
* IO_PGTABLE_QUIRK_ARM_MTK_4GB: (ARM v7s format) Set bit 9 in all
|
||||
* PTEs, for Mediatek IOMMUs which treat it as a 33rd address bit
|
||||
* when the SoC is in "4GB mode" and they can only access the high
|
||||
* remap of DRAM (0x1_00000000 to 0x1_ffffffff).
|
||||
* IO_PGTABLE_QUIRK_ARM_MTK_4GB: (ARM v7s format) Set bit 4 and 9 in all
|
||||
* PTEs, for Mediatek IOMMUs which treat it as the 33rd and 32rd
|
||||
* address bit when the SoC dram is over 4GB and they can access
|
||||
* the physical address from 0x4000_0000 to 0x3_ffff_ffff.
|
||||
*
|
||||
* IO_PGTABLE_QUIRK_NO_DMA: Guarantees that the tables will only ever
|
||||
* be accessed by a fully cache-coherent IOMMU or CPU (e.g. for a
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "mtk_iommu.h"
|
||||
|
||||
#define REG_MMU_PT_BASE_ADDR 0x000
|
||||
#define MMU_PT_ADDR_MASK GENMASK(31, 7)
|
||||
|
||||
#define REG_MMU_INVALIDATE 0x020
|
||||
#define F_ALL_INVLD 0x2
|
||||
@@ -54,7 +55,7 @@
|
||||
#define REG_MMU_CTRL_REG 0x110
|
||||
#define F_MMU_PREFETCH_RT_REPLACE_MOD BIT(4)
|
||||
#define F_MMU_TF_PROTECT_SEL_SHIFT(data) \
|
||||
((data)->m4u_plat == M4U_MT2712 ? 4 : 5)
|
||||
((data)->plat_data->m4u_plat == M4U_MT8173 ? 5 : 4)
|
||||
/* It's named by F_MMU_TF_PROT_SEL in mt2712. */
|
||||
#define F_MMU_TF_PROTECT_SEL(prot, data) \
|
||||
(((prot) & 0x3) << F_MMU_TF_PROTECT_SEL_SHIFT(data))
|
||||
@@ -73,27 +74,32 @@
|
||||
#define F_MISS_FIFO_ERR_INT_EN BIT(6)
|
||||
#define F_INT_CLR_BIT BIT(12)
|
||||
|
||||
#define REG_MMU_INT_MAIN_CONTROL 0x124
|
||||
#define F_INT_TRANSLATION_FAULT BIT(0)
|
||||
#define F_INT_MAIN_MULTI_HIT_FAULT BIT(1)
|
||||
#define F_INT_INVALID_PA_FAULT BIT(2)
|
||||
#define F_INT_ENTRY_REPLACEMENT_FAULT BIT(3)
|
||||
#define F_INT_TLB_MISS_FAULT BIT(4)
|
||||
#define F_INT_MISS_TRANSACTION_FIFO_FAULT BIT(5)
|
||||
#define F_INT_PRETETCH_TRANSATION_FIFO_FAULT BIT(6)
|
||||
#define REG_MMU_INT_MAIN_CONTROL 0x124 /* mmu0 | mmu1 */
|
||||
#define F_INT_TRANSLATION_FAULT (BIT(0) | BIT(7))
|
||||
#define F_INT_MAIN_MULTI_HIT_FAULT (BIT(1) | BIT(8))
|
||||
#define F_INT_INVALID_PA_FAULT (BIT(2) | BIT(9))
|
||||
#define F_INT_ENTRY_REPLACEMENT_FAULT (BIT(3) | BIT(10))
|
||||
#define F_INT_TLB_MISS_FAULT (BIT(4) | BIT(11))
|
||||
#define F_INT_MISS_TRANSACTION_FIFO_FAULT (BIT(5) | BIT(12))
|
||||
#define F_INT_PRETETCH_TRANSATION_FIFO_FAULT (BIT(6) | BIT(13))
|
||||
|
||||
#define REG_MMU_CPE_DONE 0x12C
|
||||
|
||||
#define REG_MMU_FAULT_ST1 0x134
|
||||
#define F_REG_MMU0_FAULT_MASK GENMASK(6, 0)
|
||||
#define F_REG_MMU1_FAULT_MASK GENMASK(13, 7)
|
||||
|
||||
#define REG_MMU_FAULT_VA 0x13c
|
||||
#define REG_MMU0_FAULT_VA 0x13c
|
||||
#define F_MMU_FAULT_VA_WRITE_BIT BIT(1)
|
||||
#define F_MMU_FAULT_VA_LAYER_BIT BIT(0)
|
||||
|
||||
#define REG_MMU_INVLD_PA 0x140
|
||||
#define REG_MMU_INT_ID 0x150
|
||||
#define F_MMU0_INT_ID_LARB_ID(a) (((a) >> 7) & 0x7)
|
||||
#define F_MMU0_INT_ID_PORT_ID(a) (((a) >> 2) & 0x1f)
|
||||
#define REG_MMU0_INVLD_PA 0x140
|
||||
#define REG_MMU1_FAULT_VA 0x144
|
||||
#define REG_MMU1_INVLD_PA 0x148
|
||||
#define REG_MMU0_INT_ID 0x150
|
||||
#define REG_MMU1_INT_ID 0x154
|
||||
#define F_MMU_INT_ID_LARB_ID(a) (((a) >> 7) & 0x7)
|
||||
#define F_MMU_INT_ID_PORT_ID(a) (((a) >> 2) & 0x1f)
|
||||
|
||||
#define MTK_PROTECT_PA_ALIGN 128
|
||||
|
||||
@@ -202,6 +208,17 @@ static const struct iommu_gather_ops mtk_iommu_gather_ops = {
|
||||
.tlb_sync = mtk_iommu_tlb_sync,
|
||||
};
|
||||
|
||||
static unsigned int mtk_iommu_get_larbid(const unsigned int *larbid_in_common,
|
||||
const unsigned int fault_larb)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MTK_LARB_NR_MAX; i++)
|
||||
if (larbid_in_common[i] == fault_larb)
|
||||
return i;
|
||||
return MTK_LARB_NR_MAX; /* Invalid larb id. */
|
||||
}
|
||||
|
||||
static irqreturn_t mtk_iommu_isr(int irq, void *dev_id)
|
||||
{
|
||||
struct mtk_iommu_data *data = dev_id;
|
||||
@@ -212,14 +229,24 @@ static irqreturn_t mtk_iommu_isr(int irq, void *dev_id)
|
||||
|
||||
/* Read error info from registers */
|
||||
int_state = readl_relaxed(data->base + REG_MMU_FAULT_ST1);
|
||||
fault_iova = readl_relaxed(data->base + REG_MMU_FAULT_VA);
|
||||
if (int_state & F_REG_MMU0_FAULT_MASK) {
|
||||
regval = readl_relaxed(data->base + REG_MMU0_INT_ID);
|
||||
fault_iova = readl_relaxed(data->base + REG_MMU0_FAULT_VA);
|
||||
fault_pa = readl_relaxed(data->base + REG_MMU0_INVLD_PA);
|
||||
} else {
|
||||
regval = readl_relaxed(data->base + REG_MMU1_INT_ID);
|
||||
fault_iova = readl_relaxed(data->base + REG_MMU1_FAULT_VA);
|
||||
fault_pa = readl_relaxed(data->base + REG_MMU1_INVLD_PA);
|
||||
}
|
||||
layer = fault_iova & F_MMU_FAULT_VA_LAYER_BIT;
|
||||
write = fault_iova & F_MMU_FAULT_VA_WRITE_BIT;
|
||||
fault_pa = readl_relaxed(data->base + REG_MMU_INVLD_PA);
|
||||
regval = readl_relaxed(data->base + REG_MMU_INT_ID);
|
||||
fault_larb = F_MMU0_INT_ID_LARB_ID(regval);
|
||||
fault_port = F_MMU0_INT_ID_PORT_ID(regval);
|
||||
fault_larb = F_MMU_INT_ID_LARB_ID(regval);
|
||||
fault_port = F_MMU_INT_ID_PORT_ID(regval);
|
||||
|
||||
if (data->plat_data->larbid_remap_enable)
|
||||
fault_larb = mtk_iommu_get_larbid(
|
||||
data->plat_data->larbid_in_common,
|
||||
fault_larb);
|
||||
if (report_iommu_fault(&dom->domain, data->dev, fault_iova,
|
||||
write ? IOMMU_FAULT_WRITE : IOMMU_FAULT_READ)) {
|
||||
dev_err_ratelimited(
|
||||
@@ -344,7 +371,7 @@ static int mtk_iommu_attach_device(struct iommu_domain *domain,
|
||||
/* Update the pgtable base address register of the M4U HW */
|
||||
if (!data->m4u_dom) {
|
||||
data->m4u_dom = dom;
|
||||
writel(dom->cfg.arm_v7s_cfg.ttbr[0],
|
||||
writel(dom->cfg.arm_v7s_cfg.ttbr[0] & MMU_PT_ADDR_MASK,
|
||||
data->base + REG_MMU_PT_BASE_ADDR);
|
||||
}
|
||||
|
||||
@@ -367,12 +394,17 @@ static int mtk_iommu_map(struct iommu_domain *domain, unsigned long iova,
|
||||
phys_addr_t paddr, size_t size, int prot)
|
||||
{
|
||||
struct mtk_iommu_domain *dom = to_mtk_domain(domain);
|
||||
struct mtk_iommu_data *data = mtk_iommu_get_m4u_data();
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
if (IS_ENABLED(CONFIG_PHYS_ADDR_T_64BIT) &&
|
||||
data->plat_data->has_4gb_mode &&
|
||||
data->enable_4GB)
|
||||
paddr |= BIT_ULL(32);
|
||||
|
||||
spin_lock_irqsave(&dom->pgtlock, flags);
|
||||
ret = dom->iop->map(dom->iop, iova, paddr & DMA_BIT_MASK(32),
|
||||
size, prot);
|
||||
ret = dom->iop->map(dom->iop, iova, paddr, size, prot);
|
||||
spin_unlock_irqrestore(&dom->pgtlock, flags);
|
||||
|
||||
return ret;
|
||||
@@ -401,7 +433,6 @@ static phys_addr_t mtk_iommu_iova_to_phys(struct iommu_domain *domain,
|
||||
dma_addr_t iova)
|
||||
{
|
||||
struct mtk_iommu_domain *dom = to_mtk_domain(domain);
|
||||
struct mtk_iommu_data *data = mtk_iommu_get_m4u_data();
|
||||
unsigned long flags;
|
||||
phys_addr_t pa;
|
||||
|
||||
@@ -409,9 +440,6 @@ static phys_addr_t mtk_iommu_iova_to_phys(struct iommu_domain *domain,
|
||||
pa = dom->iop->iova_to_phys(dom->iop, iova);
|
||||
spin_unlock_irqrestore(&dom->pgtlock, flags);
|
||||
|
||||
if (data->enable_4GB)
|
||||
pa |= BIT_ULL(32);
|
||||
|
||||
return pa;
|
||||
}
|
||||
|
||||
@@ -508,6 +536,7 @@ static struct iommu_ops mtk_iommu_ops = {
|
||||
|
||||
static int mtk_iommu_hw_init(const struct mtk_iommu_data *data)
|
||||
{
|
||||
enum mtk_iommu_plat m4u_plat = data->plat_data->m4u_plat;
|
||||
u32 regval;
|
||||
int ret;
|
||||
|
||||
@@ -518,7 +547,7 @@ static int mtk_iommu_hw_init(const struct mtk_iommu_data *data)
|
||||
}
|
||||
|
||||
regval = F_MMU_TF_PROTECT_SEL(2, data);
|
||||
if (data->m4u_plat == M4U_MT8173)
|
||||
if (m4u_plat == M4U_MT8173)
|
||||
regval |= F_MMU_PREFETCH_RT_REPLACE_MOD;
|
||||
writel_relaxed(regval, data->base + REG_MMU_CTRL_REG);
|
||||
|
||||
@@ -539,14 +568,14 @@ static int mtk_iommu_hw_init(const struct mtk_iommu_data *data)
|
||||
F_INT_PRETETCH_TRANSATION_FIFO_FAULT;
|
||||
writel_relaxed(regval, data->base + REG_MMU_INT_MAIN_CONTROL);
|
||||
|
||||
if (data->m4u_plat == M4U_MT8173)
|
||||
if (m4u_plat == M4U_MT8173)
|
||||
regval = (data->protect_base >> 1) | (data->enable_4GB << 31);
|
||||
else
|
||||
regval = lower_32_bits(data->protect_base) |
|
||||
upper_32_bits(data->protect_base);
|
||||
writel_relaxed(regval, data->base + REG_MMU_IVRP_PADDR);
|
||||
|
||||
if (data->enable_4GB && data->m4u_plat != M4U_MT8173) {
|
||||
if (data->enable_4GB && m4u_plat == M4U_MT2712) {
|
||||
/*
|
||||
* If 4GB mode is enabled, the validate PA range is from
|
||||
* 0x1_0000_0000 to 0x1_ffff_ffff. here record bit[32:30].
|
||||
@@ -556,8 +585,11 @@ static int mtk_iommu_hw_init(const struct mtk_iommu_data *data)
|
||||
}
|
||||
writel_relaxed(0, data->base + REG_MMU_DCM_DIS);
|
||||
|
||||
/* It's MISC control register whose default value is ok except mt8173.*/
|
||||
if (data->m4u_plat == M4U_MT8173)
|
||||
/*
|
||||
* It's MISC control register whose default value is ok
|
||||
* except mt8173 and mt8183.
|
||||
*/
|
||||
if (m4u_plat == M4U_MT8173 || m4u_plat == M4U_MT8183)
|
||||
writel_relaxed(0, data->base + REG_MMU_STANDARD_AXI_MODE);
|
||||
|
||||
if (devm_request_irq(data->dev, data->irq, mtk_iommu_isr, 0,
|
||||
@@ -590,7 +622,7 @@ static int mtk_iommu_probe(struct platform_device *pdev)
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
data->dev = dev;
|
||||
data->m4u_plat = (enum mtk_iommu_plat)of_device_get_match_data(dev);
|
||||
data->plat_data = of_device_get_match_data(dev);
|
||||
|
||||
/* Protect memory. HW will access here while translation fault.*/
|
||||
protect = devm_kzalloc(dev, MTK_PROTECT_PA_ALIGN * 2, GFP_KERNEL);
|
||||
@@ -612,7 +644,9 @@ static int mtk_iommu_probe(struct platform_device *pdev)
|
||||
return data->irq;
|
||||
|
||||
data->bclk = devm_clk_get(dev, "bclk");
|
||||
if (IS_ERR(data->bclk))
|
||||
if (PTR_ERR(data->bclk) == -ENOENT)
|
||||
data->bclk = NULL;
|
||||
else if (IS_ERR(data->bclk))
|
||||
return PTR_ERR(data->bclk);
|
||||
|
||||
larb_nr = of_count_phandle_with_args(dev->of_node,
|
||||
@@ -688,6 +722,11 @@ static int mtk_iommu_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mtk_iommu_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
mtk_iommu_remove(pdev);
|
||||
}
|
||||
|
||||
static int __maybe_unused mtk_iommu_suspend(struct device *dev)
|
||||
{
|
||||
struct mtk_iommu_data *data = dev_get_drvdata(dev);
|
||||
@@ -701,6 +740,7 @@ static int __maybe_unused mtk_iommu_suspend(struct device *dev)
|
||||
reg->int_control0 = readl_relaxed(base + REG_MMU_INT_CONTROL0);
|
||||
reg->int_main_control = readl_relaxed(base + REG_MMU_INT_MAIN_CONTROL);
|
||||
reg->ivrp_paddr = readl_relaxed(base + REG_MMU_IVRP_PADDR);
|
||||
reg->vld_pa_range = readl_relaxed(base + REG_MMU_VLD_PA_RNG);
|
||||
clk_disable_unprepare(data->bclk);
|
||||
return 0;
|
||||
}
|
||||
@@ -709,6 +749,7 @@ static int __maybe_unused mtk_iommu_resume(struct device *dev)
|
||||
{
|
||||
struct mtk_iommu_data *data = dev_get_drvdata(dev);
|
||||
struct mtk_iommu_suspend_reg *reg = &data->reg;
|
||||
struct mtk_iommu_domain *dom = data->m4u_dom;
|
||||
void __iomem *base = data->base;
|
||||
int ret;
|
||||
|
||||
@@ -724,8 +765,9 @@ static int __maybe_unused mtk_iommu_resume(struct device *dev)
|
||||
writel_relaxed(reg->int_control0, base + REG_MMU_INT_CONTROL0);
|
||||
writel_relaxed(reg->int_main_control, base + REG_MMU_INT_MAIN_CONTROL);
|
||||
writel_relaxed(reg->ivrp_paddr, base + REG_MMU_IVRP_PADDR);
|
||||
if (data->m4u_dom)
|
||||
writel(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
|
||||
writel_relaxed(reg->vld_pa_range, base + REG_MMU_VLD_PA_RNG);
|
||||
if (dom)
|
||||
writel(dom->cfg.arm_v7s_cfg.ttbr[0] & MMU_PT_ADDR_MASK,
|
||||
base + REG_MMU_PT_BASE_ADDR);
|
||||
return 0;
|
||||
}
|
||||
@@ -734,15 +776,33 @@ static const struct dev_pm_ops mtk_iommu_pm_ops = {
|
||||
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mtk_iommu_suspend, mtk_iommu_resume)
|
||||
};
|
||||
|
||||
static const struct mtk_iommu_plat_data mt2712_data = {
|
||||
.m4u_plat = M4U_MT2712,
|
||||
.has_4gb_mode = true,
|
||||
};
|
||||
|
||||
static const struct mtk_iommu_plat_data mt8173_data = {
|
||||
.m4u_plat = M4U_MT8173,
|
||||
.has_4gb_mode = true,
|
||||
};
|
||||
|
||||
static const struct mtk_iommu_plat_data mt8183_data = {
|
||||
.m4u_plat = M4U_MT8183,
|
||||
.larbid_remap_enable = true,
|
||||
.larbid_in_common = {0, 7, 5, 6, 1, 2, 3, 4},
|
||||
};
|
||||
|
||||
static const struct of_device_id mtk_iommu_of_ids[] = {
|
||||
{ .compatible = "mediatek,mt2712-m4u", .data = (void *)M4U_MT2712},
|
||||
{ .compatible = "mediatek,mt8173-m4u", .data = (void *)M4U_MT8173},
|
||||
{ .compatible = "mediatek,mt2712-m4u", .data = &mt2712_data},
|
||||
{ .compatible = "mediatek,mt8173-m4u", .data = &mt8173_data},
|
||||
{ .compatible = "mediatek,mt8183-m4u", .data = &mt8183_data},
|
||||
{}
|
||||
};
|
||||
|
||||
static struct platform_driver mtk_iommu_driver = {
|
||||
.probe = mtk_iommu_probe,
|
||||
.remove = mtk_iommu_remove,
|
||||
.shutdown = mtk_iommu_shutdown,
|
||||
.driver = {
|
||||
.name = "mtk-iommu",
|
||||
.of_match_table = of_match_ptr(mtk_iommu_of_ids),
|
||||
|
||||
@@ -33,12 +33,23 @@ struct mtk_iommu_suspend_reg {
|
||||
u32 int_control0;
|
||||
u32 int_main_control;
|
||||
u32 ivrp_paddr;
|
||||
u32 vld_pa_range;
|
||||
};
|
||||
|
||||
enum mtk_iommu_plat {
|
||||
M4U_MT2701,
|
||||
M4U_MT2712,
|
||||
M4U_MT8173,
|
||||
M4U_MT8183,
|
||||
};
|
||||
|
||||
struct mtk_iommu_plat_data {
|
||||
enum mtk_iommu_plat m4u_plat;
|
||||
bool has_4gb_mode;
|
||||
|
||||
/* The larb-id may be remapped in the smi-common. */
|
||||
bool larbid_remap_enable;
|
||||
unsigned int larbid_in_common[MTK_LARB_NR_MAX];
|
||||
};
|
||||
|
||||
struct mtk_iommu_domain;
|
||||
@@ -53,11 +64,11 @@ struct mtk_iommu_data {
|
||||
struct mtk_iommu_domain *m4u_dom;
|
||||
struct iommu_group *m4u_group;
|
||||
struct mtk_smi_iommu smi_imu; /* SMI larb iommu info */
|
||||
bool enable_4GB;
|
||||
bool enable_4GB; /* Dram is over 4gb */
|
||||
bool tlb_flush_active;
|
||||
|
||||
struct iommu_device iommu;
|
||||
enum mtk_iommu_plat m4u_plat;
|
||||
const struct mtk_iommu_plat_data *plat_data;
|
||||
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
@@ -172,7 +172,7 @@ config BCM_FLEXRM_MBOX
|
||||
SoCs. Say Y here if you want to use the Broadcom FlexRM.
|
||||
|
||||
config MTK_CMDQ_MBOX
|
||||
bool "MediaTek CMDQ Mailbox Support"
|
||||
tristate "MediaTek CMDQ Mailbox Support"
|
||||
help
|
||||
Say yes here to add support for the MediaTek Command Queue (CMDQ)
|
||||
mailbox driver. The CMDQ is used to help read/write registers with
|
||||
|
||||
@@ -37,4 +37,4 @@ obj-$(CONFIG_QCOM_APCS_IPC) += qcom-apcs-ipc-mailbox.o
|
||||
|
||||
obj-$(CONFIG_TEGRA_HSP_MBOX) += tegra-hsp.o
|
||||
|
||||
obj-$(CONFIG_MTK_CMDQ_MBOX) += mtk-cmdq-mailbox.o
|
||||
obj-$(CONFIG_MTK_CMDQ_MBOX) += mtk-cmdq-mailbox.o
|
||||
|
||||
@@ -49,6 +49,24 @@
|
||||
#define SMI_LARB_NONSEC_CON(id) (0x380 + ((id) * 4))
|
||||
#define F_MMU_EN BIT(0)
|
||||
|
||||
/* SMI COMMON */
|
||||
#define SMI_BUS_SEL 0x220
|
||||
#define SMI_BUS_LARB_SHIFT(larbid) ((larbid) << 1)
|
||||
/* All are MMU0 defaultly. Only specialize mmu1 here. */
|
||||
#define F_MMU1_LARB(larbid) (0x1 << SMI_BUS_LARB_SHIFT(larbid))
|
||||
|
||||
enum mtk_smi_gen {
|
||||
MTK_SMI_GEN1,
|
||||
MTK_SMI_GEN2
|
||||
};
|
||||
|
||||
struct mtk_smi_common_plat {
|
||||
enum mtk_smi_gen gen;
|
||||
|
||||
/* Adjust some larbs to mmu1 to balance the bandwidth */
|
||||
unsigned int bus_sel;
|
||||
};
|
||||
|
||||
struct mtk_smi_larb_gen {
|
||||
bool need_larbid;
|
||||
int port_in_larb[MTK_LARB_NR_MAX + 1];
|
||||
@@ -58,8 +76,11 @@ struct mtk_smi_larb_gen {
|
||||
struct mtk_smi {
|
||||
struct device *dev;
|
||||
struct clk *clk_apb, *clk_smi;
|
||||
struct clk *clk_gals0, *clk_gals1;
|
||||
struct clk *clk_async; /*only needed by mt2701*/
|
||||
void __iomem *smi_ao_base;
|
||||
void __iomem *smi_ao_base; /* only for gen1 */
|
||||
void __iomem *base; /* only for gen2 */
|
||||
const struct mtk_smi_common_plat *plat;
|
||||
};
|
||||
|
||||
struct mtk_smi_larb { /* larb: local arbiter */
|
||||
@@ -71,82 +92,56 @@ struct mtk_smi_larb { /* larb: local arbiter */
|
||||
u32 *mmu;
|
||||
};
|
||||
|
||||
enum mtk_smi_gen {
|
||||
MTK_SMI_GEN1,
|
||||
MTK_SMI_GEN2
|
||||
};
|
||||
|
||||
static int mtk_smi_enable(const struct mtk_smi *smi)
|
||||
static int mtk_smi_clk_enable(const struct mtk_smi *smi)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_get_sync(smi->dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = clk_prepare_enable(smi->clk_apb);
|
||||
if (ret)
|
||||
goto err_put_pm;
|
||||
return ret;
|
||||
|
||||
ret = clk_prepare_enable(smi->clk_smi);
|
||||
if (ret)
|
||||
goto err_disable_apb;
|
||||
|
||||
ret = clk_prepare_enable(smi->clk_gals0);
|
||||
if (ret)
|
||||
goto err_disable_smi;
|
||||
|
||||
ret = clk_prepare_enable(smi->clk_gals1);
|
||||
if (ret)
|
||||
goto err_disable_gals0;
|
||||
|
||||
return 0;
|
||||
|
||||
err_disable_gals0:
|
||||
clk_disable_unprepare(smi->clk_gals0);
|
||||
err_disable_smi:
|
||||
clk_disable_unprepare(smi->clk_smi);
|
||||
err_disable_apb:
|
||||
clk_disable_unprepare(smi->clk_apb);
|
||||
err_put_pm:
|
||||
pm_runtime_put_sync(smi->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mtk_smi_disable(const struct mtk_smi *smi)
|
||||
static void mtk_smi_clk_disable(const struct mtk_smi *smi)
|
||||
{
|
||||
clk_disable_unprepare(smi->clk_gals1);
|
||||
clk_disable_unprepare(smi->clk_gals0);
|
||||
clk_disable_unprepare(smi->clk_smi);
|
||||
clk_disable_unprepare(smi->clk_apb);
|
||||
pm_runtime_put_sync(smi->dev);
|
||||
}
|
||||
|
||||
int mtk_smi_larb_get(struct device *larbdev)
|
||||
{
|
||||
struct mtk_smi_larb *larb = dev_get_drvdata(larbdev);
|
||||
const struct mtk_smi_larb_gen *larb_gen = larb->larb_gen;
|
||||
struct mtk_smi *common = dev_get_drvdata(larb->smi_common_dev);
|
||||
int ret;
|
||||
int ret = pm_runtime_get_sync(larbdev);
|
||||
|
||||
/* Enable the smi-common's power and clocks */
|
||||
ret = mtk_smi_enable(common);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Enable the larb's power and clocks */
|
||||
ret = mtk_smi_enable(&larb->smi);
|
||||
if (ret) {
|
||||
mtk_smi_disable(common);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Configure the iommu info for this larb */
|
||||
larb_gen->config_port(larbdev);
|
||||
|
||||
return 0;
|
||||
return (ret < 0) ? ret : 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mtk_smi_larb_get);
|
||||
|
||||
void mtk_smi_larb_put(struct device *larbdev)
|
||||
{
|
||||
struct mtk_smi_larb *larb = dev_get_drvdata(larbdev);
|
||||
struct mtk_smi *common = dev_get_drvdata(larb->smi_common_dev);
|
||||
|
||||
/*
|
||||
* Don't de-configure the iommu info for this larb since there may be
|
||||
* several modules in this larb.
|
||||
* The iommu info will be reset after power off.
|
||||
*/
|
||||
|
||||
mtk_smi_disable(&larb->smi);
|
||||
mtk_smi_disable(common);
|
||||
pm_runtime_put_sync(larbdev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mtk_smi_larb_put);
|
||||
|
||||
@@ -176,12 +171,23 @@ mtk_smi_larb_bind(struct device *dev, struct device *master, void *data)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static void mtk_smi_larb_config_port_mt2712(struct device *dev)
|
||||
static void mtk_smi_larb_config_port_gen2_general(struct device *dev)
|
||||
{
|
||||
struct mtk_smi_larb *larb = dev_get_drvdata(dev);
|
||||
u32 reg;
|
||||
int i;
|
||||
|
||||
for_each_set_bit(i, (unsigned long *)larb->mmu, 32) {
|
||||
reg = readl_relaxed(larb->base + SMI_LARB_NONSEC_CON(i));
|
||||
reg |= F_MMU_EN;
|
||||
writel(reg, larb->base + SMI_LARB_NONSEC_CON(i));
|
||||
}
|
||||
}
|
||||
|
||||
static void mtk_smi_larb_config_port_mt2712(struct device *dev)
|
||||
{
|
||||
struct mtk_smi_larb *larb = dev_get_drvdata(dev);
|
||||
|
||||
/*
|
||||
* larb 8/9 is the bdpsys larb, the iommu_en is enabled defaultly.
|
||||
* Don't need to set it again.
|
||||
@@ -189,11 +195,7 @@ static void mtk_smi_larb_config_port_mt2712(struct device *dev)
|
||||
if (larb->larbid == 8 || larb->larbid == 9)
|
||||
return;
|
||||
|
||||
for_each_set_bit(i, (unsigned long *)larb->mmu, 32) {
|
||||
reg = readl_relaxed(larb->base + SMI_LARB_NONSEC_CON(i));
|
||||
reg |= F_MMU_EN;
|
||||
writel(reg, larb->base + SMI_LARB_NONSEC_CON(i));
|
||||
}
|
||||
mtk_smi_larb_config_port_gen2_general(dev);
|
||||
}
|
||||
|
||||
static void mtk_smi_larb_config_port_mt8173(struct device *dev)
|
||||
@@ -264,6 +266,10 @@ static const struct mtk_smi_larb_gen mtk_smi_larb_mt2712 = {
|
||||
.config_port = mtk_smi_larb_config_port_mt2712,
|
||||
};
|
||||
|
||||
static const struct mtk_smi_larb_gen mtk_smi_larb_mt8183 = {
|
||||
.config_port = mtk_smi_larb_config_port_gen2_general,
|
||||
};
|
||||
|
||||
static const struct of_device_id mtk_smi_larb_of_ids[] = {
|
||||
{
|
||||
.compatible = "mediatek,mt8173-smi-larb",
|
||||
@@ -277,6 +283,10 @@ static const struct of_device_id mtk_smi_larb_of_ids[] = {
|
||||
.compatible = "mediatek,mt2712-smi-larb",
|
||||
.data = &mtk_smi_larb_mt2712
|
||||
},
|
||||
{
|
||||
.compatible = "mediatek,mt8183-smi-larb",
|
||||
.data = &mtk_smi_larb_mt8183
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
@@ -306,6 +316,12 @@ static int mtk_smi_larb_probe(struct platform_device *pdev)
|
||||
larb->smi.clk_smi = devm_clk_get(dev, "smi");
|
||||
if (IS_ERR(larb->smi.clk_smi))
|
||||
return PTR_ERR(larb->smi.clk_smi);
|
||||
|
||||
larb->smi.clk_gals0 = devm_clk_get(dev, "gals");
|
||||
if (PTR_ERR(larb->smi.clk_gals0) == -ENOENT)
|
||||
larb->smi.clk_gals0 = NULL;
|
||||
else if (IS_ERR(larb->smi.clk_gals0))
|
||||
return PTR_ERR(larb->smi.clk_gals0);
|
||||
larb->smi.dev = dev;
|
||||
|
||||
if (larb->larb_gen->need_larbid) {
|
||||
@@ -344,27 +360,85 @@ static int mtk_smi_larb_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused mtk_smi_larb_resume(struct device *dev)
|
||||
{
|
||||
struct mtk_smi_larb *larb = dev_get_drvdata(dev);
|
||||
const struct mtk_smi_larb_gen *larb_gen = larb->larb_gen;
|
||||
int ret;
|
||||
|
||||
/* Power on smi-common. */
|
||||
ret = pm_runtime_get_sync(larb->smi_common_dev);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "smi-common pm get failed(%d).\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = mtk_smi_clk_enable(&larb->smi);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "larb clk enable failed(%d).\n", ret);
|
||||
pm_runtime_put_sync(larb->smi_common_dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Configure the basic setting for this larb */
|
||||
larb_gen->config_port(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused mtk_smi_larb_suspend(struct device *dev)
|
||||
{
|
||||
struct mtk_smi_larb *larb = dev_get_drvdata(dev);
|
||||
|
||||
mtk_smi_clk_disable(&larb->smi);
|
||||
pm_runtime_put_sync(larb->smi_common_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops smi_larb_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(mtk_smi_larb_suspend, mtk_smi_larb_resume, NULL)
|
||||
};
|
||||
|
||||
static struct platform_driver mtk_smi_larb_driver = {
|
||||
.probe = mtk_smi_larb_probe,
|
||||
.remove = mtk_smi_larb_remove,
|
||||
.driver = {
|
||||
.name = "mtk-smi-larb",
|
||||
.of_match_table = mtk_smi_larb_of_ids,
|
||||
.pm = &smi_larb_pm_ops,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct mtk_smi_common_plat mtk_smi_common_gen1 = {
|
||||
.gen = MTK_SMI_GEN1,
|
||||
};
|
||||
|
||||
static const struct mtk_smi_common_plat mtk_smi_common_gen2 = {
|
||||
.gen = MTK_SMI_GEN2,
|
||||
};
|
||||
|
||||
static const struct mtk_smi_common_plat mtk_smi_common_mt8183 = {
|
||||
.gen = MTK_SMI_GEN2,
|
||||
.bus_sel = F_MMU1_LARB(1) | F_MMU1_LARB(3) | F_MMU1_LARB(4) |
|
||||
F_MMU1_LARB(7),
|
||||
};
|
||||
|
||||
static const struct of_device_id mtk_smi_common_of_ids[] = {
|
||||
{
|
||||
.compatible = "mediatek,mt8173-smi-common",
|
||||
.data = (void *)MTK_SMI_GEN2
|
||||
.data = &mtk_smi_common_gen2,
|
||||
},
|
||||
{
|
||||
.compatible = "mediatek,mt2701-smi-common",
|
||||
.data = (void *)MTK_SMI_GEN1
|
||||
.data = &mtk_smi_common_gen1,
|
||||
},
|
||||
{
|
||||
.compatible = "mediatek,mt2712-smi-common",
|
||||
.data = (void *)MTK_SMI_GEN2
|
||||
.data = &mtk_smi_common_gen2,
|
||||
},
|
||||
{
|
||||
.compatible = "mediatek,mt8183-smi-common",
|
||||
.data = &mtk_smi_common_mt8183,
|
||||
},
|
||||
{}
|
||||
};
|
||||
@@ -374,13 +448,13 @@ static int mtk_smi_common_probe(struct platform_device *pdev)
|
||||
struct device *dev = &pdev->dev;
|
||||
struct mtk_smi *common;
|
||||
struct resource *res;
|
||||
enum mtk_smi_gen smi_gen;
|
||||
int ret;
|
||||
|
||||
common = devm_kzalloc(dev, sizeof(*common), GFP_KERNEL);
|
||||
if (!common)
|
||||
return -ENOMEM;
|
||||
common->dev = dev;
|
||||
common->plat = of_device_get_match_data(dev);
|
||||
|
||||
common->clk_apb = devm_clk_get(dev, "apb");
|
||||
if (IS_ERR(common->clk_apb))
|
||||
@@ -390,14 +464,25 @@ static int mtk_smi_common_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(common->clk_smi))
|
||||
return PTR_ERR(common->clk_smi);
|
||||
|
||||
common->clk_gals0 = devm_clk_get(dev, "gals0");
|
||||
if (PTR_ERR(common->clk_gals0) == -ENOENT)
|
||||
common->clk_gals0 = NULL;
|
||||
else if (IS_ERR(common->clk_gals0))
|
||||
return PTR_ERR(common->clk_gals0);
|
||||
|
||||
common->clk_gals1 = devm_clk_get(dev, "gals1");
|
||||
if (PTR_ERR(common->clk_gals1) == -ENOENT)
|
||||
common->clk_gals1 = NULL;
|
||||
else if (IS_ERR(common->clk_gals1))
|
||||
return PTR_ERR(common->clk_gals1);
|
||||
|
||||
/*
|
||||
* for mtk smi gen 1, we need to get the ao(always on) base to config
|
||||
* m4u port, and we need to enable the aync clock for transform the smi
|
||||
* clock into emi clock domain, but for mtk smi gen2, there's no smi ao
|
||||
* base.
|
||||
*/
|
||||
smi_gen = (enum mtk_smi_gen)of_device_get_match_data(dev);
|
||||
if (smi_gen == MTK_SMI_GEN1) {
|
||||
if (common->plat->gen == MTK_SMI_GEN1) {
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
common->smi_ao_base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(common->smi_ao_base))
|
||||
@@ -410,6 +495,11 @@ static int mtk_smi_common_probe(struct platform_device *pdev)
|
||||
ret = clk_prepare_enable(common->clk_async);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
common->base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(common->base))
|
||||
return PTR_ERR(common->base);
|
||||
}
|
||||
pm_runtime_enable(dev);
|
||||
platform_set_drvdata(pdev, common);
|
||||
@@ -422,12 +512,40 @@ static int mtk_smi_common_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused mtk_smi_common_resume(struct device *dev)
|
||||
{
|
||||
struct mtk_smi *common = dev_get_drvdata(dev);
|
||||
unsigned int bus_sel = common->plat->bus_sel;
|
||||
int ret;
|
||||
|
||||
ret = mtk_smi_clk_enable(common);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (common->plat->gen == MTK_SMI_GEN2 && bus_sel)
|
||||
writel(bus_sel, common->base + SMI_BUS_SEL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused mtk_smi_common_suspend(struct device *dev)
|
||||
{
|
||||
struct mtk_smi *common = dev_get_drvdata(dev);
|
||||
|
||||
mtk_smi_clk_disable(common);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops smi_common_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(mtk_smi_common_suspend, mtk_smi_common_resume, NULL)
|
||||
};
|
||||
|
||||
static struct platform_driver mtk_smi_common_driver = {
|
||||
.probe = mtk_smi_common_probe,
|
||||
.remove = mtk_smi_common_remove,
|
||||
.driver = {
|
||||
.name = "mtk-smi-common",
|
||||
.of_match_table = mtk_smi_common_of_ids,
|
||||
.pm = &smi_common_pm_ops,
|
||||
}
|
||||
};
|
||||
|
||||
@@ -454,3 +572,6 @@ err_unreg_smi:
|
||||
}
|
||||
|
||||
module_init(mtk_smi_init);
|
||||
|
||||
MODULE_DESCRIPTION("MediaTek SMI driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
@@ -21,15 +21,21 @@
|
||||
#include <linux/mfd/mt6397/core.h>
|
||||
#include <linux/mfd/mt6323/core.h>
|
||||
#include <linux/mfd/mt6397/registers.h>
|
||||
#include <linux/mfd/mt6358/registers.h>
|
||||
#include <linux/mfd/mt6323/registers.h>
|
||||
|
||||
#define MT6397_RTC_BASE 0xe000
|
||||
#define MT6397_RTC_SIZE 0x3e
|
||||
|
||||
#define MT6323_CID_CODE 0x23
|
||||
#define MT6358_CID_CODE 0x20
|
||||
#define MT6391_CID_CODE 0x91
|
||||
#define MT6397_CID_CODE 0x97
|
||||
|
||||
struct chip_data {
|
||||
u32 cid_addr;
|
||||
};
|
||||
|
||||
static const struct resource mt6397_rtc_resources[] = {
|
||||
{
|
||||
.start = MT6397_RTC_BASE,
|
||||
@@ -43,6 +49,16 @@ static const struct resource mt6397_rtc_resources[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static const struct resource mt6323_keys_resources[] = {
|
||||
DEFINE_RES_IRQ(MT6323_IRQ_STATUS_PWRKEY),
|
||||
DEFINE_RES_IRQ(MT6323_IRQ_STATUS_FCHRKEY),
|
||||
};
|
||||
|
||||
static const struct resource mt6397_keys_resources[] = {
|
||||
DEFINE_RES_IRQ(MT6397_IRQ_PWRKEY),
|
||||
DEFINE_RES_IRQ(MT6397_IRQ_HOMEKEY),
|
||||
};
|
||||
|
||||
static const struct mfd_cell mt6323_devs[] = {
|
||||
{
|
||||
.name = "mt6323-regulator",
|
||||
@@ -50,6 +66,18 @@ static const struct mfd_cell mt6323_devs[] = {
|
||||
}, {
|
||||
.name = "mt6323-led",
|
||||
.of_compatible = "mediatek,mt6323-led"
|
||||
}, {
|
||||
.name = "mtk-pmic-keys",
|
||||
.num_resources = ARRAY_SIZE(mt6323_keys_resources),
|
||||
.resources = mt6323_keys_resources,
|
||||
.of_compatible = "mediatek,mt6323-keys"
|
||||
},
|
||||
};
|
||||
|
||||
static const struct mfd_cell mt6358_devs[] = {
|
||||
{
|
||||
.name = "mt6358-regulator",
|
||||
.of_compatible = "mediatek,mt6358-regulator"
|
||||
},
|
||||
};
|
||||
|
||||
@@ -71,7 +99,24 @@ static const struct mfd_cell mt6397_devs[] = {
|
||||
}, {
|
||||
.name = "mt6397-pinctrl",
|
||||
.of_compatible = "mediatek,mt6397-pinctrl",
|
||||
},
|
||||
}, {
|
||||
.name = "mtk-pmic-keys",
|
||||
.num_resources = ARRAY_SIZE(mt6397_keys_resources),
|
||||
.resources = mt6397_keys_resources,
|
||||
.of_compatible = "mediatek,mt6397-keys"
|
||||
}
|
||||
};
|
||||
|
||||
static const struct chip_data mt6323_core = {
|
||||
.cid_addr = MT6397_CID,
|
||||
};
|
||||
|
||||
static const struct chip_data mt6358_core = {
|
||||
.cid_addr = MT6358_SWCID,
|
||||
};
|
||||
|
||||
static const struct chip_data mt6397_core = {
|
||||
.cid_addr = MT6397_CID,
|
||||
};
|
||||
|
||||
static void mt6397_irq_lock(struct irq_data *data)
|
||||
@@ -250,6 +295,7 @@ static int mt6397_probe(struct platform_device *pdev)
|
||||
int ret;
|
||||
unsigned int id;
|
||||
struct mt6397_chip *pmic;
|
||||
const struct chip_data *pmic_core;
|
||||
|
||||
pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
|
||||
if (!pmic)
|
||||
@@ -267,7 +313,11 @@ static int mt6397_probe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, pmic);
|
||||
|
||||
ret = regmap_read(pmic->regmap, MT6397_CID, &id);
|
||||
pmic_core = of_device_get_match_data(&pdev->dev);
|
||||
if (!pmic_core)
|
||||
return -ENODEV;
|
||||
|
||||
ret = regmap_read(pmic->regmap, pmic_core->cid_addr, &id);
|
||||
if (ret) {
|
||||
dev_err(pmic->dev, "Failed to read chip id: %d\n", ret);
|
||||
return ret;
|
||||
@@ -289,7 +339,21 @@ static int mt6397_probe(struct platform_device *pdev)
|
||||
|
||||
ret = devm_mfd_add_devices(&pdev->dev, -1, mt6323_devs,
|
||||
ARRAY_SIZE(mt6323_devs), NULL,
|
||||
0, NULL);
|
||||
0, pmic->irq_domain);
|
||||
break;
|
||||
|
||||
case MT6358_CID_CODE:
|
||||
pmic->int_con[0] = MT6358_PSC_TOP_INT_CON0;
|
||||
pmic->int_con[1] = MT6358_HK_TOP_INT_CON0;
|
||||
pmic->int_status[0] = MT6358_PSC_TOP_INT_STATUS0;
|
||||
pmic->int_status[1] = MT6358_HK_TOP_INT_STATUS0;
|
||||
ret = mt6397_irq_init(pmic);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_mfd_add_devices(&pdev->dev, -1, mt6358_devs,
|
||||
ARRAY_SIZE(mt6358_devs), NULL,
|
||||
0, pmic->irq_domain);
|
||||
break;
|
||||
|
||||
case MT6397_CID_CODE:
|
||||
@@ -304,7 +368,7 @@ static int mt6397_probe(struct platform_device *pdev)
|
||||
|
||||
ret = devm_mfd_add_devices(&pdev->dev, -1, mt6397_devs,
|
||||
ARRAY_SIZE(mt6397_devs), NULL,
|
||||
0, NULL);
|
||||
0, pmic->irq_domain);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -322,9 +386,18 @@ static int mt6397_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
static const struct of_device_id mt6397_of_match[] = {
|
||||
{ .compatible = "mediatek,mt6397" },
|
||||
{ .compatible = "mediatek,mt6323" },
|
||||
{ }
|
||||
{
|
||||
.compatible = "mediatek,mt6323",
|
||||
.data = &mt6323_core,
|
||||
}, {
|
||||
.compatible = "mediatek,mt6358",
|
||||
.data = &mt6358_core,
|
||||
}, {
|
||||
.compatible = "mediatek,mt6397",
|
||||
.data = &mt6397_core,
|
||||
}, {
|
||||
/* sentinel */
|
||||
}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mt6397_of_match);
|
||||
|
||||
|
||||
@@ -85,6 +85,13 @@
|
||||
#define EMMC50_CFG3 0x220
|
||||
#define SDC_FIFO_CFG 0x228
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* Top Register Offset */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
#define EMMC_TOP_CONTROL (0x00)
|
||||
#define EMMC_TOP_CMD (0x04)
|
||||
#define EMMC50_PAD_DS_TUNE (0x0c)
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* Register Mask */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
@@ -260,6 +267,23 @@
|
||||
#define SDC_FIFO_CFG_WRVALIDSEL (0x1 << 24) /* RW */
|
||||
#define SDC_FIFO_CFG_RDVALIDSEL (0x1 << 25) /* RW */
|
||||
|
||||
/* EMMC_TOP_CONTROL mask */
|
||||
#define PAD_RXDLY_SEL (0x1 << 0) /* RW */
|
||||
#define DELAY_EN (0x1 << 1) /* RW */
|
||||
#define PAD_DAT_RD_RXDLY2 (0x1F << 2) /* RW */
|
||||
#define PAD_DAT_RD_RXDLY (0x1F << 7) /* RW */
|
||||
#define PAD_DAT_RD_RXDLY2_SEL (0x1 << 12) /* RW */
|
||||
#define PAD_DAT_RD_RXDLY_SEL (0x1 << 13) /* RW */
|
||||
#define DATA_K_VALUE_SEL (0x1 << 14) /* RW */
|
||||
#define SDC_RX_ENH_EN (0x1 << 15) /* TW */
|
||||
|
||||
/* EMMC_TOP_CMD mask */
|
||||
#define PAD_CMD_RXDLY2 (0x1F << 0) /* RW */
|
||||
#define PAD_CMD_RXDLY (0x1F << 5) /* RW */
|
||||
#define PAD_CMD_RD_RXDLY2_SEL (0x1 << 10) /* RW */
|
||||
#define PAD_CMD_RD_RXDLY_SEL (0x1 << 11) /* RW */
|
||||
#define PAD_CMD_TX_DLY (0x1F << 12) /* RW */
|
||||
|
||||
#define REQ_CMD_EIO (0x1 << 0)
|
||||
#define REQ_CMD_TMO (0x1 << 1)
|
||||
#define REQ_DAT_ERR (0x1 << 2)
|
||||
@@ -332,6 +356,9 @@ struct msdc_save_para {
|
||||
u32 emmc50_cfg0;
|
||||
u32 emmc50_cfg3;
|
||||
u32 sdc_fifo_cfg;
|
||||
u32 emmc_top_control;
|
||||
u32 emmc_top_cmd;
|
||||
u32 emmc50_pad_ds_tune;
|
||||
};
|
||||
|
||||
struct mtk_mmc_compatible {
|
||||
@@ -344,12 +371,15 @@ struct mtk_mmc_compatible {
|
||||
bool stop_clk_fix;
|
||||
bool enhance_rx;
|
||||
bool support_64g;
|
||||
bool tune_resp_data_together;
|
||||
};
|
||||
|
||||
struct msdc_tune_para {
|
||||
u32 iocon;
|
||||
u32 pad_tune;
|
||||
u32 pad_cmd_tune;
|
||||
u32 emmc_top_control;
|
||||
u32 emmc_top_cmd;
|
||||
};
|
||||
|
||||
struct msdc_delay_phase {
|
||||
@@ -371,6 +401,7 @@ struct msdc_host {
|
||||
int error;
|
||||
|
||||
void __iomem *base; /* host base address */
|
||||
void __iomem *top_base; /* host top register base address */
|
||||
|
||||
struct msdc_dma dma; /* dma channel */
|
||||
u64 dma_mask;
|
||||
@@ -414,6 +445,7 @@ static const struct mtk_mmc_compatible mt8135_compat = {
|
||||
.stop_clk_fix = false,
|
||||
.enhance_rx = false,
|
||||
.support_64g = false,
|
||||
.tune_resp_data_together = false,
|
||||
};
|
||||
|
||||
static const struct mtk_mmc_compatible mt8173_compat = {
|
||||
@@ -426,6 +458,7 @@ static const struct mtk_mmc_compatible mt8173_compat = {
|
||||
.stop_clk_fix = false,
|
||||
.enhance_rx = false,
|
||||
.support_64g = false,
|
||||
.tune_resp_data_together = false,
|
||||
};
|
||||
|
||||
static const struct mtk_mmc_compatible mt2701_compat = {
|
||||
@@ -438,6 +471,7 @@ static const struct mtk_mmc_compatible mt2701_compat = {
|
||||
.stop_clk_fix = false,
|
||||
.enhance_rx = false,
|
||||
.support_64g = false,
|
||||
.tune_resp_data_together = false,
|
||||
};
|
||||
|
||||
static const struct mtk_mmc_compatible mt2712_compat = {
|
||||
@@ -450,6 +484,7 @@ static const struct mtk_mmc_compatible mt2712_compat = {
|
||||
.stop_clk_fix = true,
|
||||
.enhance_rx = true,
|
||||
.support_64g = true,
|
||||
.tune_resp_data_together = true,
|
||||
};
|
||||
|
||||
static const struct mtk_mmc_compatible mt7622_compat = {
|
||||
@@ -462,6 +497,20 @@ static const struct mtk_mmc_compatible mt7622_compat = {
|
||||
.stop_clk_fix = true,
|
||||
.enhance_rx = true,
|
||||
.support_64g = false,
|
||||
.tune_resp_data_together = false,
|
||||
};
|
||||
|
||||
static const struct mtk_mmc_compatible mt8183_compat = {
|
||||
.clk_div_bits = 12,
|
||||
.hs400_tune = false,
|
||||
.pad_tune_reg = MSDC_PAD_TUNE0,
|
||||
.async_fifo = true,
|
||||
.data_tune = true,
|
||||
.busy_check = true,
|
||||
.stop_clk_fix = true,
|
||||
.enhance_rx = true,
|
||||
.support_64g = true,
|
||||
.tune_resp_data_together = true,
|
||||
};
|
||||
|
||||
static const struct of_device_id msdc_of_ids[] = {
|
||||
@@ -470,6 +519,7 @@ static const struct of_device_id msdc_of_ids[] = {
|
||||
{ .compatible = "mediatek,mt2701-mmc", .data = &mt2701_compat},
|
||||
{ .compatible = "mediatek,mt2712-mmc", .data = &mt2712_compat},
|
||||
{ .compatible = "mediatek,mt7622-mmc", .data = &mt7622_compat},
|
||||
{ .compatible = "mediatek,mt8183-mmc", .data = &mt8183_compat},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, msdc_of_ids);
|
||||
@@ -774,11 +824,23 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
|
||||
if (host->sclk <= 52000000) {
|
||||
writel(host->def_tune_para.iocon, host->base + MSDC_IOCON);
|
||||
writel(host->def_tune_para.pad_tune, host->base + tune_reg);
|
||||
if (host->top_base != NULL) {
|
||||
writel(host->def_tune_para.emmc_top_control,
|
||||
host->top_base + EMMC_TOP_CONTROL);
|
||||
writel(host->def_tune_para.emmc_top_cmd,
|
||||
host->top_base + EMMC_TOP_CMD);
|
||||
}
|
||||
} else {
|
||||
writel(host->saved_tune_para.iocon, host->base + MSDC_IOCON);
|
||||
writel(host->saved_tune_para.pad_tune, host->base + tune_reg);
|
||||
writel(host->saved_tune_para.pad_cmd_tune,
|
||||
host->base + PAD_CMD_TUNE);
|
||||
if (host->top_base != NULL) {
|
||||
writel(host->saved_tune_para.emmc_top_control,
|
||||
host->top_base + EMMC_TOP_CONTROL);
|
||||
writel(host->saved_tune_para.emmc_top_cmd,
|
||||
host->top_base + EMMC_TOP_CMD);
|
||||
}
|
||||
}
|
||||
|
||||
if (timing == MMC_TIMING_MMC_HS400 &&
|
||||
@@ -1000,8 +1062,10 @@ static bool msdc_cmd_done(struct msdc_host *host, int events,
|
||||
host->error |= REQ_CMD_TMO;
|
||||
}
|
||||
}
|
||||
if (cmd->error)
|
||||
dev_dbg(host->dev,
|
||||
if (cmd->error &&
|
||||
cmd->opcode != MMC_SEND_TUNING_BLOCK &&
|
||||
cmd->opcode != MMC_SEND_TUNING_BLOCK_HS200)
|
||||
dev_info(host->dev,
|
||||
"%s: cmd=%d arg=%08X; rsp %08X; cmd_error=%d\n",
|
||||
__func__, cmd->opcode, cmd->arg, rsp[0],
|
||||
cmd->error);
|
||||
@@ -1190,11 +1254,14 @@ static bool msdc_data_xfer_done(struct msdc_host *host, u32 events,
|
||||
data->error = -ETIMEDOUT;
|
||||
else if (events & MSDC_INT_DATCRCERR)
|
||||
data->error = -EILSEQ;
|
||||
|
||||
dev_dbg(host->dev, "%s: cmd=%d; blocks=%d",
|
||||
__func__, mrq->cmd->opcode, data->blocks);
|
||||
dev_dbg(host->dev, "data_error=%d xfer_size=%d\n",
|
||||
(int)data->error, data->bytes_xfered);
|
||||
if (mrq->cmd->opcode != MMC_SEND_TUNING_BLOCK &&
|
||||
mrq->cmd->opcode != MMC_SEND_TUNING_BLOCK_HS200) {
|
||||
dev_info(host->dev, "%s: cmd=%d; blocks=%d",
|
||||
__func__, mrq->cmd->opcode,
|
||||
data->blocks);
|
||||
dev_info(host->dev, "data_error=%d xfer_size=%d\n",
|
||||
(int)data->error, data->bytes_xfered);
|
||||
}
|
||||
}
|
||||
|
||||
msdc_data_xfer_next(host, mrq, data);
|
||||
@@ -1351,6 +1418,10 @@ static void msdc_init_hw(struct msdc_host *host)
|
||||
writel(val, host->base + MSDC_INT);
|
||||
|
||||
writel(0, host->base + tune_reg);
|
||||
if (host->top_base != NULL) {
|
||||
writel(0, host->top_base + EMMC_TOP_CONTROL);
|
||||
writel(0, host->top_base + EMMC_TOP_CMD);
|
||||
}
|
||||
writel(0, host->base + MSDC_IOCON);
|
||||
sdr_set_field(host->base + MSDC_IOCON, MSDC_IOCON_DDLSEL, 0);
|
||||
writel(0x403c0046, host->base + MSDC_PATCH_BIT);
|
||||
@@ -1374,8 +1445,12 @@ static void msdc_init_hw(struct msdc_host *host)
|
||||
sdr_set_field(host->base + MSDC_PATCH_BIT2,
|
||||
MSDC_PB2_RESPWAIT, 3);
|
||||
if (host->dev_comp->enhance_rx) {
|
||||
sdr_set_bits(host->base + SDC_ADV_CFG0,
|
||||
SDC_RX_ENHANCE_EN);
|
||||
if (host->top_base != NULL)
|
||||
sdr_set_bits(host->top_base + EMMC_TOP_CONTROL,
|
||||
SDC_RX_ENH_EN);
|
||||
else
|
||||
sdr_set_bits(host->base + SDC_ADV_CFG0,
|
||||
SDC_RX_ENHANCE_EN);
|
||||
} else {
|
||||
sdr_set_field(host->base + MSDC_PATCH_BIT2,
|
||||
MSDC_PB2_RESPSTSENSEL, 2);
|
||||
@@ -1393,11 +1468,26 @@ static void msdc_init_hw(struct msdc_host *host)
|
||||
sdr_set_bits(host->base + MSDC_PATCH_BIT2,
|
||||
MSDC_PB2_SUPPORT_64G);
|
||||
if (host->dev_comp->data_tune) {
|
||||
sdr_set_bits(host->base + tune_reg,
|
||||
MSDC_PAD_TUNE_RD_SEL | MSDC_PAD_TUNE_CMD_SEL);
|
||||
if (host->top_base != NULL) {
|
||||
sdr_set_bits(host->top_base + EMMC_TOP_CONTROL,
|
||||
PAD_DAT_RD_RXDLY_SEL);
|
||||
sdr_clr_bits(host->top_base + EMMC_TOP_CONTROL,
|
||||
DATA_K_VALUE_SEL);
|
||||
sdr_set_bits(host->top_base + EMMC_TOP_CMD,
|
||||
PAD_CMD_RD_RXDLY_SEL);
|
||||
} else {
|
||||
sdr_set_bits(host->base + tune_reg,
|
||||
MSDC_PAD_TUNE_RD_SEL |
|
||||
MSDC_PAD_TUNE_CMD_SEL);
|
||||
}
|
||||
} else {
|
||||
/* choose clock tune */
|
||||
sdr_set_bits(host->base + tune_reg, MSDC_PAD_TUNE_RXDLYSEL);
|
||||
if (host->top_base != NULL)
|
||||
sdr_set_bits(host->top_base + EMMC_TOP_CONTROL,
|
||||
PAD_RXDLY_SEL);
|
||||
else
|
||||
sdr_set_bits(host->base + tune_reg,
|
||||
MSDC_PAD_TUNE_RXDLYSEL);
|
||||
}
|
||||
|
||||
/* Configure to enable SDIO mode.
|
||||
@@ -1415,6 +1505,16 @@ static void msdc_init_hw(struct msdc_host *host)
|
||||
host->def_tune_para.pad_tune = readl(host->base + tune_reg);
|
||||
host->saved_tune_para.iocon = readl(host->base + MSDC_IOCON);
|
||||
host->saved_tune_para.pad_tune = readl(host->base + tune_reg);
|
||||
if (host->top_base != NULL) {
|
||||
host->def_tune_para.emmc_top_control =
|
||||
readl(host->top_base + EMMC_TOP_CONTROL);
|
||||
host->def_tune_para.emmc_top_cmd =
|
||||
readl(host->top_base + EMMC_TOP_CMD);
|
||||
host->saved_tune_para.emmc_top_control =
|
||||
readl(host->top_base + EMMC_TOP_CONTROL);
|
||||
host->saved_tune_para.emmc_top_cmd =
|
||||
readl(host->top_base + EMMC_TOP_CMD);
|
||||
}
|
||||
dev_dbg(host->dev, "init hardware done!");
|
||||
}
|
||||
|
||||
@@ -1562,6 +1662,132 @@ static struct msdc_delay_phase get_best_delay(struct msdc_host *host, u32 delay)
|
||||
return delay_phase;
|
||||
}
|
||||
|
||||
static int msdc_tune_resp_data(struct mmc_host *mmc, u32 opcode)
|
||||
{
|
||||
struct msdc_host *host = mmc_priv(mmc);
|
||||
u32 rise_delay = 0, fall_delay = 0;
|
||||
struct msdc_delay_phase final_rise_delay, final_fall_delay = { 0,};
|
||||
u8 final_delay, final_maxlen;
|
||||
u32 tune_reg = host->dev_comp->pad_tune_reg;
|
||||
int err;
|
||||
int i, j;
|
||||
|
||||
sdr_set_field(host->base + MSDC_PATCH_BIT, MSDC_INT_DAT_LATCH_CK_SEL,
|
||||
host->latch_ck);
|
||||
sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
|
||||
sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
|
||||
sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
|
||||
for (i = 0 ; i < PAD_DELAY_MAX; i++) {
|
||||
if (host->top_base != NULL) {
|
||||
sdr_set_field(host->top_base + EMMC_TOP_CMD,
|
||||
PAD_CMD_RXDLY, i);
|
||||
sdr_set_field(host->top_base + EMMC_TOP_CONTROL,
|
||||
PAD_DAT_RD_RXDLY, i);
|
||||
} else {
|
||||
sdr_set_field(host->base + tune_reg,
|
||||
MSDC_PAD_TUNE_CMDRDLY, i);
|
||||
sdr_set_field(host->base + tune_reg,
|
||||
MSDC_PAD_TUNE_DATRRDLY, i);
|
||||
}
|
||||
/*
|
||||
* Using the same parameters, it may sometimes pass the test,
|
||||
* but sometimes it may fail. To make sure the parameters are
|
||||
* more stable, we test each set of parameters 3 times.
|
||||
*/
|
||||
for (j = 0; j < 3; j++) {
|
||||
err = mmc_send_tuning(mmc, opcode, NULL);
|
||||
if (!err) {
|
||||
rise_delay |= (1 << i);
|
||||
} else {
|
||||
rise_delay &= ~(1 << i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
final_rise_delay = get_best_delay(host, rise_delay);
|
||||
/* if rising edge has enough margin, then do not scan falling edge */
|
||||
if (final_rise_delay.maxlen >= 12 ||
|
||||
(final_rise_delay.start == 0 && final_rise_delay.maxlen >= 4))
|
||||
goto skip_fall;
|
||||
|
||||
sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
|
||||
sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
|
||||
sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
|
||||
for (i = 0; i < PAD_DELAY_MAX; i++) {
|
||||
if (host->top_base != NULL) {
|
||||
sdr_set_field(host->top_base + EMMC_TOP_CMD,
|
||||
PAD_CMD_RXDLY, i);
|
||||
sdr_set_field(host->top_base + EMMC_TOP_CONTROL,
|
||||
PAD_DAT_RD_RXDLY, i);
|
||||
} else {
|
||||
sdr_set_field(host->base + tune_reg,
|
||||
MSDC_PAD_TUNE_CMDRDLY, i);
|
||||
sdr_set_field(host->base + tune_reg,
|
||||
MSDC_PAD_TUNE_DATRRDLY, i);
|
||||
}
|
||||
|
||||
for (j = 0; j < 3; j++) {
|
||||
err = mmc_send_tuning(mmc, opcode, NULL);
|
||||
if (!err) {
|
||||
fall_delay |= (1 << i);
|
||||
} else {
|
||||
fall_delay &= ~(1 << i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
final_fall_delay = get_best_delay(host, fall_delay);
|
||||
|
||||
skip_fall:
|
||||
final_maxlen = max(final_rise_delay.maxlen, final_fall_delay.maxlen);
|
||||
if (final_fall_delay.maxlen >= 12 && final_fall_delay.start < 4)
|
||||
final_maxlen = final_fall_delay.maxlen;
|
||||
if (final_maxlen == final_rise_delay.maxlen) {
|
||||
sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
|
||||
sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
|
||||
sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
|
||||
if (host->top_base != NULL) {
|
||||
sdr_set_field(host->top_base + EMMC_TOP_CMD,
|
||||
PAD_CMD_RXDLY,
|
||||
final_rise_delay.final_phase);
|
||||
sdr_set_field(host->top_base + EMMC_TOP_CONTROL,
|
||||
PAD_DAT_RD_RXDLY,
|
||||
final_rise_delay.final_phase);
|
||||
} else {
|
||||
sdr_set_field(host->base + tune_reg,
|
||||
MSDC_PAD_TUNE_CMDRDLY,
|
||||
final_rise_delay.final_phase);
|
||||
sdr_set_field(host->base + tune_reg,
|
||||
MSDC_PAD_TUNE_DATRRDLY,
|
||||
final_rise_delay.final_phase);
|
||||
}
|
||||
final_delay = final_rise_delay.final_phase;
|
||||
} else {
|
||||
sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
|
||||
sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
|
||||
sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
|
||||
if (host->top_base != NULL) {
|
||||
sdr_set_field(host->top_base + EMMC_TOP_CMD,
|
||||
PAD_CMD_RXDLY,
|
||||
final_fall_delay.final_phase);
|
||||
sdr_set_field(host->top_base + EMMC_TOP_CONTROL,
|
||||
PAD_DAT_RD_RXDLY,
|
||||
final_fall_delay.final_phase);
|
||||
} else {
|
||||
sdr_set_field(host->base + tune_reg,
|
||||
MSDC_PAD_TUNE_CMDRDLY,
|
||||
final_fall_delay.final_phase);
|
||||
sdr_set_field(host->base + tune_reg,
|
||||
MSDC_PAD_TUNE_DATRRDLY,
|
||||
final_fall_delay.final_phase);
|
||||
}
|
||||
final_delay = final_fall_delay.final_phase;
|
||||
}
|
||||
|
||||
dev_info(host->dev, "Final cmd/data pad delay: %x\n", final_delay);
|
||||
return final_delay == 0xff ? -EIO : 0;
|
||||
}
|
||||
|
||||
static int msdc_tune_response(struct mmc_host *mmc, u32 opcode)
|
||||
{
|
||||
struct msdc_host *host = mmc_priv(mmc);
|
||||
@@ -1582,8 +1808,12 @@ static int msdc_tune_response(struct mmc_host *mmc, u32 opcode)
|
||||
|
||||
sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
|
||||
for (i = 0 ; i < PAD_DELAY_MAX; i++) {
|
||||
sdr_set_field(host->base + tune_reg,
|
||||
MSDC_PAD_TUNE_CMDRDLY, i);
|
||||
if (host->top_base != NULL)
|
||||
sdr_set_field(host->top_base + EMMC_TOP_CMD,
|
||||
PAD_CMD_RXDLY, i);
|
||||
else
|
||||
sdr_set_field(host->base + tune_reg,
|
||||
MSDC_PAD_TUNE_CMDRDLY, i);
|
||||
/*
|
||||
* Using the same parameters, it may sometimes pass the test,
|
||||
* but sometimes it may fail. To make sure the parameters are
|
||||
@@ -1607,8 +1837,12 @@ static int msdc_tune_response(struct mmc_host *mmc, u32 opcode)
|
||||
|
||||
sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
|
||||
for (i = 0; i < PAD_DELAY_MAX; i++) {
|
||||
sdr_set_field(host->base + tune_reg,
|
||||
MSDC_PAD_TUNE_CMDRDLY, i);
|
||||
if (host->top_base != NULL)
|
||||
sdr_set_field(host->top_base + EMMC_TOP_CMD,
|
||||
PAD_CMD_RXDLY, i);
|
||||
else
|
||||
sdr_set_field(host->base + tune_reg,
|
||||
MSDC_PAD_TUNE_CMDRDLY, i);
|
||||
/*
|
||||
* Using the same parameters, it may sometimes pass the test,
|
||||
* but sometimes it may fail. To make sure the parameters are
|
||||
@@ -1632,13 +1866,25 @@ skip_fall:
|
||||
final_maxlen = final_fall_delay.maxlen;
|
||||
if (final_maxlen == final_rise_delay.maxlen) {
|
||||
sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
|
||||
sdr_set_field(host->base + tune_reg, MSDC_PAD_TUNE_CMDRDLY,
|
||||
final_rise_delay.final_phase);
|
||||
if (host->top_base != NULL)
|
||||
sdr_set_field(host->top_base + EMMC_TOP_CMD,
|
||||
PAD_CMD_RXDLY,
|
||||
final_rise_delay.final_phase);
|
||||
else
|
||||
sdr_set_field(host->base + tune_reg,
|
||||
MSDC_PAD_TUNE_CMDRDLY,
|
||||
final_rise_delay.final_phase);
|
||||
final_delay = final_rise_delay.final_phase;
|
||||
} else {
|
||||
sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
|
||||
sdr_set_field(host->base + tune_reg, MSDC_PAD_TUNE_CMDRDLY,
|
||||
final_fall_delay.final_phase);
|
||||
if (host->top_base != NULL)
|
||||
sdr_set_field(host->top_base + EMMC_TOP_CMD,
|
||||
PAD_CMD_RXDLY,
|
||||
final_fall_delay.final_phase);
|
||||
else
|
||||
sdr_set_field(host->base + tune_reg,
|
||||
MSDC_PAD_TUNE_CMDRDLY,
|
||||
final_fall_delay.final_phase);
|
||||
final_delay = final_fall_delay.final_phase;
|
||||
}
|
||||
if (host->dev_comp->async_fifo || host->hs200_cmd_int_delay)
|
||||
@@ -1651,12 +1897,12 @@ skip_fall:
|
||||
if (!cmd_err)
|
||||
internal_delay |= (1 << i);
|
||||
}
|
||||
dev_dbg(host->dev, "Final internal delay: 0x%x\n", internal_delay);
|
||||
dev_info(host->dev, "Final internal delay: 0x%x\n", internal_delay);
|
||||
internal_delay_phase = get_best_delay(host, internal_delay);
|
||||
sdr_set_field(host->base + tune_reg, MSDC_PAD_TUNE_CMDRRDLY,
|
||||
internal_delay_phase.final_phase);
|
||||
skip_internal:
|
||||
dev_dbg(host->dev, "Final cmd pad delay: %x\n", final_delay);
|
||||
dev_info(host->dev, "Final cmd pad delay: %x\n", final_delay);
|
||||
return final_delay == 0xff ? -EIO : 0;
|
||||
}
|
||||
|
||||
@@ -1705,7 +1951,7 @@ static int hs400_tune_response(struct mmc_host *mmc, u32 opcode)
|
||||
final_cmd_delay.final_phase);
|
||||
final_delay = final_cmd_delay.final_phase;
|
||||
|
||||
dev_dbg(host->dev, "Final cmd pad delay: %x\n", final_delay);
|
||||
dev_info(host->dev, "Final cmd pad delay: %x\n", final_delay);
|
||||
return final_delay == 0xff ? -EIO : 0;
|
||||
}
|
||||
|
||||
@@ -1723,8 +1969,12 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode)
|
||||
sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
|
||||
sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
|
||||
for (i = 0 ; i < PAD_DELAY_MAX; i++) {
|
||||
sdr_set_field(host->base + tune_reg,
|
||||
MSDC_PAD_TUNE_DATRRDLY, i);
|
||||
if (host->top_base != NULL)
|
||||
sdr_set_field(host->top_base + EMMC_TOP_CONTROL,
|
||||
PAD_DAT_RD_RXDLY, i);
|
||||
else
|
||||
sdr_set_field(host->base + tune_reg,
|
||||
MSDC_PAD_TUNE_DATRRDLY, i);
|
||||
ret = mmc_send_tuning(mmc, opcode, NULL);
|
||||
if (!ret)
|
||||
rise_delay |= (1 << i);
|
||||
@@ -1738,8 +1988,12 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode)
|
||||
sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
|
||||
sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
|
||||
for (i = 0; i < PAD_DELAY_MAX; i++) {
|
||||
sdr_set_field(host->base + tune_reg,
|
||||
MSDC_PAD_TUNE_DATRRDLY, i);
|
||||
if (host->top_base != NULL)
|
||||
sdr_set_field(host->top_base + EMMC_TOP_CONTROL,
|
||||
PAD_DAT_RD_RXDLY, i);
|
||||
else
|
||||
sdr_set_field(host->base + tune_reg,
|
||||
MSDC_PAD_TUNE_DATRRDLY, i);
|
||||
ret = mmc_send_tuning(mmc, opcode, NULL);
|
||||
if (!ret)
|
||||
fall_delay |= (1 << i);
|
||||
@@ -1751,20 +2005,30 @@ skip_fall:
|
||||
if (final_maxlen == final_rise_delay.maxlen) {
|
||||
sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
|
||||
sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
|
||||
sdr_set_field(host->base + tune_reg,
|
||||
MSDC_PAD_TUNE_DATRRDLY,
|
||||
final_rise_delay.final_phase);
|
||||
if (host->top_base != NULL)
|
||||
sdr_set_field(host->top_base + EMMC_TOP_CONTROL,
|
||||
PAD_DAT_RD_RXDLY,
|
||||
final_rise_delay.final_phase);
|
||||
else
|
||||
sdr_set_field(host->base + tune_reg,
|
||||
MSDC_PAD_TUNE_DATRRDLY,
|
||||
final_rise_delay.final_phase);
|
||||
final_delay = final_rise_delay.final_phase;
|
||||
} else {
|
||||
sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
|
||||
sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
|
||||
sdr_set_field(host->base + tune_reg,
|
||||
MSDC_PAD_TUNE_DATRRDLY,
|
||||
final_fall_delay.final_phase);
|
||||
if (host->top_base != NULL)
|
||||
sdr_set_field(host->top_base + EMMC_TOP_CONTROL,
|
||||
PAD_DAT_RD_RXDLY,
|
||||
final_fall_delay.final_phase);
|
||||
else
|
||||
sdr_set_field(host->base + tune_reg,
|
||||
MSDC_PAD_TUNE_DATRRDLY,
|
||||
final_fall_delay.final_phase);
|
||||
final_delay = final_fall_delay.final_phase;
|
||||
}
|
||||
|
||||
dev_dbg(host->dev, "Final data pad delay: %x\n", final_delay);
|
||||
dev_info(host->dev, "Final data pad delay: %x\n", final_delay);
|
||||
return final_delay == 0xff ? -EIO : 0;
|
||||
}
|
||||
|
||||
@@ -1774,24 +2038,48 @@ static int msdc_execute_tuning(struct mmc_host *mmc, u32 opcode)
|
||||
int ret;
|
||||
u32 tune_reg = host->dev_comp->pad_tune_reg;
|
||||
|
||||
if (host->hs400_mode &&
|
||||
host->dev_comp->hs400_tune)
|
||||
ret = hs400_tune_response(mmc, opcode);
|
||||
else
|
||||
ret = msdc_tune_response(mmc, opcode);
|
||||
if (ret == -EIO) {
|
||||
dev_err(host->dev, "Tune response fail!\n");
|
||||
return ret;
|
||||
}
|
||||
if (host->hs400_mode == false) {
|
||||
ret = msdc_tune_data(mmc, opcode);
|
||||
if (host->dev_comp->tune_resp_data_together) {
|
||||
ret = msdc_tune_resp_data(mmc, opcode);
|
||||
if (ret == -EIO)
|
||||
dev_err(host->dev, "Tune data fail!\n");
|
||||
dev_err(host->dev, "Tune cmd/data fail!\n");
|
||||
if (host->hs400_mode) {
|
||||
sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
|
||||
sdr_clr_bits(host->base + MSDC_IOCON,
|
||||
MSDC_IOCON_W_DSPL);
|
||||
if (host->top_base != NULL)
|
||||
sdr_set_field(host->top_base + EMMC_TOP_CONTROL,
|
||||
PAD_DAT_RD_RXDLY, 0);
|
||||
else
|
||||
sdr_set_field(host->base + tune_reg,
|
||||
MSDC_PAD_TUNE_DATRRDLY, 0);
|
||||
}
|
||||
} else {
|
||||
if (host->hs400_mode &&
|
||||
host->dev_comp->hs400_tune)
|
||||
ret = hs400_tune_response(mmc, opcode);
|
||||
else
|
||||
ret = msdc_tune_response(mmc, opcode);
|
||||
if (ret == -EIO) {
|
||||
dev_err(host->dev, "Tune response fail!\n");
|
||||
return ret;
|
||||
}
|
||||
if (host->hs400_mode == false) {
|
||||
ret = msdc_tune_data(mmc, opcode);
|
||||
if (ret == -EIO)
|
||||
dev_err(host->dev, "Tune data fail!\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
host->saved_tune_para.iocon = readl(host->base + MSDC_IOCON);
|
||||
host->saved_tune_para.pad_tune = readl(host->base + tune_reg);
|
||||
host->saved_tune_para.pad_cmd_tune = readl(host->base + PAD_CMD_TUNE);
|
||||
if (host->top_base != NULL) {
|
||||
host->saved_tune_para.emmc_top_control = readl(host->top_base +
|
||||
EMMC_TOP_CONTROL);
|
||||
host->saved_tune_para.emmc_top_cmd = readl(host->top_base +
|
||||
EMMC_TOP_CMD);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1800,7 +2088,11 @@ static int msdc_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||
struct msdc_host *host = mmc_priv(mmc);
|
||||
host->hs400_mode = true;
|
||||
|
||||
writel(host->hs400_ds_delay, host->base + PAD_DS_TUNE);
|
||||
if (host->top_base != NULL)
|
||||
writel(host->hs400_ds_delay,
|
||||
host->top_base + EMMC50_PAD_DS_TUNE);
|
||||
else
|
||||
writel(host->hs400_ds_delay, host->base + PAD_DS_TUNE);
|
||||
/* hs400 mode must set it to 0 */
|
||||
sdr_clr_bits(host->base + MSDC_PATCH_BIT2, MSDC_PATCH_BIT2_CFGCRCSTS);
|
||||
/* to improve read performance, set outstanding to 2 */
|
||||
@@ -1887,6 +2179,11 @@ static int msdc_drv_probe(struct platform_device *pdev)
|
||||
goto host_free;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
host->top_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(host->top_base))
|
||||
host->top_base = NULL;
|
||||
|
||||
ret = mmc_regulator_get_supply(mmc);
|
||||
if (ret)
|
||||
goto host_free;
|
||||
@@ -2061,6 +2358,15 @@ static void msdc_save_reg(struct msdc_host *host)
|
||||
host->save_para.emmc50_cfg0 = readl(host->base + EMMC50_CFG0);
|
||||
host->save_para.emmc50_cfg3 = readl(host->base + EMMC50_CFG3);
|
||||
host->save_para.sdc_fifo_cfg = readl(host->base + SDC_FIFO_CFG);
|
||||
if (host->top_base != NULL) {
|
||||
host->save_para.emmc_top_control =
|
||||
readl(host->top_base + EMMC_TOP_CONTROL);
|
||||
host->save_para.emmc_top_cmd =
|
||||
readl(host->top_base + EMMC_TOP_CMD);
|
||||
host->save_para.emmc50_pad_ds_tune =
|
||||
readl(host->top_base + EMMC50_PAD_DS_TUNE);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void msdc_restore_reg(struct msdc_host *host)
|
||||
@@ -2079,6 +2385,14 @@ static void msdc_restore_reg(struct msdc_host *host)
|
||||
writel(host->save_para.emmc50_cfg0, host->base + EMMC50_CFG0);
|
||||
writel(host->save_para.emmc50_cfg3, host->base + EMMC50_CFG3);
|
||||
writel(host->save_para.sdc_fifo_cfg, host->base + SDC_FIFO_CFG);
|
||||
if (host->top_base != NULL) {
|
||||
writel(host->save_para.emmc_top_control,
|
||||
host->top_base + EMMC_TOP_CONTROL);
|
||||
writel(host->save_para.emmc_top_cmd,
|
||||
host->top_base + EMMC_TOP_CMD);
|
||||
writel(host->save_para.emmc50_pad_ds_tune,
|
||||
host->top_base + EMMC50_PAD_DS_TUNE);
|
||||
}
|
||||
}
|
||||
|
||||
static int msdc_runtime_suspend(struct device *dev)
|
||||
|
||||
@@ -53,6 +53,17 @@ config PINCTRL_MT6397
|
||||
default MFD_MT6397
|
||||
select PINCTRL_MTK
|
||||
|
||||
# For pintcrl command debug
|
||||
config PINCTRL_MTK_DEBUG
|
||||
bool "Mediatek pin control common debug"
|
||||
depends on OF
|
||||
default ARM64 && ARCH_MEDIATEK
|
||||
select PINCTRL_MTK
|
||||
help
|
||||
Say yes here to enable support for MediaTek pinctrl debug command.
|
||||
It can provide gpio status debug shell command.
|
||||
We also can use these shell command to change gpio status.
|
||||
|
||||
endif
|
||||
|
||||
if !ARCH_MEDIATEK
|
||||
|
||||
@@ -855,9 +855,11 @@ static int mtk_pmx_set_mode(struct pinctrl_dev *pctldev,
|
||||
return mtk_pinctrl_set_gpio_mode(pctl, pin, mode);
|
||||
#endif
|
||||
|
||||
if (pctl->devdata->spec_pinmux_set)
|
||||
if (pctl->devdata->spec_pinmux_set) {
|
||||
pctl->devdata->spec_pinmux_set(mtk_get_regmap(pctl, pin),
|
||||
pin, mode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
reg_addr = ((pin / MAX_GPIO_MODE_PER_REG) << pctl->devdata->port_shf)
|
||||
+ pctl->devdata->pinmux_offset;
|
||||
|
||||
@@ -559,6 +559,15 @@ config REGULATOR_MT6323
|
||||
This driver supports the control of different power rails of device
|
||||
through regulator interface.
|
||||
|
||||
config REGULATOR_MT6358
|
||||
tristate "MediaTek MT6358 PMIC"
|
||||
depends on MFD_MT6397
|
||||
help
|
||||
Say y here to select this option to enable the power regulator of
|
||||
MediaTek MT6358 PMIC.
|
||||
This driver supports the control of different power rails of device
|
||||
through regulator interface.
|
||||
|
||||
config REGULATOR_MT6380
|
||||
tristate "MediaTek MT6380 PMIC"
|
||||
depends on MTK_PMIC_WRAP
|
||||
|
||||
@@ -73,6 +73,7 @@ obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o
|
||||
obj-$(CONFIG_REGULATOR_MT6311) += mt6311-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_MT6323) += mt6323-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_MT6358) += mt6358-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_MT6380) += mt6380-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o
|
||||
|
||||
495
drivers/regulator/mt6358-regulator.c
Normal file
495
drivers/regulator/mt6358-regulator.c
Normal file
@@ -0,0 +1,495 @@
|
||||
/*
|
||||
* Copyright (c) 2018 MediaTek Inc.
|
||||
* Author: Hsin-Hsiung Wang <hsin-hsiung.wang@mediatek.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/mfd/mt6397/core.h>
|
||||
#include <linux/mfd/mt6358/registers.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
#include <linux/regulator/mt6358-regulator.h>
|
||||
#include <linux/regulator/of_regulator.h>
|
||||
|
||||
/*
|
||||
* MT6358 regulators' information
|
||||
*
|
||||
* @desc: standard fields of regulator description.
|
||||
* @qi: Mask for query enable signal status of regulators
|
||||
*/
|
||||
struct mt6358_regulator_info {
|
||||
struct regulator_desc desc;
|
||||
u32 status_reg;
|
||||
u32 qi;
|
||||
const u32 *index_table;
|
||||
unsigned int n_table;
|
||||
u32 vsel_shift;
|
||||
};
|
||||
|
||||
#define MT6358_BUCK(match, vreg, min, max, step, \
|
||||
volt_ranges, vosel_mask) \
|
||||
[MT6358_ID_##vreg] = { \
|
||||
.desc = { \
|
||||
.name = #vreg, \
|
||||
.of_match = of_match_ptr(match), \
|
||||
.ops = &mt6358_volt_range_ops, \
|
||||
.type = REGULATOR_VOLTAGE, \
|
||||
.id = MT6358_ID_##vreg, \
|
||||
.owner = THIS_MODULE, \
|
||||
.n_voltages = (max - min)/step + 1, \
|
||||
.linear_ranges = volt_ranges, \
|
||||
.n_linear_ranges = ARRAY_SIZE(volt_ranges), \
|
||||
.vsel_reg = MT6358_BUCK_##vreg##_ELR0, \
|
||||
.vsel_mask = vosel_mask, \
|
||||
.enable_reg = MT6358_BUCK_##vreg##_CON0, \
|
||||
.enable_mask = BIT(0), \
|
||||
}, \
|
||||
.status_reg = MT6358_BUCK_##vreg##_DBG1, \
|
||||
.qi = BIT(0), \
|
||||
}
|
||||
|
||||
#define MT6358_LDO(match, vreg, ldo_volt_table, ldo_index_table, enreg, \
|
||||
enbit, vosel, vosel_mask, vosel_shift) \
|
||||
[MT6358_ID_##vreg] = { \
|
||||
.desc = { \
|
||||
.name = #vreg, \
|
||||
.of_match = of_match_ptr(match), \
|
||||
.ops = &mt6358_volt_table_ops, \
|
||||
.type = REGULATOR_VOLTAGE, \
|
||||
.id = MT6358_ID_##vreg, \
|
||||
.owner = THIS_MODULE, \
|
||||
.n_voltages = ARRAY_SIZE(ldo_volt_table), \
|
||||
.volt_table = ldo_volt_table, \
|
||||
.vsel_reg = vosel, \
|
||||
.vsel_mask = vosel_mask, \
|
||||
.enable_reg = enreg, \
|
||||
.enable_mask = BIT(enbit), \
|
||||
}, \
|
||||
.status_reg = MT6358_LDO_##vreg##_CON1, \
|
||||
.qi = BIT(15), \
|
||||
.index_table = ldo_index_table, \
|
||||
.n_table = ARRAY_SIZE(ldo_index_table), \
|
||||
.vsel_shift = vosel_shift, \
|
||||
}
|
||||
|
||||
#define MT6358_LDO1(match, vreg, min, max, step, \
|
||||
volt_ranges, vosel, vosel_mask) \
|
||||
[MT6358_ID_##vreg] = { \
|
||||
.desc = { \
|
||||
.name = #vreg, \
|
||||
.of_match = of_match_ptr(match), \
|
||||
.ops = &mt6358_volt_range_ops, \
|
||||
.type = REGULATOR_VOLTAGE, \
|
||||
.id = MT6358_ID_##vreg, \
|
||||
.owner = THIS_MODULE, \
|
||||
.n_voltages = (max - min)/step + 1, \
|
||||
.linear_ranges = volt_ranges, \
|
||||
.n_linear_ranges = ARRAY_SIZE(volt_ranges), \
|
||||
.vsel_reg = vosel, \
|
||||
.vsel_mask = vosel_mask, \
|
||||
.enable_reg = MT6358_LDO_##vreg##_CON0, \
|
||||
.enable_mask = BIT(0), \
|
||||
}, \
|
||||
.status_reg = MT6358_LDO_##vreg##_DBG1, \
|
||||
.qi = BIT(0), \
|
||||
}
|
||||
|
||||
#define MT6358_REG_FIXED(match, vreg, enreg, enbit, volt) \
|
||||
[MT6358_ID_##vreg] = { \
|
||||
.desc = { \
|
||||
.name = #vreg, \
|
||||
.of_match = of_match_ptr(match), \
|
||||
.ops = &mt6358_volt_fixed_ops, \
|
||||
.type = REGULATOR_VOLTAGE, \
|
||||
.id = MT6358_ID_##vreg, \
|
||||
.owner = THIS_MODULE, \
|
||||
.n_voltages = 1, \
|
||||
.enable_reg = enreg, \
|
||||
.enable_mask = BIT(enbit), \
|
||||
.min_uV = volt, \
|
||||
}, \
|
||||
.status_reg = MT6358_LDO_##vreg##_CON1, \
|
||||
.qi = BIT(15), \
|
||||
}
|
||||
|
||||
static const struct regulator_linear_range buck_volt_range1[] = {
|
||||
REGULATOR_LINEAR_RANGE(500000, 0, 0x7f, 6250),
|
||||
};
|
||||
|
||||
static const struct regulator_linear_range buck_volt_range2[] = {
|
||||
REGULATOR_LINEAR_RANGE(500000, 0, 0x7f, 12500),
|
||||
};
|
||||
|
||||
static const struct regulator_linear_range buck_volt_range3[] = {
|
||||
REGULATOR_LINEAR_RANGE(500000, 0, 0x3f, 50000),
|
||||
};
|
||||
|
||||
static const struct regulator_linear_range buck_volt_range4[] = {
|
||||
REGULATOR_LINEAR_RANGE(1000000, 0, 0x7f, 12500),
|
||||
};
|
||||
|
||||
static const u32 vdram2_voltages[] = {
|
||||
600000, 1800000,
|
||||
};
|
||||
|
||||
static const u32 vsim1_voltages[] = {
|
||||
1700000, 1800000, 2700000, 3000000, 3100000,
|
||||
};
|
||||
|
||||
static const u32 vibr_voltages[] = {
|
||||
1200000, 1300000, 1500000, 1800000,
|
||||
2000000, 2800000, 3000000, 3300000,
|
||||
};
|
||||
|
||||
static const u32 vusb_voltages[] = {
|
||||
3000000, 3100000,
|
||||
};
|
||||
|
||||
static const u32 vcamd_voltages[] = {
|
||||
900000, 1000000, 1100000, 1200000,
|
||||
1300000, 1500000, 1800000,
|
||||
};
|
||||
|
||||
static const u32 vefuse_voltages[] = {
|
||||
1700000, 1800000, 1900000,
|
||||
};
|
||||
|
||||
static const u32 vmch_voltages[] = {
|
||||
2900000, 3000000, 3300000,
|
||||
};
|
||||
|
||||
static const u32 vcama1_voltages[] = {
|
||||
1800000, 2500000, 2700000,
|
||||
2800000, 2900000, 3000000,
|
||||
};
|
||||
|
||||
static const u32 vemc_voltages[] = {
|
||||
2900000, 3000000, 3300000,
|
||||
};
|
||||
|
||||
static const u32 vcn33_bt_voltages[] = {
|
||||
3300000, 3400000, 3500000,
|
||||
};
|
||||
|
||||
static const u32 vcn33_wifi_voltages[] = {
|
||||
3300000, 3400000, 3500000,
|
||||
};
|
||||
|
||||
static const u32 vcama2_voltages[] = {
|
||||
1800000, 2500000, 2700000,
|
||||
2800000, 2900000, 3000000,
|
||||
};
|
||||
|
||||
static const u32 vmc_voltages[] = {
|
||||
1800000, 2900000, 3000000, 3300000,
|
||||
};
|
||||
|
||||
static const u32 vldo28_voltages[] = {
|
||||
2800000, 3000000,
|
||||
};
|
||||
|
||||
static const u32 vsim2_voltages[] = {
|
||||
1700000, 1800000, 2700000,
|
||||
3000000, 3100000,
|
||||
};
|
||||
|
||||
static const u32 vdram2_idx[] = {
|
||||
0, 12,
|
||||
};
|
||||
|
||||
static const u32 vsim1_idx[] = {
|
||||
3, 4, 8, 11, 12,
|
||||
};
|
||||
|
||||
static const u32 vibr_idx[] = {
|
||||
0, 1, 2, 4, 5, 9, 11, 13,
|
||||
};
|
||||
|
||||
static const u32 vusb_idx[] = {
|
||||
3, 4,
|
||||
};
|
||||
|
||||
static const u32 vcamd_idx[] = {
|
||||
3, 4, 5, 6, 7, 9, 12,
|
||||
};
|
||||
|
||||
static const u32 vefuse_idx[] = {
|
||||
11, 12, 13,
|
||||
};
|
||||
|
||||
static const u32 vmch_idx[] = {
|
||||
2, 3, 5,
|
||||
};
|
||||
|
||||
static const u32 vcama1_idx[] = {
|
||||
0, 7, 9, 10, 11, 12,
|
||||
};
|
||||
|
||||
static const u32 vemc_idx[] = {
|
||||
2, 3, 5,
|
||||
};
|
||||
|
||||
static const u32 vcn33_bt_idx[] = {
|
||||
1, 2, 3,
|
||||
};
|
||||
|
||||
static const u32 vcn33_wifi_idx[] = {
|
||||
1, 2, 3,
|
||||
};
|
||||
|
||||
static const u32 vcama2_idx[] = {
|
||||
0, 7, 9, 10, 11, 12,
|
||||
};
|
||||
|
||||
static const u32 vmc_idx[] = {
|
||||
4, 10, 11, 13,
|
||||
};
|
||||
|
||||
static const u32 vldo28_idx[] = {
|
||||
1, 3,
|
||||
};
|
||||
|
||||
static const u32 vsim2_idx[] = {
|
||||
3, 4, 8, 11, 12,
|
||||
};
|
||||
|
||||
static int mt6358_set_voltage_sel(
|
||||
struct regulator_dev *rdev, unsigned int selector)
|
||||
{
|
||||
int idx, ret;
|
||||
const u32 *pVoltidx;
|
||||
struct mt6358_regulator_info *info = rdev_get_drvdata(rdev);
|
||||
|
||||
pVoltidx = (const u32 *)info->index_table;
|
||||
|
||||
idx = pVoltidx[selector];
|
||||
ret = regmap_update_bits(rdev->regmap, info->desc.vsel_reg,
|
||||
info->desc.vsel_mask, idx << info->vsel_shift);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mt6358_get_voltage_sel(struct regulator_dev *rdev)
|
||||
{
|
||||
int idx, ret;
|
||||
u32 selector;
|
||||
struct mt6358_regulator_info *info = rdev_get_drvdata(rdev);
|
||||
const u32 *pVoltidx;
|
||||
|
||||
ret = regmap_read(rdev->regmap, info->desc.vsel_reg, &selector);
|
||||
if (ret != 0) {
|
||||
dev_info(&rdev->dev,
|
||||
"Failed to get mt6358 %s vsel reg: %d\n",
|
||||
info->desc.name, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
selector = (selector & info->desc.vsel_mask) >> info->vsel_shift;
|
||||
pVoltidx = (const u32 *)info->index_table;
|
||||
ret = -1;
|
||||
for (idx = 0; idx < info->desc.n_voltages; idx++) {
|
||||
if (pVoltidx[idx] == selector) {
|
||||
ret = idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mt6358_get_status(struct regulator_dev *rdev)
|
||||
{
|
||||
int ret;
|
||||
u32 regval;
|
||||
struct mt6358_regulator_info *info = rdev_get_drvdata(rdev);
|
||||
|
||||
ret = regmap_read(rdev->regmap, info->status_reg, ®val);
|
||||
if (ret != 0) {
|
||||
dev_info(&rdev->dev, "Failed to get enable reg: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return (regval & info->qi) ? REGULATOR_STATUS_ON : REGULATOR_STATUS_OFF;
|
||||
}
|
||||
|
||||
static const struct regulator_ops mt6358_volt_range_ops = {
|
||||
.list_voltage = regulator_list_voltage_linear_range,
|
||||
.map_voltage = regulator_map_voltage_linear_range,
|
||||
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||
.set_voltage_time_sel = regulator_set_voltage_time_sel,
|
||||
.enable = regulator_enable_regmap,
|
||||
.disable = regulator_disable_regmap,
|
||||
.is_enabled = regulator_is_enabled_regmap,
|
||||
.get_status = mt6358_get_status,
|
||||
};
|
||||
|
||||
static const struct regulator_ops mt6358_volt_table_ops = {
|
||||
.list_voltage = regulator_list_voltage_table,
|
||||
.map_voltage = regulator_map_voltage_iterate,
|
||||
.set_voltage_sel = mt6358_set_voltage_sel,
|
||||
.get_voltage_sel = mt6358_get_voltage_sel,
|
||||
.set_voltage_time_sel = regulator_set_voltage_time_sel,
|
||||
.enable = regulator_enable_regmap,
|
||||
.disable = regulator_disable_regmap,
|
||||
.is_enabled = regulator_is_enabled_regmap,
|
||||
.get_status = mt6358_get_status,
|
||||
};
|
||||
|
||||
static const struct regulator_ops mt6358_volt_fixed_ops = {
|
||||
.list_voltage = regulator_list_voltage_linear,
|
||||
.enable = regulator_enable_regmap,
|
||||
.disable = regulator_disable_regmap,
|
||||
.is_enabled = regulator_is_enabled_regmap,
|
||||
.get_status = mt6358_get_status,
|
||||
};
|
||||
|
||||
/* The array is indexed by id(MT6358_ID_XXX) */
|
||||
static struct mt6358_regulator_info mt6358_regulators[] = {
|
||||
MT6358_BUCK("buck_vdram1", VDRAM1, 500000, 2087500, 12500,
|
||||
buck_volt_range2, 0x7f),
|
||||
MT6358_BUCK("buck_vcore", VCORE, 500000, 1293750, 6250,
|
||||
buck_volt_range1, 0x7f),
|
||||
MT6358_BUCK("buck_vpa", VPA, 500000, 3650000, 50000,
|
||||
buck_volt_range3, 0x3f),
|
||||
MT6358_BUCK("buck_vproc11", VPROC11, 500000, 1293750, 6250,
|
||||
buck_volt_range1, 0x7f),
|
||||
MT6358_BUCK("buck_vproc12", VPROC12, 500000, 1293750, 6250,
|
||||
buck_volt_range1, 0x7f),
|
||||
MT6358_BUCK("buck_vgpu", VGPU, 500000, 1293750, 6250,
|
||||
buck_volt_range1, 0x7f),
|
||||
MT6358_BUCK("buck_vs2", VS2, 500000, 2087500, 12500,
|
||||
buck_volt_range2, 0x7f),
|
||||
MT6358_BUCK("buck_vmodem", VMODEM, 500000, 1293750, 6250,
|
||||
buck_volt_range1, 0x7f),
|
||||
MT6358_BUCK("buck_vs1", VS1, 1000000, 2587500, 12500,
|
||||
buck_volt_range4, 0x7f),
|
||||
MT6358_REG_FIXED("ldo_vrf12", VRF12,
|
||||
MT6358_LDO_VRF12_CON0, 0, 1200000),
|
||||
MT6358_REG_FIXED("ldo_vio18", VIO18,
|
||||
MT6358_LDO_VIO18_CON0, 0, 1800000),
|
||||
MT6358_REG_FIXED("ldo_vcamio", VCAMIO,
|
||||
MT6358_LDO_VCAMIO_CON0, 0, 1800000),
|
||||
MT6358_REG_FIXED("ldo_vcn18", VCN18, MT6358_LDO_VCN18_CON0, 0, 1800000),
|
||||
MT6358_REG_FIXED("ldo_vfe28", VFE28, MT6358_LDO_VFE28_CON0, 0, 2800000),
|
||||
MT6358_REG_FIXED("ldo_vcn28", VCN28, MT6358_LDO_VCN28_CON0, 0, 2800000),
|
||||
MT6358_REG_FIXED("ldo_vxo22", VXO22, MT6358_LDO_VXO22_CON0, 0, 2200000),
|
||||
MT6358_REG_FIXED("ldo_vaux18", VAUX18,
|
||||
MT6358_LDO_VAUX18_CON0, 0, 1800000),
|
||||
MT6358_REG_FIXED("ldo_vbif28", VBIF28,
|
||||
MT6358_LDO_VBIF28_CON0, 0, 2800000),
|
||||
MT6358_REG_FIXED("ldo_vio28", VIO28, MT6358_LDO_VIO28_CON0, 0, 2800000),
|
||||
MT6358_REG_FIXED("ldo_va12", VA12, MT6358_LDO_VA12_CON0, 0, 1200000),
|
||||
MT6358_REG_FIXED("ldo_vrf18", VRF18, MT6358_LDO_VRF18_CON0, 0, 1800000),
|
||||
MT6358_REG_FIXED("ldo_vaud28", VAUD28,
|
||||
MT6358_LDO_VAUD28_CON0, 0, 2800000),
|
||||
MT6358_LDO("ldo_vdram2", VDRAM2, vdram2_voltages, vdram2_idx,
|
||||
MT6358_LDO_VDRAM2_CON0, 0, MT6358_LDO_VDRAM2_ELR0, 0x10, 0),
|
||||
MT6358_LDO("ldo_vsim1", VSIM1, vsim1_voltages, vsim1_idx,
|
||||
MT6358_LDO_VSIM1_CON0, 0, MT6358_VSIM1_ANA_CON0, 0xf00, 8),
|
||||
MT6358_LDO("ldo_vibr", VIBR, vibr_voltages, vibr_idx,
|
||||
MT6358_LDO_VIBR_CON0, 0, MT6358_VIBR_ANA_CON0, 0xf00, 8),
|
||||
MT6358_LDO("ldo_vusb", VUSB, vusb_voltages, vusb_idx,
|
||||
MT6358_LDO_VUSB_CON0_0, 0, MT6358_VUSB_ANA_CON0, 0x700, 8),
|
||||
MT6358_LDO("ldo_vcamd", VCAMD, vcamd_voltages, vcamd_idx,
|
||||
MT6358_LDO_VCAMD_CON0, 0, MT6358_VCAMD_ANA_CON0, 0xf00, 8),
|
||||
MT6358_LDO("ldo_vefuse", VEFUSE, vefuse_voltages, vefuse_idx,
|
||||
MT6358_LDO_VEFUSE_CON0, 0, MT6358_VEFUSE_ANA_CON0, 0xf00, 8),
|
||||
MT6358_LDO("ldo_vmch", VMCH, vmch_voltages, vmch_idx,
|
||||
MT6358_LDO_VMCH_CON0, 0, MT6358_VMCH_ANA_CON0, 0x700, 8),
|
||||
MT6358_LDO("ldo_vcama1", VCAMA1, vcama1_voltages, vcama1_idx,
|
||||
MT6358_LDO_VCAMA1_CON0, 0, MT6358_VCAMA1_ANA_CON0, 0xf00, 8),
|
||||
MT6358_LDO("ldo_vemc", VEMC, vemc_voltages, vemc_idx,
|
||||
MT6358_LDO_VEMC_CON0, 0, MT6358_VEMC_ANA_CON0, 0x700, 8),
|
||||
MT6358_LDO("ldo_vcn33_bt", VCN33_BT, vcn33_bt_voltages, vcn33_bt_idx,
|
||||
MT6358_LDO_VCN33_CON0_0, 0, MT6358_VCN33_ANA_CON0, 0x300, 8),
|
||||
MT6358_LDO("ldo_vcn33_wifi", VCN33_WIFI, vcn33_wifi_voltages,
|
||||
vcn33_wifi_idx, MT6358_LDO_VCN33_CON0_1,
|
||||
0, MT6358_VCN33_ANA_CON0, 0x300, 8),
|
||||
MT6358_LDO("ldo_vcama2", VCAMA2, vcama2_voltages, vcama2_idx,
|
||||
MT6358_LDO_VCAMA2_CON0, 0, MT6358_VCAMA2_ANA_CON0, 0xf00, 8),
|
||||
MT6358_LDO("ldo_vmc", VMC, vmc_voltages, vmc_idx,
|
||||
MT6358_LDO_VMC_CON0, 0, MT6358_VMC_ANA_CON0, 0xf00, 8),
|
||||
MT6358_LDO("ldo_vldo28", VLDO28, vldo28_voltages, vldo28_idx,
|
||||
MT6358_LDO_VLDO28_CON0_0, 0, MT6358_VLDO28_ANA_CON0, 0x300, 8),
|
||||
MT6358_LDO("ldo_vsim2", VSIM2, vsim2_voltages, vsim2_idx,
|
||||
MT6358_LDO_VSIM2_CON0, 0, MT6358_VSIM2_ANA_CON0, 0xf00, 8),
|
||||
MT6358_LDO1("ldo_vsram_proc11", VSRAM_PROC11, 500000, 1293750, 6250,
|
||||
buck_volt_range1, MT6358_LDO_VSRAM_CON0, 0x7f),
|
||||
MT6358_LDO1("ldo_vsram_others", VSRAM_OTHERS, 500000, 1293750, 6250,
|
||||
buck_volt_range1, MT6358_LDO_VSRAM_CON2, 0x7f),
|
||||
MT6358_LDO1("ldo_vsram_gpu", VSRAM_GPU, 500000, 1293750, 6250,
|
||||
buck_volt_range1, MT6358_LDO_VSRAM_CON3, 0x7f),
|
||||
MT6358_LDO1("ldo_vsram_proc12", VSRAM_PROC12, 500000, 1293750, 6250,
|
||||
buck_volt_range1, MT6358_LDO_VSRAM_CON1, 0x7f),
|
||||
};
|
||||
|
||||
static int mt6358_regulator_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct mt6397_chip *mt6397 = dev_get_drvdata(pdev->dev.parent);
|
||||
struct regulator_config config = {};
|
||||
struct regulator_dev *rdev;
|
||||
int i;
|
||||
u32 reg_value;
|
||||
|
||||
/* Read PMIC chip revision to update constraints and voltage table */
|
||||
if (regmap_read(mt6397->regmap, MT6358_SWCID, ®_value) < 0) {
|
||||
dev_err(&pdev->dev, "Failed to read Chip ID\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
for (i = 0; i < MT6358_MAX_REGULATOR; i++) {
|
||||
config.dev = &pdev->dev;
|
||||
config.driver_data = &mt6358_regulators[i];
|
||||
config.regmap = mt6397->regmap;
|
||||
|
||||
rdev = devm_regulator_register(&pdev->dev,
|
||||
&mt6358_regulators[i].desc, &config);
|
||||
if (IS_ERR(rdev)) {
|
||||
dev_err(&pdev->dev, "failed to register %s\n",
|
||||
mt6358_regulators[i].desc.name);
|
||||
return PTR_ERR(rdev);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct platform_device_id mt6358_platform_ids[] = {
|
||||
{"mt6358-regulator", 0},
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, mt6358_platform_ids);
|
||||
|
||||
static const struct of_device_id mt6358_of_match[] = {
|
||||
{ .compatible = "mediatek,mt6358-regulator", },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mt6358_of_match);
|
||||
|
||||
static struct platform_driver mt6358_regulator_driver = {
|
||||
.driver = {
|
||||
.name = "mt6358-regulator",
|
||||
.of_match_table = of_match_ptr(mt6358_of_match),
|
||||
},
|
||||
.probe = mt6358_regulator_probe,
|
||||
.id_table = mt6358_platform_ids,
|
||||
};
|
||||
|
||||
module_platform_driver(mt6358_regulator_driver);
|
||||
|
||||
MODULE_AUTHOR("Hsin-Hsiung Wang <hsin-hsiung.wang@mediatek.com>");
|
||||
MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6358 PMIC");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -322,10 +322,9 @@ static int mtk_rtc_probe(struct platform_device *pdev)
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
rtc->addr_base = res->start;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
rtc->irq = irq_create_mapping(mt6397_chip->irq_domain, res->start);
|
||||
if (rtc->irq <= 0)
|
||||
return -EINVAL;
|
||||
rtc->irq = platform_get_irq(pdev, 0);
|
||||
if (rtc->irq < 0)
|
||||
return rtc->irq;
|
||||
|
||||
rtc->regmap = mt6397_chip->regmap;
|
||||
rtc->dev = &pdev->dev;
|
||||
|
||||
@@ -10,6 +10,18 @@ config MTK_INFRACFG
|
||||
INFRACFG controller contains various infrastructure registers not
|
||||
directly associated to any device.
|
||||
|
||||
config MTK_CMDQ
|
||||
tristate "MediaTek CMDQ Support"
|
||||
depends on ARCH_MEDIATEK || COMPILE_TEST
|
||||
select MAILBOX
|
||||
select MTK_CMDQ_MBOX
|
||||
select MTK_INFRACFG
|
||||
help
|
||||
Say yes here to add support for the MediaTek Command Queue (CMDQ)
|
||||
driver. The CMDQ is used to help read/write registers with critical
|
||||
time limitation, such as updating display configuration during the
|
||||
vblank.
|
||||
|
||||
config MTK_PMIC_WRAP
|
||||
tristate "MediaTek PMIC Wrapper Support"
|
||||
select REGMAP
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
obj-$(CONFIG_MTK_CMDQ) += mtk-cmdq-helper.o
|
||||
obj-$(CONFIG_MTK_INFRACFG) += mtk-infracfg.o
|
||||
obj-$(CONFIG_MTK_PMIC_WRAP) += mtk-pmic-wrap.o
|
||||
obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <dt-bindings/power/mt6797-power.h>
|
||||
#include <dt-bindings/power/mt7622-power.h>
|
||||
#include <dt-bindings/power/mt8173-power.h>
|
||||
#include <dt-bindings/power/mt8183-power.h>
|
||||
|
||||
#define SPM_VDE_PWR_CON 0x0210
|
||||
#define SPM_MFG_PWR_CON 0x0214
|
||||
@@ -84,6 +85,13 @@ enum clk_id {
|
||||
CLK_ETHIF,
|
||||
CLK_VDEC,
|
||||
CLK_HIFSEL,
|
||||
CLK_ISP,
|
||||
CLK_AUDIO,
|
||||
CLK_CAM,
|
||||
CLK_VPU,
|
||||
CLK_VPU1,
|
||||
CLK_VPU2,
|
||||
CLK_VPU3,
|
||||
CLK_MAX,
|
||||
};
|
||||
|
||||
@@ -96,6 +104,13 @@ static const char * const clk_names[] = {
|
||||
"ethif",
|
||||
"vdec",
|
||||
"hif_sel",
|
||||
"isp",
|
||||
"audio",
|
||||
"cam",
|
||||
"vpu",
|
||||
"vpu1",
|
||||
"vpu2",
|
||||
"vpu3",
|
||||
NULL,
|
||||
};
|
||||
|
||||
@@ -810,6 +825,147 @@ static const struct scp_subdomain scp_subdomain_mt8173[] = {
|
||||
{MT8173_POWER_DOMAIN_MFG_2D, MT8173_POWER_DOMAIN_MFG},
|
||||
};
|
||||
|
||||
/*
|
||||
* MT8183 power domain support
|
||||
*/
|
||||
|
||||
static const struct scp_domain_data scp_domain_data_mt8183[] = {
|
||||
[MT8183_POWER_DOMAIN_AUDIO] = {
|
||||
.name = "audio",
|
||||
.sta_mask = PWR_STATUS_AUDIO,
|
||||
.ctl_offs = 0x0314,
|
||||
.sram_pdn_bits = GENMASK(11, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(15, 12),
|
||||
.clk_id = {CLK_AUDIO},
|
||||
},
|
||||
[MT8183_POWER_DOMAIN_CONN] = {
|
||||
.name = "conn",
|
||||
.sta_mask = PWR_STATUS_CONN,
|
||||
.ctl_offs = 0x032c,
|
||||
.sram_pdn_bits = 0,
|
||||
.sram_pdn_ack_bits = 0,
|
||||
.clk_id = {CLK_NONE},
|
||||
},
|
||||
[MT8183_POWER_DOMAIN_MFG_ASYNC] = {
|
||||
.name = "mfg_async",
|
||||
.sta_mask = PWR_STATUS_MFG_ASYNC,
|
||||
.ctl_offs = 0x0334,
|
||||
.sram_pdn_bits = 0,
|
||||
.sram_pdn_ack_bits = 0,
|
||||
.clk_id = {CLK_MFG},
|
||||
},
|
||||
[MT8183_POWER_DOMAIN_MFG] = {
|
||||
.name = "mfg",
|
||||
.sta_mask = PWR_STATUS_MFG,
|
||||
.ctl_offs = 0x0338,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.clk_id = {CLK_NONE},
|
||||
},
|
||||
[MT8183_POWER_DOMAIN_MFG_CORE0] = {
|
||||
.name = "mfg_core0",
|
||||
.sta_mask = BIT(7),
|
||||
.ctl_offs = 0x034c,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.clk_id = {CLK_NONE},
|
||||
},
|
||||
[MT8183_POWER_DOMAIN_MFG_CORE1] = {
|
||||
.name = "mfg_core1",
|
||||
.sta_mask = BIT(20),
|
||||
.ctl_offs = 0x0310,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.clk_id = {CLK_NONE},
|
||||
},
|
||||
[MT8183_POWER_DOMAIN_MFG_2D] = {
|
||||
.name = "mfg_2d",
|
||||
.sta_mask = PWR_STATUS_MFG_2D,
|
||||
.ctl_offs = 0x0348,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.clk_id = {CLK_NONE},
|
||||
},
|
||||
[MT8183_POWER_DOMAIN_DISP] = {
|
||||
.name = "disp",
|
||||
.sta_mask = PWR_STATUS_DISP,
|
||||
.ctl_offs = 0x030c,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.clk_id = {CLK_MM},
|
||||
},
|
||||
[MT8183_POWER_DOMAIN_CAM] = {
|
||||
.name = "cam",
|
||||
.sta_mask = BIT(25),
|
||||
.ctl_offs = 0x0344,
|
||||
.sram_pdn_bits = GENMASK(9, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(13, 12),
|
||||
.clk_id = {CLK_CAM},
|
||||
},
|
||||
[MT8183_POWER_DOMAIN_ISP] = {
|
||||
.name = "isp",
|
||||
.sta_mask = PWR_STATUS_ISP,
|
||||
.ctl_offs = 0x0308,
|
||||
.sram_pdn_bits = GENMASK(9, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(13, 12),
|
||||
.clk_id = {CLK_ISP},
|
||||
},
|
||||
[MT8183_POWER_DOMAIN_VDEC] = {
|
||||
.name = "vdec",
|
||||
.sta_mask = BIT(31),
|
||||
.ctl_offs = 0x0300,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.clk_id = {CLK_NONE},
|
||||
},
|
||||
[MT8183_POWER_DOMAIN_VENC] = {
|
||||
.name = "venc",
|
||||
.sta_mask = PWR_STATUS_VENC,
|
||||
.ctl_offs = 0x0304,
|
||||
.sram_pdn_bits = GENMASK(11, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(15, 12),
|
||||
.clk_id = {CLK_NONE},
|
||||
},
|
||||
[MT8183_POWER_DOMAIN_VPU_TOP] = {
|
||||
.name = "vpu_top",
|
||||
.sta_mask = BIT(26),
|
||||
.ctl_offs = 0x0324,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.clk_id = {CLK_VPU, CLK_VPU1},
|
||||
},
|
||||
[MT8183_POWER_DOMAIN_VPU_CORE0] = {
|
||||
.name = "vpu_core0",
|
||||
.sta_mask = BIT(27),
|
||||
.ctl_offs = 0x33c,
|
||||
.sram_pdn_bits = GENMASK(11, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(13, 12),
|
||||
.clk_id = {CLK_VPU2},
|
||||
},
|
||||
[MT8183_POWER_DOMAIN_VPU_CORE1] = {
|
||||
.name = "vpu_core1",
|
||||
.sta_mask = BIT(28),
|
||||
.ctl_offs = 0x0340,
|
||||
.sram_pdn_bits = GENMASK(11, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(13, 12),
|
||||
.clk_id = {CLK_VPU3},
|
||||
},
|
||||
};
|
||||
|
||||
static const struct scp_subdomain scp_subdomain_mt8183[] = {
|
||||
{MT8183_POWER_DOMAIN_MFG_ASYNC, MT8183_POWER_DOMAIN_MFG},
|
||||
{MT8183_POWER_DOMAIN_MFG, MT8183_POWER_DOMAIN_MFG_2D},
|
||||
{MT8183_POWER_DOMAIN_MFG, MT8183_POWER_DOMAIN_MFG_CORE0},
|
||||
{MT8183_POWER_DOMAIN_MFG, MT8183_POWER_DOMAIN_MFG_CORE1},
|
||||
{MT8183_POWER_DOMAIN_DISP, MT8183_POWER_DOMAIN_CAM},
|
||||
{MT8183_POWER_DOMAIN_DISP, MT8183_POWER_DOMAIN_ISP},
|
||||
{MT8183_POWER_DOMAIN_DISP, MT8183_POWER_DOMAIN_VDEC},
|
||||
{MT8183_POWER_DOMAIN_DISP, MT8183_POWER_DOMAIN_VENC},
|
||||
{MT8183_POWER_DOMAIN_DISP, MT8183_POWER_DOMAIN_VPU_TOP},
|
||||
{MT8183_POWER_DOMAIN_VPU_TOP, MT8183_POWER_DOMAIN_VPU_CORE0},
|
||||
{MT8183_POWER_DOMAIN_VPU_TOP, MT8183_POWER_DOMAIN_VPU_CORE1},
|
||||
};
|
||||
|
||||
static const struct scp_soc_data mt2701_data = {
|
||||
.domains = scp_domain_data_mt2701,
|
||||
.num_domains = ARRAY_SIZE(scp_domain_data_mt2701),
|
||||
@@ -850,6 +1006,17 @@ static const struct scp_soc_data mt8173_data = {
|
||||
}
|
||||
};
|
||||
|
||||
static const struct scp_soc_data mt8183_data = {
|
||||
.domains = scp_domain_data_mt8183,
|
||||
.num_domains = ARRAY_SIZE(scp_domain_data_mt8183),
|
||||
.subdomains = scp_subdomain_mt8183,
|
||||
.num_subdomains = ARRAY_SIZE(scp_subdomain_mt8183),
|
||||
.regs = {
|
||||
.pwr_sta_offs = 0x0180,
|
||||
.pwr_sta2nd_offs = 0x0184
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* scpsys driver init
|
||||
*/
|
||||
@@ -867,6 +1034,9 @@ static const struct of_device_id of_scpsys_match_tbl[] = {
|
||||
}, {
|
||||
.compatible = "mediatek,mt8173-scpsys",
|
||||
.data = &mt8173_data,
|
||||
}, {
|
||||
.compatible = "mediatek,mt8183-scpsys",
|
||||
.data = &mt8183_data,
|
||||
}, {
|
||||
/* sentinel */
|
||||
}
|
||||
@@ -874,15 +1044,13 @@ static const struct of_device_id of_scpsys_match_tbl[] = {
|
||||
|
||||
static int scpsys_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct of_device_id *match;
|
||||
const struct scp_subdomain *sd;
|
||||
const struct scp_soc_data *soc;
|
||||
struct scp *scp;
|
||||
struct genpd_onecell_data *pd_data;
|
||||
int i, ret;
|
||||
|
||||
match = of_match_device(of_scpsys_match_tbl, &pdev->dev);
|
||||
soc = (const struct scp_soc_data *)match->data;
|
||||
soc = of_device_get_match_data(&pdev->dev);
|
||||
|
||||
scp = init_scp(pdev, soc->domains, soc->num_domains, &soc->regs);
|
||||
if (IS_ERR(scp))
|
||||
|
||||
48
include/dt-bindings/gce/mt8173-gce.h
Normal file
48
include/dt-bindings/gce/mt8173-gce.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2018 MediaTek Inc.
|
||||
* Author: Houlong Wei <houlong.wei@mediatek.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _DT_BINDINGS_GCE_MT8173_H
|
||||
#define _DT_BINDINGS_GCE_MT8173_H
|
||||
|
||||
#define CMDQ_NO_TIMEOUT 0xffffffff
|
||||
|
||||
#define CMDQ_THR_MAX_COUNT 16
|
||||
|
||||
/* GCE HW thread priority */
|
||||
#define CMDQ_THR_PRIO_LOWEST 0
|
||||
#define CMDQ_THR_PRIO_HIGHEST 1
|
||||
|
||||
/* GCE SUBSYS */
|
||||
#define SUBSYS_1400XXXX 1
|
||||
#define SUBSYS_1401XXXX 2
|
||||
#define SUBSYS_1402XXXX 3
|
||||
|
||||
/* GCE HW EVENT */
|
||||
#define CMDQ_EVENT_DISP_OVL0_SOF 11
|
||||
#define CMDQ_EVENT_DISP_OVL1_SOF 12
|
||||
#define CMDQ_EVENT_DISP_RDMA0_SOF 13
|
||||
#define CMDQ_EVENT_DISP_RDMA1_SOF 14
|
||||
#define CMDQ_EVENT_DISP_RDMA2_SOF 15
|
||||
#define CMDQ_EVENT_DISP_WDMA0_SOF 16
|
||||
#define CMDQ_EVENT_DISP_WDMA1_SOF 17
|
||||
#define CMDQ_EVENT_DISP_OVL0_EOF 39
|
||||
#define CMDQ_EVENT_DISP_OVL1_EOF 40
|
||||
#define CMDQ_EVENT_DISP_RDMA0_EOF 41
|
||||
#define CMDQ_EVENT_DISP_RDMA1_EOF 42
|
||||
#define CMDQ_EVENT_DISP_RDMA2_EOF 43
|
||||
#define CMDQ_EVENT_DISP_WDMA0_EOF 44
|
||||
#define CMDQ_EVENT_DISP_WDMA1_EOF 45
|
||||
#define CMDQ_EVENT_MUTEX0_STREAM_EOF 53
|
||||
#define CMDQ_EVENT_MUTEX1_STREAM_EOF 54
|
||||
#define CMDQ_EVENT_MUTEX2_STREAM_EOF 55
|
||||
#define CMDQ_EVENT_MUTEX3_STREAM_EOF 56
|
||||
#define CMDQ_EVENT_MUTEX4_STREAM_EOF 57
|
||||
#define CMDQ_EVENT_DISP_RDMA0_UNDERRUN 63
|
||||
#define CMDQ_EVENT_DISP_RDMA1_UNDERRUN 64
|
||||
#define CMDQ_EVENT_DISP_RDMA2_UNDERRUN 65
|
||||
|
||||
#endif
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _DT_BINDINGS_POWER_MT8183_POWER_H
|
||||
#define _DT_BINDINGS_POWER_MT8183_POWER_H
|
||||
#ifndef _DT_BINDINGS_POWER_MT8173_POWER_H
|
||||
#define _DT_BINDINGS_POWER_MT8173_POWER_H
|
||||
|
||||
#define MT8173_POWER_DOMAIN_VDEC 0
|
||||
#define MT8173_POWER_DOMAIN_VENC 1
|
||||
@@ -13,4 +13,4 @@
|
||||
#define MT8173_POWER_DOMAIN_MFG_2D 8
|
||||
#define MT8173_POWER_DOMAIN_MFG 9
|
||||
|
||||
#endif /* _DT_BINDINGS_POWER_MT8183_POWER_H */
|
||||
#endif /* _DT_BINDINGS_POWER_MT8173_POWER_H */
|
||||
|
||||
33
include/dt-bindings/power/mt8183-power.h
Normal file
33
include/dt-bindings/power/mt8183-power.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2018 MediaTek Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See http://www.gnu.org/licenses/gpl-2.0.html for more details.
|
||||
*/
|
||||
|
||||
#ifndef _DT_BINDINGS_POWER_MT8183_POWER_H
|
||||
#define _DT_BINDINGS_POWER_MT8183_POWER_H
|
||||
|
||||
#define MT8183_POWER_DOMAIN_AUDIO 0
|
||||
#define MT8183_POWER_DOMAIN_CONN 1
|
||||
#define MT8183_POWER_DOMAIN_MFG_ASYNC 2
|
||||
#define MT8183_POWER_DOMAIN_MFG 3
|
||||
#define MT8183_POWER_DOMAIN_MFG_CORE0 4
|
||||
#define MT8183_POWER_DOMAIN_MFG_CORE1 5
|
||||
#define MT8183_POWER_DOMAIN_MFG_2D 6
|
||||
#define MT8183_POWER_DOMAIN_DISP 7
|
||||
#define MT8183_POWER_DOMAIN_CAM 8
|
||||
#define MT8183_POWER_DOMAIN_ISP 9
|
||||
#define MT8183_POWER_DOMAIN_VDEC 10
|
||||
#define MT8183_POWER_DOMAIN_VENC 11
|
||||
#define MT8183_POWER_DOMAIN_VPU_TOP 12
|
||||
#define MT8183_POWER_DOMAIN_VPU_CORE0 13
|
||||
#define MT8183_POWER_DOMAIN_VPU_CORE1 14
|
||||
|
||||
#endif /* _DT_BINDINGS_POWER_MT8183_POWER_H */
|
||||
1935
include/linux/mfd/mt6358/registers.h
Normal file
1935
include/linux/mfd/mt6358/registers.h
Normal file
File diff suppressed because it is too large
Load Diff
65
include/linux/regulator/mt6358-regulator.h
Normal file
65
include/linux/regulator/mt6358-regulator.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2018 MediaTek Inc.
|
||||
* Author: Hsin-Hsiung Wang <hsin-hsiung.wang@mediatek.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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 __LINUX_REGULATOR_MT6358_H
|
||||
#define __LINUX_REGULATOR_MT6358_H
|
||||
|
||||
enum {
|
||||
MT6358_ID_VDRAM1 = 0,
|
||||
MT6358_ID_VCORE,
|
||||
MT6358_ID_VPA,
|
||||
MT6358_ID_VPROC11,
|
||||
MT6358_ID_VPROC12,
|
||||
MT6358_ID_VGPU,
|
||||
MT6358_ID_VS2,
|
||||
MT6358_ID_VMODEM,
|
||||
MT6358_ID_VS1,
|
||||
MT6358_ID_VDRAM2 = 9,
|
||||
MT6358_ID_VSIM1,
|
||||
MT6358_ID_VIBR,
|
||||
MT6358_ID_VRF12,
|
||||
MT6358_ID_VIO18,
|
||||
MT6358_ID_VUSB,
|
||||
MT6358_ID_VCAMIO,
|
||||
MT6358_ID_VCAMD,
|
||||
MT6358_ID_VCN18,
|
||||
MT6358_ID_VFE28,
|
||||
MT6358_ID_VSRAM_PROC11,
|
||||
MT6358_ID_VCN28,
|
||||
MT6358_ID_VSRAM_OTHERS,
|
||||
MT6358_ID_VSRAM_GPU,
|
||||
MT6358_ID_VXO22,
|
||||
MT6358_ID_VEFUSE,
|
||||
MT6358_ID_VAUX18,
|
||||
MT6358_ID_VMCH,
|
||||
MT6358_ID_VBIF28,
|
||||
MT6358_ID_VSRAM_PROC12,
|
||||
MT6358_ID_VCAMA1,
|
||||
MT6358_ID_VEMC,
|
||||
MT6358_ID_VIO28,
|
||||
MT6358_ID_VA12,
|
||||
MT6358_ID_VRF18,
|
||||
MT6358_ID_VCN33_BT,
|
||||
MT6358_ID_VCN33_WIFI,
|
||||
MT6358_ID_VCAMA2,
|
||||
MT6358_ID_VMC,
|
||||
MT6358_ID_VLDO28,
|
||||
MT6358_ID_VAUD28,
|
||||
MT6358_ID_VSIM2,
|
||||
MT6358_ID_RG_MAX,
|
||||
};
|
||||
|
||||
#define MT6358_MAX_REGULATOR MT6358_ID_RG_MAX
|
||||
|
||||
#endif /* __LINUX_REGULATOR_MT6358_H */
|
||||
Reference in New Issue
Block a user