162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR MIT 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Renesas UFS host controller driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2022 Renesas Electronics Corporation 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/clk.h> 962306a36Sopenharmony_ci#include <linux/delay.h> 1062306a36Sopenharmony_ci#include <linux/err.h> 1162306a36Sopenharmony_ci#include <linux/iopoll.h> 1262306a36Sopenharmony_ci#include <linux/kernel.h> 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci#include <linux/of.h> 1562306a36Sopenharmony_ci#include <linux/platform_device.h> 1662306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1762306a36Sopenharmony_ci#include <ufs/ufshcd.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include "ufshcd-pltfrm.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistruct ufs_renesas_priv { 2262306a36Sopenharmony_ci bool initialized; /* The hardware needs initialization once */ 2362306a36Sopenharmony_ci}; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cienum { 2662306a36Sopenharmony_ci SET_PHY_INDEX_LO = 0, 2762306a36Sopenharmony_ci SET_PHY_INDEX_HI, 2862306a36Sopenharmony_ci TIMER_INDEX, 2962306a36Sopenharmony_ci MAX_INDEX 3062306a36Sopenharmony_ci}; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cienum ufs_renesas_init_param_mode { 3362306a36Sopenharmony_ci MODE_RESTORE, 3462306a36Sopenharmony_ci MODE_SET, 3562306a36Sopenharmony_ci MODE_SAVE, 3662306a36Sopenharmony_ci MODE_POLL, 3762306a36Sopenharmony_ci MODE_WAIT, 3862306a36Sopenharmony_ci MODE_WRITE, 3962306a36Sopenharmony_ci}; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#define PARAM_RESTORE(_reg, _index) \ 4262306a36Sopenharmony_ci { .mode = MODE_RESTORE, .reg = _reg, .index = _index } 4362306a36Sopenharmony_ci#define PARAM_SET(_index, _set) \ 4462306a36Sopenharmony_ci { .mode = MODE_SET, .index = _index, .u.set = _set } 4562306a36Sopenharmony_ci#define PARAM_SAVE(_reg, _mask, _index) \ 4662306a36Sopenharmony_ci { .mode = MODE_SAVE, .reg = _reg, .mask = (u32)(_mask), \ 4762306a36Sopenharmony_ci .index = _index } 4862306a36Sopenharmony_ci#define PARAM_POLL(_reg, _expected, _mask) \ 4962306a36Sopenharmony_ci { .mode = MODE_POLL, .reg = _reg, .u.expected = _expected, \ 5062306a36Sopenharmony_ci .mask = (u32)(_mask) } 5162306a36Sopenharmony_ci#define PARAM_WAIT(_delay_us) \ 5262306a36Sopenharmony_ci { .mode = MODE_WAIT, .u.delay_us = _delay_us } 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci#define PARAM_WRITE(_reg, _val) \ 5562306a36Sopenharmony_ci { .mode = MODE_WRITE, .reg = _reg, .u.val = _val } 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci#define PARAM_WRITE_D0_D4(_d0, _d4) \ 5862306a36Sopenharmony_ci PARAM_WRITE(0xd0, _d0), PARAM_WRITE(0xd4, _d4) 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#define PARAM_WRITE_800_80C_POLL(_addr, _data_800) \ 6162306a36Sopenharmony_ci PARAM_WRITE_D0_D4(0x0000080c, 0x00000100), \ 6262306a36Sopenharmony_ci PARAM_WRITE_D0_D4(0x00000800, ((_data_800) << 16) | BIT(8) | (_addr)), \ 6362306a36Sopenharmony_ci PARAM_WRITE(0xd0, 0x0000080c), \ 6462306a36Sopenharmony_ci PARAM_POLL(0xd4, BIT(8), BIT(8)) 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci#define PARAM_RESTORE_800_80C_POLL(_index) \ 6762306a36Sopenharmony_ci PARAM_WRITE_D0_D4(0x0000080c, 0x00000100), \ 6862306a36Sopenharmony_ci PARAM_WRITE(0xd0, 0x00000800), \ 6962306a36Sopenharmony_ci PARAM_RESTORE(0xd4, _index), \ 7062306a36Sopenharmony_ci PARAM_WRITE(0xd0, 0x0000080c), \ 7162306a36Sopenharmony_ci PARAM_POLL(0xd4, BIT(8), BIT(8)) 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci#define PARAM_WRITE_804_80C_POLL(_addr, _data_804) \ 7462306a36Sopenharmony_ci PARAM_WRITE_D0_D4(0x0000080c, 0x00000100), \ 7562306a36Sopenharmony_ci PARAM_WRITE_D0_D4(0x00000804, ((_data_804) << 16) | BIT(8) | (_addr)), \ 7662306a36Sopenharmony_ci PARAM_WRITE(0xd0, 0x0000080c), \ 7762306a36Sopenharmony_ci PARAM_POLL(0xd4, BIT(8), BIT(8)) 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci#define PARAM_WRITE_828_82C_POLL(_data_828) \ 8062306a36Sopenharmony_ci PARAM_WRITE_D0_D4(0x0000082c, 0x0f000000), \ 8162306a36Sopenharmony_ci PARAM_WRITE_D0_D4(0x00000828, _data_828), \ 8262306a36Sopenharmony_ci PARAM_WRITE(0xd0, 0x0000082c), \ 8362306a36Sopenharmony_ci PARAM_POLL(0xd4, _data_828, _data_828) 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci#define PARAM_WRITE_PHY(_addr16, _data16) \ 8662306a36Sopenharmony_ci PARAM_WRITE(0xf0, 1), \ 8762306a36Sopenharmony_ci PARAM_WRITE_800_80C_POLL(0x16, (_addr16) & 0xff), \ 8862306a36Sopenharmony_ci PARAM_WRITE_800_80C_POLL(0x17, ((_addr16) >> 8) & 0xff), \ 8962306a36Sopenharmony_ci PARAM_WRITE_800_80C_POLL(0x18, (_data16) & 0xff), \ 9062306a36Sopenharmony_ci PARAM_WRITE_800_80C_POLL(0x19, ((_data16) >> 8) & 0xff), \ 9162306a36Sopenharmony_ci PARAM_WRITE_800_80C_POLL(0x1c, 0x01), \ 9262306a36Sopenharmony_ci PARAM_WRITE_828_82C_POLL(0x0f000000), \ 9362306a36Sopenharmony_ci PARAM_WRITE(0xf0, 0) 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci#define PARAM_SET_PHY(_addr16, _data16) \ 9662306a36Sopenharmony_ci PARAM_WRITE(0xf0, 1), \ 9762306a36Sopenharmony_ci PARAM_WRITE_800_80C_POLL(0x16, (_addr16) & 0xff), \ 9862306a36Sopenharmony_ci PARAM_WRITE_800_80C_POLL(0x17, ((_addr16) >> 8) & 0xff), \ 9962306a36Sopenharmony_ci PARAM_WRITE_800_80C_POLL(0x1c, 0x01), \ 10062306a36Sopenharmony_ci PARAM_WRITE_828_82C_POLL(0x0f000000), \ 10162306a36Sopenharmony_ci PARAM_WRITE_804_80C_POLL(0x1a, 0), \ 10262306a36Sopenharmony_ci PARAM_WRITE(0xd0, 0x00000808), \ 10362306a36Sopenharmony_ci PARAM_SAVE(0xd4, 0xff, SET_PHY_INDEX_LO), \ 10462306a36Sopenharmony_ci PARAM_WRITE_804_80C_POLL(0x1b, 0), \ 10562306a36Sopenharmony_ci PARAM_WRITE(0xd0, 0x00000808), \ 10662306a36Sopenharmony_ci PARAM_SAVE(0xd4, 0xff, SET_PHY_INDEX_HI), \ 10762306a36Sopenharmony_ci PARAM_WRITE_828_82C_POLL(0x0f000000), \ 10862306a36Sopenharmony_ci PARAM_WRITE(0xf0, 0), \ 10962306a36Sopenharmony_ci PARAM_WRITE(0xf0, 1), \ 11062306a36Sopenharmony_ci PARAM_WRITE_800_80C_POLL(0x16, (_addr16) & 0xff), \ 11162306a36Sopenharmony_ci PARAM_WRITE_800_80C_POLL(0x17, ((_addr16) >> 8) & 0xff), \ 11262306a36Sopenharmony_ci PARAM_SET(SET_PHY_INDEX_LO, ((_data16 & 0xff) << 16) | BIT(8) | 0x18), \ 11362306a36Sopenharmony_ci PARAM_RESTORE_800_80C_POLL(SET_PHY_INDEX_LO), \ 11462306a36Sopenharmony_ci PARAM_SET(SET_PHY_INDEX_HI, (((_data16 >> 8) & 0xff) << 16) | BIT(8) | 0x19), \ 11562306a36Sopenharmony_ci PARAM_RESTORE_800_80C_POLL(SET_PHY_INDEX_HI), \ 11662306a36Sopenharmony_ci PARAM_WRITE_800_80C_POLL(0x1c, 0x01), \ 11762306a36Sopenharmony_ci PARAM_WRITE_828_82C_POLL(0x0f000000), \ 11862306a36Sopenharmony_ci PARAM_WRITE(0xf0, 0) 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci#define PARAM_INDIRECT_WRITE(_gpio, _addr, _data_800) \ 12162306a36Sopenharmony_ci PARAM_WRITE(0xf0, _gpio), \ 12262306a36Sopenharmony_ci PARAM_WRITE_800_80C_POLL(_addr, _data_800), \ 12362306a36Sopenharmony_ci PARAM_WRITE_828_82C_POLL(0x0f000000), \ 12462306a36Sopenharmony_ci PARAM_WRITE(0xf0, 0) 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci#define PARAM_INDIRECT_POLL(_gpio, _addr, _expected, _mask) \ 12762306a36Sopenharmony_ci PARAM_WRITE(0xf0, _gpio), \ 12862306a36Sopenharmony_ci PARAM_WRITE_800_80C_POLL(_addr, 0), \ 12962306a36Sopenharmony_ci PARAM_WRITE(0xd0, 0x00000808), \ 13062306a36Sopenharmony_ci PARAM_POLL(0xd4, _expected, _mask), \ 13162306a36Sopenharmony_ci PARAM_WRITE(0xf0, 0) 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistruct ufs_renesas_init_param { 13462306a36Sopenharmony_ci enum ufs_renesas_init_param_mode mode; 13562306a36Sopenharmony_ci u32 reg; 13662306a36Sopenharmony_ci union { 13762306a36Sopenharmony_ci u32 expected; 13862306a36Sopenharmony_ci u32 delay_us; 13962306a36Sopenharmony_ci u32 set; 14062306a36Sopenharmony_ci u32 val; 14162306a36Sopenharmony_ci } u; 14262306a36Sopenharmony_ci u32 mask; 14362306a36Sopenharmony_ci u32 index; 14462306a36Sopenharmony_ci}; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci/* This setting is for SERIES B */ 14762306a36Sopenharmony_cistatic const struct ufs_renesas_init_param ufs_param[] = { 14862306a36Sopenharmony_ci PARAM_WRITE(0xc0, 0x49425308), 14962306a36Sopenharmony_ci PARAM_WRITE_D0_D4(0x00000104, 0x00000002), 15062306a36Sopenharmony_ci PARAM_WAIT(1), 15162306a36Sopenharmony_ci PARAM_WRITE_D0_D4(0x00000828, 0x00000200), 15262306a36Sopenharmony_ci PARAM_WAIT(1), 15362306a36Sopenharmony_ci PARAM_WRITE_D0_D4(0x00000828, 0x00000000), 15462306a36Sopenharmony_ci PARAM_WRITE_D0_D4(0x00000104, 0x00000001), 15562306a36Sopenharmony_ci PARAM_WRITE_D0_D4(0x00000940, 0x00000001), 15662306a36Sopenharmony_ci PARAM_WAIT(1), 15762306a36Sopenharmony_ci PARAM_WRITE_D0_D4(0x00000940, 0x00000000), 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci PARAM_WRITE(0xc0, 0x49425308), 16062306a36Sopenharmony_ci PARAM_WRITE(0xc0, 0x41584901), 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci PARAM_WRITE_D0_D4(0x0000080c, 0x00000100), 16362306a36Sopenharmony_ci PARAM_WRITE_D0_D4(0x00000804, 0x00000000), 16462306a36Sopenharmony_ci PARAM_WRITE(0xd0, 0x0000080c), 16562306a36Sopenharmony_ci PARAM_POLL(0xd4, BIT(8), BIT(8)), 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci PARAM_WRITE(REG_CONTROLLER_ENABLE, 0x00000001), 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci PARAM_WRITE(0xd0, 0x00000804), 17062306a36Sopenharmony_ci PARAM_POLL(0xd4, BIT(8) | BIT(6) | BIT(0), BIT(8) | BIT(6) | BIT(0)), 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci PARAM_WRITE(0xd0, 0x00000d00), 17362306a36Sopenharmony_ci PARAM_SAVE(0xd4, 0x0000ffff, TIMER_INDEX), 17462306a36Sopenharmony_ci PARAM_WRITE(0xd4, 0x00000000), 17562306a36Sopenharmony_ci PARAM_WRITE_D0_D4(0x0000082c, 0x0f000000), 17662306a36Sopenharmony_ci PARAM_WRITE_D0_D4(0x00000828, 0x08000000), 17762306a36Sopenharmony_ci PARAM_WRITE(0xd0, 0x0000082c), 17862306a36Sopenharmony_ci PARAM_POLL(0xd4, BIT(27), BIT(27)), 17962306a36Sopenharmony_ci PARAM_WRITE(0xd0, 0x00000d2c), 18062306a36Sopenharmony_ci PARAM_POLL(0xd4, BIT(0), BIT(0)), 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci /* phy setup */ 18362306a36Sopenharmony_ci PARAM_INDIRECT_WRITE(1, 0x01, 0x001f), 18462306a36Sopenharmony_ci PARAM_INDIRECT_WRITE(7, 0x5d, 0x0014), 18562306a36Sopenharmony_ci PARAM_INDIRECT_WRITE(7, 0x5e, 0x0014), 18662306a36Sopenharmony_ci PARAM_INDIRECT_WRITE(7, 0x0d, 0x0003), 18762306a36Sopenharmony_ci PARAM_INDIRECT_WRITE(7, 0x0e, 0x0007), 18862306a36Sopenharmony_ci PARAM_INDIRECT_WRITE(7, 0x5f, 0x0003), 18962306a36Sopenharmony_ci PARAM_INDIRECT_WRITE(7, 0x60, 0x0003), 19062306a36Sopenharmony_ci PARAM_INDIRECT_WRITE(7, 0x5b, 0x00a6), 19162306a36Sopenharmony_ci PARAM_INDIRECT_WRITE(7, 0x5c, 0x0003), 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci PARAM_INDIRECT_POLL(7, 0x3c, 0, BIT(7)), 19462306a36Sopenharmony_ci PARAM_INDIRECT_POLL(7, 0x4c, 0, BIT(4)), 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci PARAM_INDIRECT_WRITE(1, 0x32, 0x0080), 19762306a36Sopenharmony_ci PARAM_INDIRECT_WRITE(1, 0x1f, 0x0001), 19862306a36Sopenharmony_ci PARAM_INDIRECT_WRITE(0, 0x2c, 0x0001), 19962306a36Sopenharmony_ci PARAM_INDIRECT_WRITE(0, 0x32, 0x0087), 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci PARAM_INDIRECT_WRITE(1, 0x4d, 0x0061), 20262306a36Sopenharmony_ci PARAM_INDIRECT_WRITE(4, 0x9b, 0x0009), 20362306a36Sopenharmony_ci PARAM_INDIRECT_WRITE(4, 0xa6, 0x0005), 20462306a36Sopenharmony_ci PARAM_INDIRECT_WRITE(4, 0xa5, 0x0058), 20562306a36Sopenharmony_ci PARAM_INDIRECT_WRITE(1, 0x39, 0x0027), 20662306a36Sopenharmony_ci PARAM_INDIRECT_WRITE(1, 0x47, 0x004c), 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci PARAM_INDIRECT_WRITE(7, 0x0d, 0x0002), 20962306a36Sopenharmony_ci PARAM_INDIRECT_WRITE(7, 0x0e, 0x0007), 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci PARAM_WRITE_PHY(0x0028, 0x0061), 21262306a36Sopenharmony_ci PARAM_WRITE_PHY(0x4014, 0x0061), 21362306a36Sopenharmony_ci PARAM_SET_PHY(0x401c, BIT(2)), 21462306a36Sopenharmony_ci PARAM_WRITE_PHY(0x4000, 0x0000), 21562306a36Sopenharmony_ci PARAM_WRITE_PHY(0x4001, 0x0000), 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci PARAM_WRITE_PHY(0x10ae, 0x0001), 21862306a36Sopenharmony_ci PARAM_WRITE_PHY(0x10ad, 0x0000), 21962306a36Sopenharmony_ci PARAM_WRITE_PHY(0x10af, 0x0001), 22062306a36Sopenharmony_ci PARAM_WRITE_PHY(0x10b6, 0x0001), 22162306a36Sopenharmony_ci PARAM_WRITE_PHY(0x10ae, 0x0000), 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci PARAM_WRITE_PHY(0x10ae, 0x0001), 22462306a36Sopenharmony_ci PARAM_WRITE_PHY(0x10ad, 0x0000), 22562306a36Sopenharmony_ci PARAM_WRITE_PHY(0x10af, 0x0002), 22662306a36Sopenharmony_ci PARAM_WRITE_PHY(0x10b6, 0x0001), 22762306a36Sopenharmony_ci PARAM_WRITE_PHY(0x10ae, 0x0000), 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci PARAM_WRITE_PHY(0x10ae, 0x0001), 23062306a36Sopenharmony_ci PARAM_WRITE_PHY(0x10ad, 0x0080), 23162306a36Sopenharmony_ci PARAM_WRITE_PHY(0x10af, 0x0000), 23262306a36Sopenharmony_ci PARAM_WRITE_PHY(0x10b6, 0x0001), 23362306a36Sopenharmony_ci PARAM_WRITE_PHY(0x10ae, 0x0000), 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci PARAM_WRITE_PHY(0x10ae, 0x0001), 23662306a36Sopenharmony_ci PARAM_WRITE_PHY(0x10ad, 0x0080), 23762306a36Sopenharmony_ci PARAM_WRITE_PHY(0x10af, 0x001a), 23862306a36Sopenharmony_ci PARAM_WRITE_PHY(0x10b6, 0x0001), 23962306a36Sopenharmony_ci PARAM_WRITE_PHY(0x10ae, 0x0000), 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci PARAM_INDIRECT_WRITE(7, 0x70, 0x0016), 24262306a36Sopenharmony_ci PARAM_INDIRECT_WRITE(7, 0x71, 0x0016), 24362306a36Sopenharmony_ci PARAM_INDIRECT_WRITE(7, 0x72, 0x0014), 24462306a36Sopenharmony_ci PARAM_INDIRECT_WRITE(7, 0x73, 0x0014), 24562306a36Sopenharmony_ci PARAM_INDIRECT_WRITE(7, 0x74, 0x0000), 24662306a36Sopenharmony_ci PARAM_INDIRECT_WRITE(7, 0x75, 0x0000), 24762306a36Sopenharmony_ci PARAM_INDIRECT_WRITE(7, 0x76, 0x0010), 24862306a36Sopenharmony_ci PARAM_INDIRECT_WRITE(7, 0x77, 0x0010), 24962306a36Sopenharmony_ci PARAM_INDIRECT_WRITE(7, 0x78, 0x00ff), 25062306a36Sopenharmony_ci PARAM_INDIRECT_WRITE(7, 0x79, 0x0000), 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci PARAM_INDIRECT_WRITE(7, 0x19, 0x0007), 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci PARAM_INDIRECT_WRITE(7, 0x1a, 0x0007), 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci PARAM_INDIRECT_WRITE(7, 0x24, 0x000c), 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci PARAM_INDIRECT_WRITE(7, 0x25, 0x000c), 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci PARAM_INDIRECT_WRITE(7, 0x62, 0x0000), 26162306a36Sopenharmony_ci PARAM_INDIRECT_WRITE(7, 0x63, 0x0000), 26262306a36Sopenharmony_ci PARAM_INDIRECT_WRITE(7, 0x5d, 0x0014), 26362306a36Sopenharmony_ci PARAM_INDIRECT_WRITE(7, 0x5e, 0x0017), 26462306a36Sopenharmony_ci PARAM_INDIRECT_WRITE(7, 0x5d, 0x0004), 26562306a36Sopenharmony_ci PARAM_INDIRECT_WRITE(7, 0x5e, 0x0017), 26662306a36Sopenharmony_ci PARAM_INDIRECT_POLL(7, 0x55, 0, BIT(6)), 26762306a36Sopenharmony_ci PARAM_INDIRECT_POLL(7, 0x41, 0, BIT(7)), 26862306a36Sopenharmony_ci /* end of phy setup */ 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci PARAM_WRITE(0xf0, 0), 27162306a36Sopenharmony_ci PARAM_WRITE(0xd0, 0x00000d00), 27262306a36Sopenharmony_ci PARAM_RESTORE(0xd4, TIMER_INDEX), 27362306a36Sopenharmony_ci}; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_cistatic void ufs_renesas_dbg_register_dump(struct ufs_hba *hba) 27662306a36Sopenharmony_ci{ 27762306a36Sopenharmony_ci ufshcd_dump_regs(hba, 0xc0, 0x40, "regs: 0xc0 + "); 27862306a36Sopenharmony_ci} 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_cistatic void ufs_renesas_reg_control(struct ufs_hba *hba, 28162306a36Sopenharmony_ci const struct ufs_renesas_init_param *p) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci static u32 save[MAX_INDEX]; 28462306a36Sopenharmony_ci int ret; 28562306a36Sopenharmony_ci u32 val; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci WARN_ON(p->index >= MAX_INDEX); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci switch (p->mode) { 29062306a36Sopenharmony_ci case MODE_RESTORE: 29162306a36Sopenharmony_ci ufshcd_writel(hba, save[p->index], p->reg); 29262306a36Sopenharmony_ci break; 29362306a36Sopenharmony_ci case MODE_SET: 29462306a36Sopenharmony_ci save[p->index] |= p->u.set; 29562306a36Sopenharmony_ci break; 29662306a36Sopenharmony_ci case MODE_SAVE: 29762306a36Sopenharmony_ci save[p->index] = ufshcd_readl(hba, p->reg) & p->mask; 29862306a36Sopenharmony_ci break; 29962306a36Sopenharmony_ci case MODE_POLL: 30062306a36Sopenharmony_ci ret = readl_poll_timeout_atomic(hba->mmio_base + p->reg, 30162306a36Sopenharmony_ci val, 30262306a36Sopenharmony_ci (val & p->mask) == p->u.expected, 30362306a36Sopenharmony_ci 10, 1000); 30462306a36Sopenharmony_ci if (ret) 30562306a36Sopenharmony_ci dev_err(hba->dev, "%s: poll failed %d (%08x, %08x, %08x)\n", 30662306a36Sopenharmony_ci __func__, ret, val, p->mask, p->u.expected); 30762306a36Sopenharmony_ci break; 30862306a36Sopenharmony_ci case MODE_WAIT: 30962306a36Sopenharmony_ci if (p->u.delay_us > 1000) 31062306a36Sopenharmony_ci mdelay(DIV_ROUND_UP(p->u.delay_us, 1000)); 31162306a36Sopenharmony_ci else 31262306a36Sopenharmony_ci udelay(p->u.delay_us); 31362306a36Sopenharmony_ci break; 31462306a36Sopenharmony_ci case MODE_WRITE: 31562306a36Sopenharmony_ci ufshcd_writel(hba, p->u.val, p->reg); 31662306a36Sopenharmony_ci break; 31762306a36Sopenharmony_ci default: 31862306a36Sopenharmony_ci break; 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci} 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_cistatic void ufs_renesas_pre_init(struct ufs_hba *hba) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci const struct ufs_renesas_init_param *p = ufs_param; 32562306a36Sopenharmony_ci unsigned int i; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ufs_param); i++) 32862306a36Sopenharmony_ci ufs_renesas_reg_control(hba, &p[i]); 32962306a36Sopenharmony_ci} 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_cistatic int ufs_renesas_hce_enable_notify(struct ufs_hba *hba, 33262306a36Sopenharmony_ci enum ufs_notify_change_status status) 33362306a36Sopenharmony_ci{ 33462306a36Sopenharmony_ci struct ufs_renesas_priv *priv = ufshcd_get_variant(hba); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci if (priv->initialized) 33762306a36Sopenharmony_ci return 0; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci if (status == PRE_CHANGE) 34062306a36Sopenharmony_ci ufs_renesas_pre_init(hba); 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci priv->initialized = true; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci return 0; 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic int ufs_renesas_setup_clocks(struct ufs_hba *hba, bool on, 34862306a36Sopenharmony_ci enum ufs_notify_change_status status) 34962306a36Sopenharmony_ci{ 35062306a36Sopenharmony_ci if (on && status == PRE_CHANGE) 35162306a36Sopenharmony_ci pm_runtime_get_sync(hba->dev); 35262306a36Sopenharmony_ci else if (!on && status == POST_CHANGE) 35362306a36Sopenharmony_ci pm_runtime_put(hba->dev); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci return 0; 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cistatic int ufs_renesas_init(struct ufs_hba *hba) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci struct ufs_renesas_priv *priv; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci priv = devm_kzalloc(hba->dev, sizeof(*priv), GFP_KERNEL); 36362306a36Sopenharmony_ci if (!priv) 36462306a36Sopenharmony_ci return -ENOMEM; 36562306a36Sopenharmony_ci ufshcd_set_variant(hba, priv); 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci hba->quirks |= UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS | UFSHCD_QUIRK_HIBERN_FASTAUTO; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci return 0; 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_cistatic const struct ufs_hba_variant_ops ufs_renesas_vops = { 37362306a36Sopenharmony_ci .name = "renesas", 37462306a36Sopenharmony_ci .init = ufs_renesas_init, 37562306a36Sopenharmony_ci .setup_clocks = ufs_renesas_setup_clocks, 37662306a36Sopenharmony_ci .hce_enable_notify = ufs_renesas_hce_enable_notify, 37762306a36Sopenharmony_ci .dbg_register_dump = ufs_renesas_dbg_register_dump, 37862306a36Sopenharmony_ci}; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_cistatic const struct of_device_id __maybe_unused ufs_renesas_of_match[] = { 38162306a36Sopenharmony_ci { .compatible = "renesas,r8a779f0-ufs" }, 38262306a36Sopenharmony_ci { /* sentinel */ } 38362306a36Sopenharmony_ci}; 38462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, ufs_renesas_of_match); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_cistatic int ufs_renesas_probe(struct platform_device *pdev) 38762306a36Sopenharmony_ci{ 38862306a36Sopenharmony_ci return ufshcd_pltfrm_init(pdev, &ufs_renesas_vops); 38962306a36Sopenharmony_ci} 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_cistatic int ufs_renesas_remove(struct platform_device *pdev) 39262306a36Sopenharmony_ci{ 39362306a36Sopenharmony_ci struct ufs_hba *hba = platform_get_drvdata(pdev); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci ufshcd_remove(hba); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci return 0; 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_cistatic struct platform_driver ufs_renesas_platform = { 40162306a36Sopenharmony_ci .probe = ufs_renesas_probe, 40262306a36Sopenharmony_ci .remove = ufs_renesas_remove, 40362306a36Sopenharmony_ci .driver = { 40462306a36Sopenharmony_ci .name = "ufshcd-renesas", 40562306a36Sopenharmony_ci .of_match_table = of_match_ptr(ufs_renesas_of_match), 40662306a36Sopenharmony_ci }, 40762306a36Sopenharmony_ci}; 40862306a36Sopenharmony_cimodule_platform_driver(ufs_renesas_platform); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ciMODULE_AUTHOR("Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>"); 41162306a36Sopenharmony_ciMODULE_DESCRIPTION("Renesas UFS host controller driver"); 41262306a36Sopenharmony_ciMODULE_LICENSE("Dual MIT/GPL"); 413