From 30a570a983c77cddda314cdb2bc5763112338746 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 23 Apr 2017 20:10:43 -0600 Subject: dm: core: Clarify uclass_first/next_device() comments These are not as clear as they could be. Tidy them up a bit. Also fix a tiny code-style nit. Signed-off-by: Simon Glass diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index 21dc696..97500f4 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -366,8 +366,7 @@ int uclass_get_device_by_driver(enum uclass_id id, return -ENODEV; } -int uclass_get_device_tail(struct udevice *dev, int ret, - struct udevice **devp) +int uclass_get_device_tail(struct udevice *dev, int ret, struct udevice **devp) { if (ret) return ret; diff --git a/include/dm/uclass.h b/include/dm/uclass.h index 7f5a130..4dcd883 100644 --- a/include/dm/uclass.h +++ b/include/dm/uclass.h @@ -241,8 +241,13 @@ int uclass_get_device_by_driver(enum uclass_id id, const struct driver *drv, * * The device returned is probed if necessary, and ready for use * + * This function is useful to start iterating through a list of devices which + * are functioning correctly and can be probed. + * * @id: Uclass ID to look up - * @devp: Returns pointer to the first device in that uclass, or NULL if none + * @devp: Returns pointer to the first device in that uclass if no error + * occurred, or NULL if there is no first device, or an error occurred with + * that device. * @return 0 if OK (found or not found), other -ve on error */ int uclass_first_device(enum uclass_id id, struct udevice **devp); @@ -263,8 +268,12 @@ int uclass_first_device_err(enum uclass_id id, struct udevice **devp); * * The device returned is probed if necessary, and ready for use * + * This function is useful to start iterating through a list of devices which + * are functioning correctly and can be probed. + * * @devp: On entry, pointer to device to lookup. On exit, returns pointer - * to the next device in the same uclass, or NULL if none + * to the next device in the uclass if no error occurred, or NULL if there is + * no next device, or an error occurred with that next device. * @return 0 if OK (found or not found), other -ve on error */ int uclass_next_device(struct udevice **devp); -- cgit v0.10.2 From 9856157259f4ab55e3d99c9aacc85f08797c8579 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 23 Apr 2017 20:10:44 -0600 Subject: dm: core: Test uclass_first/next_device() on probe failure Add some tests which check the behaviour of uclass_first_device() and uclass_next_device() when probing of a device fails. Signed-off-by: Simon Glass diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 7dde95d..65b2f8e 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -289,6 +289,25 @@ }; }; + probing { + compatible = "simple-bus"; + test1 { + compatible = "denx,u-boot-probe-test"; + }; + + test2 { + compatible = "denx,u-boot-probe-test"; + }; + + test3 { + compatible = "denx,u-boot-probe-test"; + }; + + test4 { + compatible = "denx,u-boot-probe-test"; + }; + }; + pwrdom: power-domain { compatible = "sandbox,power-domain"; #power-domain-cells = <1>; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 1f7e32c..2e6498b 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -18,6 +18,7 @@ enum uclass_id { UCLASS_TEST, UCLASS_TEST_FDT, UCLASS_TEST_BUS, + UCLASS_TEST_PROBE, UCLASS_SPI_EMUL, /* sandbox SPI device emulator */ UCLASS_I2C_EMUL, /* sandbox I2C device emulator */ UCLASS_PCI_EMUL, /* sandbox PCI device emulator */ diff --git a/test/dm/test-fdt.c b/test/dm/test-fdt.c index 987a265..7c9c5de 100644 --- a/test/dm/test-fdt.c +++ b/test/dm/test-fdt.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -99,6 +100,36 @@ UCLASS_DRIVER(testfdt) = { .flags = DM_UC_FLAG_SEQ_ALIAS, }; +struct dm_testprobe_pdata { + int probe_err; +}; + +static int testprobe_drv_probe(struct udevice *dev) +{ + struct dm_testprobe_pdata *pdata = dev_get_platdata(dev); + + return pdata->probe_err; +} + +static const struct udevice_id testprobe_ids[] = { + { .compatible = "denx,u-boot-probe-test" }, + { } +}; + +U_BOOT_DRIVER(testprobe_drv) = { + .name = "testprobe_drv", + .of_match = testprobe_ids, + .id = UCLASS_TEST_PROBE, + .probe = testprobe_drv_probe, + .platdata_auto_alloc_size = sizeof(struct dm_testprobe_pdata), +}; + +UCLASS_DRIVER(testprobe) = { + .name = "testprobe", + .id = UCLASS_TEST_PROBE, + .flags = DM_UC_FLAG_SEQ_ALIAS, +}; + int dm_check_devices(struct unit_test_state *uts, int num_devices) { struct udevice *dev; @@ -267,3 +298,44 @@ static int dm_test_fdt_offset(struct unit_test_state *uts) } DM_TEST(dm_test_fdt_offset, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT | DM_TESTF_FLAT_TREE); + +/** + * Test various error conditions with uclass_first_device() and + * uclass_next_device() + */ +static int dm_test_first_next_device(struct unit_test_state *uts) +{ + struct dm_testprobe_pdata *pdata; + struct udevice *dev, *parent = NULL; + int count; + int ret; + + /* There should be 4 devices */ + for (ret = uclass_first_device(UCLASS_TEST_PROBE, &dev), count = 0; + dev; + ret = uclass_next_device(&dev)) { + count++; + parent = dev_get_parent(dev); + } + ut_assertok(ret); + ut_asserteq(4, count); + + /* Remove them and try again, with an error on the second one */ + ut_assertok(uclass_get_device(UCLASS_TEST_PROBE, 1, &dev)); + pdata = dev_get_platdata(dev); + pdata->probe_err = -ENOMEM; + device_remove(parent, DM_REMOVE_NORMAL); + ut_assertok(uclass_first_device(UCLASS_TEST_PROBE, &dev)); + ut_asserteq(-ENOMEM, uclass_next_device(&dev)); + ut_asserteq_ptr(dev, NULL); + + /* Now an error on the first one */ + ut_assertok(uclass_get_device(UCLASS_TEST_PROBE, 0, &dev)); + pdata = dev_get_platdata(dev); + pdata->probe_err = -ENOENT; + device_remove(parent, DM_REMOVE_NORMAL); + ut_asserteq(-ENOENT, uclass_first_device(UCLASS_TEST_PROBE, &dev)); + + return 0; +} +DM_TEST(dm_test_first_next_device, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); -- cgit v0.10.2 From 95ce385a4ad0bb0d0a20f68b2a1f2451584bf3ff Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 23 Apr 2017 20:10:45 -0600 Subject: dm: core: Add uclass_first/next_device_check() Sometimes it is useful to iterate through all devices in a uclass and skip over those which do not work correctly (e.g fail to probe). Add two new functions to provide this feature. The caller must check the return value each time to make sure that the device is valid. But the device pointer is always returned. Signed-off-by: Simon Glass diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index 97500f4..f5e4067 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -492,6 +492,33 @@ int uclass_next_device(struct udevice **devp) return uclass_get_device_tail(dev, ret, devp); } +int uclass_first_device_check(enum uclass_id id, struct udevice **devp) +{ + int ret; + + *devp = NULL; + ret = uclass_find_first_device(id, devp); + if (ret) + return ret; + if (!*devp) + return 0; + + return device_probe(*devp); +} + +int uclass_next_device_check(struct udevice **devp) +{ + int ret; + + ret = uclass_find_next_device(devp); + if (ret) + return ret; + if (!*devp) + return 0; + + return device_probe(*devp); +} + int uclass_bind_device(struct udevice *dev) { struct uclass *uc; diff --git a/include/dm/uclass.h b/include/dm/uclass.h index 4dcd883..1818849 100644 --- a/include/dm/uclass.h +++ b/include/dm/uclass.h @@ -279,6 +279,37 @@ int uclass_first_device_err(enum uclass_id id, struct udevice **devp); int uclass_next_device(struct udevice **devp); /** + * uclass_first_device() - Get the first device in a uclass + * + * The device returned is probed if necessary, and ready for use + * + * This function is useful to start iterating through a list of devices which + * are functioning correctly and can be probed. + * + * @id: Uclass ID to look up + * @devp: Returns pointer to the first device in that uclass, or NULL if there + * is no first device + * @return 0 if OK (found or not found), other -ve on error. If an error occurs + * it is still possible to move to the next device. + */ +int uclass_first_device_check(enum uclass_id id, struct udevice **devp); + +/** + * uclass_next_device() - Get the next device in a uclass + * + * The device returned is probed if necessary, and ready for use + * + * This function is useful to start iterating through a list of devices which + * are functioning correctly and can be probed. + * + * @devp: On entry, pointer to device to lookup. On exit, returns pointer + * to the next device in the uclass if any + * @return 0 if OK (found or not found), other -ve on error. If an error occurs + * it is still possible to move to the next device. + */ +int uclass_next_device_check(struct udevice **devp); + +/** * uclass_resolve_seq() - Resolve a device's sequence number * * On entry dev->seq is -1, and dev->req_seq may be -1 (to allocate a diff --git a/test/dm/test-fdt.c b/test/dm/test-fdt.c index 7c9c5de..dcc2ef8 100644 --- a/test/dm/test-fdt.c +++ b/test/dm/test-fdt.c @@ -339,3 +339,83 @@ static int dm_test_first_next_device(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_first_next_device, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +/** + * check_devices() - Check return values and pointers + * + * This runs through a full sequence of uclass_first_device_check()... + * uclass_next_device_check() checking that the return values and devices + * are correct. + * + * @uts: Test state + * @devlist: List of expected devices + * @mask: Indicates which devices should return an error. Device n should + * return error (-NOENT - n) if bit n is set, or no error (i.e. 0) if + * bit n is clear. + */ +static int check_devices(struct unit_test_state *uts, + struct udevice *devlist[], int mask) +{ + int expected_ret; + struct udevice *dev; + int i; + + expected_ret = (mask & 1) ? -ENOENT : 0; + mask >>= 1; + ut_asserteq(expected_ret, + uclass_first_device_check(UCLASS_TEST_PROBE, &dev)); + for (i = 0; i < 4; i++) { + ut_asserteq_ptr(devlist[i], dev); + expected_ret = (mask & 1) ? -ENOENT - (i + 1) : 0; + mask >>= 1; + ut_asserteq(expected_ret, uclass_next_device_check(&dev)); + } + ut_asserteq_ptr(NULL, dev); + + return 0; +} + +/* Test uclass_first_device_check() and uclass_next_device_check() */ +static int dm_test_first_next_ok_device(struct unit_test_state *uts) +{ + struct dm_testprobe_pdata *pdata; + struct udevice *dev, *parent = NULL, *devlist[4]; + int count; + int ret; + + /* There should be 4 devices */ + count = 0; + for (ret = uclass_first_device_check(UCLASS_TEST_PROBE, &dev); + dev; + ret = uclass_next_device_check(&dev)) { + ut_assertok(ret); + devlist[count++] = dev; + parent = dev_get_parent(dev); + } + ut_asserteq(4, count); + ut_assertok(uclass_first_device_check(UCLASS_TEST_PROBE, &dev)); + ut_assertok(check_devices(uts, devlist, 0)); + + /* Remove them and try again, with an error on the second one */ + pdata = dev_get_platdata(devlist[1]); + pdata->probe_err = -ENOENT - 1; + device_remove(parent, DM_REMOVE_NORMAL); + ut_assertok(check_devices(uts, devlist, 1 << 1)); + + /* Now an error on the first one */ + pdata = dev_get_platdata(devlist[0]); + pdata->probe_err = -ENOENT - 0; + device_remove(parent, DM_REMOVE_NORMAL); + ut_assertok(check_devices(uts, devlist, 3 << 0)); + + /* Now errors on all */ + pdata = dev_get_platdata(devlist[2]); + pdata->probe_err = -ENOENT - 2; + pdata = dev_get_platdata(devlist[3]); + pdata->probe_err = -ENOENT - 3; + device_remove(parent, DM_REMOVE_NORMAL); + ut_assertok(check_devices(uts, devlist, 0xf << 0)); + + return 0; +} +DM_TEST(dm_test_first_next_ok_device, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); -- cgit v0.10.2 From 69aaec0bca6a0283d21453e1b18e407a9f20b69a Mon Sep 17 00:00:00 2001 From: Kever Yang Date: Thu, 18 May 2017 16:05:20 +0800 Subject: rockchip: dts: rk3328: add aliases for mmc controller Add aliases for mmc controller to get a fixed order with emmc at index 0 and sdmmc at index 1. Signed-off-by: Kever Yang Reviewed-by: Simon Glass diff --git a/arch/arm/dts/rk3328.dtsi b/arch/arm/dts/rk3328.dtsi index f18cfc2..dd9cb1c 100644 --- a/arch/arm/dts/rk3328.dtsi +++ b/arch/arm/dts/rk3328.dtsi @@ -25,6 +25,9 @@ i2c1 = &i2c1; i2c2 = &i2c2; i2c3 = &i2c3; + mmc0 = &emmc; + mmc1 = &sdmmc; + mmc2 = &sdmmc_ext; }; cpus { -- cgit v0.10.2 From 25f978cb1c55d2ff52db2aeaa1eacd84eec115db Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 1 Jun 2017 19:38:58 -0600 Subject: moveconfig: Support providing a path to the defconfig files It is convenient to provide the full patch to the defconfig files in some situations, e.g. when the file was generated by a shell command (e.g. 'ls configs/zynq*'). Add support for this, and move the globbing code into a function with its own documentation. Signed-off-by: Simon Glass diff --git a/tools/moveconfig.py b/tools/moveconfig.py index 7aa9612..390aac6 100755 --- a/tools/moveconfig.py +++ b/tools/moveconfig.py @@ -278,6 +278,24 @@ def get_make_cmd(): sys.exit('GNU Make not found') return ret[0].rstrip() +def get_matched_defconfig(line): + """Get the defconfig files that match a pattern + + Args: + line: Path or filename to match, e.g. 'configs/snow_defconfig' or + 'k2*_defconfig'. If no directory is provided, 'configs/' is + prepended + + Returns: + a list of matching defconfig files + """ + dirname = os.path.dirname(line) + if dirname: + pattern = line + else: + pattern = os.path.join('configs', line) + return glob.glob(pattern) + glob.glob(pattern + '_defconfig') + def get_matched_defconfigs(defconfigs_file): """Get all the defconfig files that match the patterns in a file.""" defconfigs = [] @@ -285,8 +303,7 @@ def get_matched_defconfigs(defconfigs_file): line = line.strip() if not line: continue # skip blank lines silently - pattern = os.path.join('configs', line) - matched = glob.glob(pattern) + glob.glob(pattern + '_defconfig') + matched = get_matched_defconfig(line) if not matched: print >> sys.stderr, "warning: %s:%d: no defconfig matched '%s'" % \ (defconfigs_file, i + 1, line) -- cgit v0.10.2 From ee4e61bda4b5187d2e098accbc166b9f09c94814 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 1 Jun 2017 19:38:59 -0600 Subject: moveconfig: Allow reading the defconfig list from stdin Support passes in a defconfig filename of '-' to read the list from stdin instead of from a file. Signed-off-by: Simon Glass diff --git a/tools/moveconfig.py b/tools/moveconfig.py index 390aac6..c581fb6 100755 --- a/tools/moveconfig.py +++ b/tools/moveconfig.py @@ -297,9 +297,22 @@ def get_matched_defconfig(line): return glob.glob(pattern) + glob.glob(pattern + '_defconfig') def get_matched_defconfigs(defconfigs_file): - """Get all the defconfig files that match the patterns in a file.""" + """Get all the defconfig files that match the patterns in a file. + + Args: + defconfigs_file: File containing a list of defconfigs to process, or + '-' to read the list from stdin + + Returns: + A list of paths to defconfig files, with no duplicates + """ defconfigs = [] - for i, line in enumerate(open(defconfigs_file)): + if defconfigs_file == '-': + fd = sys.stdin + defconfigs_file = 'stdin' + else: + fd = open(defconfigs_file) + for i, line in enumerate(fd): line = line.strip() if not line: continue # skip blank lines silently @@ -1328,7 +1341,9 @@ def main(): parser.add_option('-C', '--commit', action='store_true', default=False, help='Create a git commit for the operation') parser.add_option('-d', '--defconfigs', type='string', - help='a file containing a list of defconfigs to move') + help='a file containing a list of defconfigs to move, ' + "one per line (for example 'snow_defconfig') " + "or '-' to read from stdin") parser.add_option('-n', '--dry-run', action='store_true', default=False, help='perform a trial run (show log with no changes)') parser.add_option('-e', '--exit-on-error', action='store_true', -- cgit v0.10.2 From ddf91c64233e2a62cc7d70b3a22035a4161e418e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 1 Jun 2017 19:39:00 -0600 Subject: moveconfig: Tidy up the documentation and add hints The newest clean-up features are not mentioned in the docs. Fix this and add a few hints for particular workflows that are hopefully helpful. Signed-off-by: Simon Glass diff --git a/tools/moveconfig.py b/tools/moveconfig.py index c581fb6..a6d473d 100755 --- a/tools/moveconfig.py +++ b/tools/moveconfig.py @@ -115,6 +115,23 @@ use your own. Instead of modifying the list directly, you can give them via environments. +Tips and trips +-------------- + +To sync only X86 defconfigs: + + ./tools/moveconfig.py -s -d <(grep -l X86 configs/*) + +or: + + grep -l X86 configs/* | ./tools/moveconfig.py -s -d - + +To process CONFIG_CMD_FPGAD only for a subset of configs based on path match: + + ls configs/{hrcon*,iocon*,strider*} | \ + ./tools/moveconfig.py -Cy CONFIG_CMD_FPGAD -d - + + Available options ----------------- @@ -128,7 +145,7 @@ Available options -d, --defconfigs Specify a file containing a list of defconfigs to move. The defconfig - files can be given with shell-style wildcards. + files can be given with shell-style wildcards. Use '-' to read from stdin. -n, --dry-run Perform a trial run that does not make any changes. It is useful to @@ -169,7 +186,8 @@ Available options -y, --yes Instead of prompting, automatically go ahead with all operations. This - includes cleaning up headers and CONFIG_SYS_EXTRA_OPTIONS. + includes cleaning up headers, CONFIG_SYS_EXTRA_OPTIONS, the config whitelist + and the README. To see the complete list of supported options, run -- cgit v0.10.2 From f3b8e6470cb2d599ce021e3785827a9d4e360db0 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 1 Jun 2017 19:39:01 -0600 Subject: moveconfig: Add a constant for auto.conf This filename is used a few times. Move it to a constant before adding further uses. Signed-off-by: Simon Glass diff --git a/tools/moveconfig.py b/tools/moveconfig.py index a6d473d..eb7ada2 100755 --- a/tools/moveconfig.py +++ b/tools/moveconfig.py @@ -262,6 +262,9 @@ COLOR_LIGHT_PURPLE = '1;35' COLOR_LIGHT_CYAN = '1;36' COLOR_WHITE = '1;37' +AUTO_CONF_PATH = 'include/config/auto.conf' + + ### helper functions ### def get_devnull(): """Get the file object of '/dev/null' device.""" @@ -751,8 +754,7 @@ class KconfigParser: self.autoconf = os.path.join(build_dir, 'include', 'autoconf.mk') self.spl_autoconf = os.path.join(build_dir, 'spl', 'include', 'autoconf.mk') - self.config_autoconf = os.path.join(build_dir, 'include', 'config', - 'auto.conf') + self.config_autoconf = os.path.join(build_dir, AUTO_CONF_PATH) self.defconfig = os.path.join(build_dir, 'defconfig') def get_cross_compile(self): @@ -1070,7 +1072,7 @@ class Slot: self.state = STATE_DEFCONFIG def do_autoconf(self): - """Run 'make include/config/auto.conf'.""" + """Run 'make AUTO_CONF_PATH'.""" self.cross_compile = self.parser.get_cross_compile() if self.cross_compile is None: @@ -1083,7 +1085,7 @@ class Slot: if self.cross_compile: cmd.append('CROSS_COMPILE=%s' % self.cross_compile) cmd.append('KCONFIG_IGNORE_DUPLICATES=1') - cmd.append('include/config/auto.conf') + cmd.append(AUTO_CONF_PATH) self.ps = subprocess.Popen(cmd, stdout=self.devnull, stderr=subprocess.PIPE, cwd=self.current_src_dir) -- cgit v0.10.2 From d73fcb12e27277d5b3e80399b4b3ec41abcd80d2 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 1 Jun 2017 19:39:02 -0600 Subject: moveconfig: Support building a simple config database Add a -b option which scans all the defconfigs and builds a database of all the CONFIG options used by each. This is useful for querying later. At present this only works with the separate -b option, which does not move any configs. It would be possible to adjust the script to build the database automatically when moving configs, but this might not be useful as the database does not change that often. Signed-off-by: Simon Glass diff --git a/tools/moveconfig.py b/tools/moveconfig.py index eb7ada2..00101ba 100755 --- a/tools/moveconfig.py +++ b/tools/moveconfig.py @@ -203,11 +203,13 @@ import glob import multiprocessing import optparse import os +import Queue import re import shutil import subprocess import sys import tempfile +import threading import time SHOW_GNU_MAKE = 'scripts/show-gnu-make' @@ -263,6 +265,7 @@ COLOR_LIGHT_CYAN = '1;36' COLOR_WHITE = '1;37' AUTO_CONF_PATH = 'include/config/auto.conf' +CONFIG_DATABASE = 'moveconfig.db' ### helper functions ### @@ -940,6 +943,34 @@ class KconfigParser: return log + +class DatabaseThread(threading.Thread): + """This thread processes results from Slot threads. + + It collects the data in the master config directary. There is only one + result thread, and this helps to serialise the build output. + """ + def __init__(self, config_db, db_queue): + """Set up a new result thread + + Args: + builder: Builder which will be sent each result + """ + threading.Thread.__init__(self) + self.config_db = config_db + self.db_queue= db_queue + + def run(self): + """Called to start up the result thread. + + We collect the next result job and pass it on to the build. + """ + while True: + defconfig, configs = self.db_queue.get() + self.config_db[defconfig] = configs + self.db_queue.task_done() + + class Slot: """A slot to store a subprocess. @@ -949,7 +980,8 @@ class Slot: for faster processing. """ - def __init__(self, configs, options, progress, devnull, make_cmd, reference_src_dir): + def __init__(self, configs, options, progress, devnull, make_cmd, + reference_src_dir, db_queue): """Create a new process slot. Arguments: @@ -960,6 +992,7 @@ class Slot: make_cmd: command name of GNU Make. reference_src_dir: Determine the true starting config state from this source tree. + db_queue: output queue to write config info for the database """ self.options = options self.progress = progress @@ -967,6 +1000,7 @@ class Slot: self.devnull = devnull self.make_cmd = (make_cmd, 'O=' + self.build_dir) self.reference_src_dir = reference_src_dir + self.db_queue = db_queue self.parser = KconfigParser(configs, options, self.build_dir) self.state = STATE_IDLE self.failed_boards = set() @@ -1042,6 +1076,8 @@ class Slot: if self.current_src_dir: self.current_src_dir = None self.do_defconfig() + elif self.options.build_db: + self.do_build_db() else: self.do_savedefconfig() elif self.state == STATE_SAVEDEFCONFIG: @@ -1091,6 +1127,17 @@ class Slot: cwd=self.current_src_dir) self.state = STATE_AUTOCONF + def do_build_db(self): + """Add the board to the database""" + configs = {} + with open(os.path.join(self.build_dir, AUTO_CONF_PATH)) as fd: + for line in fd.readlines(): + if line.startswith('CONFIG'): + config, value = line.split('=', 1) + configs[config] = value.rstrip() + self.db_queue.put([self.defconfig, configs]) + self.finish(True) + def do_savedefconfig(self): """Update the .config and run 'make savedefconfig'.""" @@ -1173,7 +1220,7 @@ class Slots: """Controller of the array of subprocess slots.""" - def __init__(self, configs, options, progress, reference_src_dir): + def __init__(self, configs, options, progress, reference_src_dir, db_queue): """Create a new slots controller. Arguments: @@ -1182,6 +1229,7 @@ class Slots: progress: A progress indicator. reference_src_dir: Determine the true starting config state from this source tree. + db_queue: output queue to write config info for the database """ self.options = options self.slots = [] @@ -1189,7 +1237,7 @@ class Slots: make_cmd = get_make_cmd() for i in range(options.jobs): self.slots.append(Slot(configs, options, progress, devnull, - make_cmd, reference_src_dir)) + make_cmd, reference_src_dir, db_queue)) def add(self, defconfig): """Add a new subprocess if a vacant slot is found. @@ -1301,7 +1349,7 @@ class ReferenceSource: return self.src_dir -def move_config(configs, options): +def move_config(configs, options, db_queue): """Move config options to defconfig files. Arguments: @@ -1311,6 +1359,8 @@ def move_config(configs, options): if len(configs) == 0: if options.force_sync: print 'No CONFIG is specified. You are probably syncing defconfigs.', + elif options.build_db: + print 'Building %s database' % CONFIG_DATABASE else: print 'Neither CONFIG nor --force-sync is specified. Nothing will happen.', else: @@ -1329,7 +1379,7 @@ def move_config(configs, options): defconfigs = get_all_defconfigs() progress = Progress(len(defconfigs)) - slots = Slots(configs, options, progress, reference_src_dir) + slots = Slots(configs, options, progress, reference_src_dir, db_queue) # Main loop to process defconfig files: # Add a new subprocess into a vacant slot. @@ -1356,6 +1406,8 @@ def main(): parser = optparse.OptionParser() # Add options here + parser.add_option('-b', '--build-db', action='store_true', default=False, + help='build a CONFIG database') parser.add_option('-c', '--color', action='store_true', default=False, help='display the log in color') parser.add_option('-C', '--commit', action='store_true', default=False, @@ -1388,7 +1440,7 @@ def main(): (options, configs) = parser.parse_args() - if len(configs) == 0 and not options.force_sync: + if len(configs) == 0 and not any((options.force_sync, options.build_db)): parser.print_usage() sys.exit(1) @@ -1398,10 +1450,17 @@ def main(): check_top_directory() + config_db = {} + db_queue = Queue.Queue() + t = DatabaseThread(config_db, db_queue) + t.setDaemon(True) + t.start() + if not options.cleanup_headers_only: check_clean_directory() update_cross_compile(options.color) - move_config(configs, options) + move_config(configs, options, db_queue) + db_queue.join() if configs: cleanup_headers(configs, options) @@ -1421,5 +1480,13 @@ def main(): msg += '\n\nRsync all defconfig files using moveconfig.py' subprocess.call(['git', 'commit', '-s', '-m', msg]) + if options.build_db: + with open(CONFIG_DATABASE, 'w') as fd: + for defconfig, configs in config_db.iteritems(): + print >>fd, '%s' % defconfig + for config in sorted(configs.keys()): + print >>fd, ' %s=%s' % (config, configs[config]) + print >>fd + if __name__ == '__main__': main() -- cgit v0.10.2 From 99b66605f05e6de13f43ef1033809b648406f98e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 1 Jun 2017 19:39:03 -0600 Subject: moveconfig: Support looking for implied CONFIG options Some CONFIG options can be implied by others and this can help to reduce the size of the defconfig files. For example, CONFIG_X86 implies CONFIG_CMD_IRQ, so we can put 'imply CMD_IRQ' under 'config X86' and all x86 boards will have that option, avoiding adding CONFIG_CMD_IRQ to each of the x86 defconfig files. Add a -i option which searches for such options. Signed-off-by: Simon Glass Reviewed-by: Heiko Schocher diff --git a/tools/moveconfig.py b/tools/moveconfig.py index 00101ba..6fa394a 100755 --- a/tools/moveconfig.py +++ b/tools/moveconfig.py @@ -132,6 +132,69 @@ To process CONFIG_CMD_FPGAD only for a subset of configs based on path match: ./tools/moveconfig.py -Cy CONFIG_CMD_FPGAD -d - +Finding implied CONFIGs +----------------------- + +Some CONFIG options can be implied by others and this can help to reduce +the size of the defconfig files. For example, CONFIG_X86 implies +CONFIG_CMD_IRQ, so we can put 'imply CMD_IRQ' under 'config X86' and +all x86 boards will have that option, avoiding adding CONFIG_CMD_IRQ to +each of the x86 defconfig files. + +This tool can help find such configs. To use it, first build a database: + + ./tools/moveconfig.py -b + +Then try to query it: + + ./tools/moveconfig.py -i CONFIG_CMD_IRQ + CONFIG_CMD_IRQ found in 311/2384 defconfigs + 44 : CONFIG_SYS_FSL_ERRATUM_IFC_A002769 + 41 : CONFIG_SYS_FSL_ERRATUM_A007075 + 31 : CONFIG_SYS_FSL_DDR_VER_44 + 28 : CONFIG_ARCH_P1010 + 28 : CONFIG_SYS_FSL_ERRATUM_P1010_A003549 + 28 : CONFIG_SYS_FSL_ERRATUM_SEC_A003571 + 28 : CONFIG_SYS_FSL_ERRATUM_IFC_A003399 + 25 : CONFIG_SYS_FSL_ERRATUM_A008044 + 22 : CONFIG_ARCH_P1020 + 21 : CONFIG_SYS_FSL_DDR_VER_46 + 20 : CONFIG_MAX_PIRQ_LINKS + 20 : CONFIG_HPET_ADDRESS + 20 : CONFIG_X86 + 20 : CONFIG_PCIE_ECAM_SIZE + 20 : CONFIG_IRQ_SLOT_COUNT + 20 : CONFIG_I8259_PIC + 20 : CONFIG_CPU_ADDR_BITS + 20 : CONFIG_RAMBASE + 20 : CONFIG_SYS_FSL_ERRATUM_A005871 + 20 : CONFIG_PCIE_ECAM_BASE + 20 : CONFIG_X86_TSC_TIMER + 20 : CONFIG_I8254_TIMER + 20 : CONFIG_CMD_GETTIME + 19 : CONFIG_SYS_FSL_ERRATUM_A005812 + 18 : CONFIG_X86_RUN_32BIT + 17 : CONFIG_CMD_CHIP_CONFIG + ... + +This shows a list of config options which might imply CONFIG_CMD_EEPROM along +with how many defconfigs they cover. From this you can see that CONFIG_X86 +implies CONFIG_CMD_EEPROM. Therefore, instead of adding CONFIG_CMD_EEPROM to +the defconfig of every x86 board, you could add a single imply line to the +Kconfig file: + + config X86 + bool "x86 architecture" + ... + imply CMD_EEPROM + +That will cover 20 defconfigs. Many of the options listed are not suitable as +they are not related. E.g. it would be odd for CONFIG_CMD_GETTIME to imply +CMD_EEPROM. + +Using this search you can reduce the size of moveconfig patches. + + Available options ----------------- @@ -195,6 +258,7 @@ To see the complete list of supported options, run """ +import collections import copy import difflib import filecmp @@ -1398,6 +1462,148 @@ def move_config(configs, options, db_queue): slots.show_failed_boards() slots.show_suspicious_boards() +def imply_config(config_list, find_superset=False): + """Find CONFIG options which imply those in the list + + Some CONFIG options can be implied by others and this can help to reduce + the size of the defconfig files. For example, CONFIG_X86 implies + CONFIG_CMD_IRQ, so we can put 'imply CMD_IRQ' under 'config X86' and + all x86 boards will have that option, avoiding adding CONFIG_CMD_IRQ to + each of the x86 defconfig files. + + This function uses the moveconfig database to find such options. It + displays a list of things that could possibly imply those in the list. + The algorithm ignores any that start with CONFIG_TARGET since these + typically refer to only a few defconfigs (often one). It also does not + display a config with less than 5 defconfigs. + + The algorithm works using sets. For each target config in config_list: + - Get the set 'defconfigs' which use that target config + - For each config (from a list of all configs): + - Get the set 'imply_defconfig' of defconfigs which use that config + - + - If imply_defconfigs contains anything not in defconfigs then + this config does not imply the target config + + Params: + config_list: List of CONFIG options to check (each a string) + find_superset: True to look for configs which are a superset of those + already found. So for example if CONFIG_EXYNOS5 implies an option, + but CONFIG_EXYNOS covers a larger set of defconfigs and also + implies that option, this will drop the former in favour of the + latter. In practice this option has not proved very used. + + Note the terminoloy: + config - a CONFIG_XXX options (a string, e.g. 'CONFIG_CMD_EEPROM') + defconfig - a defconfig file (a string, e.g. 'configs/snow_defconfig') + """ + # key is defconfig name, value is dict of (CONFIG_xxx, value) + config_db = {} + + # Holds a dict containing the set of defconfigs that contain each config + # key is config, value is set of defconfigs using that config + defconfig_db = collections.defaultdict(set) + + # Set of all config options we have seen + all_configs = set() + + # Set of all defconfigs we have seen + all_defconfigs = set() + + # Read in the database + configs = {} + with open(CONFIG_DATABASE) as fd: + for line in fd.readlines(): + line = line.rstrip() + if not line: # Separator between defconfigs + config_db[defconfig] = configs + all_defconfigs.add(defconfig) + configs = {} + elif line[0] == ' ': # CONFIG line + config, value = line.strip().split('=', 1) + configs[config] = value + defconfig_db[config].add(defconfig) + all_configs.add(config) + else: # New defconfig + defconfig = line + + # Work through each target config option in tern, independently + for config in config_list: + defconfigs = defconfig_db.get(config) + if not defconfigs: + print '%s not found in any defconfig' % config + continue + + # Get the set of defconfigs without this one (since a config cannot + # imply itself) + non_defconfigs = all_defconfigs - defconfigs + num_defconfigs = len(defconfigs) + print '%s found in %d/%d defconfigs' % (config, num_defconfigs, + len(all_configs)) + + # This will hold the results: key=config, value=defconfigs containing it + imply_configs = {} + rest_configs = all_configs - set([config]) + + # Look at every possible config, except the target one + for imply_config in rest_configs: + if 'CONFIG_TARGET' in imply_config: + continue + + # Find set of defconfigs that have this config + imply_defconfig = defconfig_db[imply_config] + + # Get the intersection of this with defconfigs containing the + # target config + common_defconfigs = imply_defconfig & defconfigs + + # Get the set of defconfigs containing this config which DO NOT + # also contain the taret config. If this set is non-empty it means + # that this config affects other defconfigs as well as (possibly) + # the ones affected by the target config. This means it implies + # things we don't want to imply. + not_common_defconfigs = imply_defconfig & non_defconfigs + if not_common_defconfigs: + continue + + # If there are common defconfigs, imply_config may be useful + if common_defconfigs: + skip = False + if find_superset: + for prev in imply_configs.keys(): + prev_count = len(imply_configs[prev]) + count = len(common_defconfigs) + if (prev_count > count and + (imply_configs[prev] & common_defconfigs == + common_defconfigs)): + # skip imply_config because prev is a superset + skip = True + break + elif count > prev_count: + # delete prev because imply_config is a superset + del imply_configs[prev] + if not skip: + imply_configs[imply_config] = common_defconfigs + + # Now we have a dict imply_configs of configs which imply each config + # The value of each dict item is the set of defconfigs containing that + # config. Rank them so that we print the configs that imply the largest + # number of defconfigs first. + ranked_configs = sorted(imply_configs, + key=lambda k: len(imply_configs[k]), reverse=True) + for config in ranked_configs: + num_common = len(imply_configs[config]) + + # Don't bother if there are less than 5 defconfigs affected. + if num_common < 5: + continue + missing = defconfigs - imply_configs[config] + missing_str = ', '.join(missing) if missing else 'all' + missing_str = '' + print ' %d : %-30s%s' % (num_common, config.ljust(30), + missing_str) + + def main(): try: cpu_count = multiprocessing.cpu_count() @@ -1416,6 +1622,8 @@ def main(): help='a file containing a list of defconfigs to move, ' "one per line (for example 'snow_defconfig') " "or '-' to read from stdin") + parser.add_option('-i', '--imply', action='store_true', default=False, + help='find options which imply others') parser.add_option('-n', '--dry-run', action='store_true', default=False, help='perform a trial run (show log with no changes)') parser.add_option('-e', '--exit-on-error', action='store_true', @@ -1440,7 +1648,8 @@ def main(): (options, configs) = parser.parse_args() - if len(configs) == 0 and not any((options.force_sync, options.build_db)): + if len(configs) == 0 and not any((options.force_sync, options.build_db, + options.imply)): parser.print_usage() sys.exit(1) @@ -1450,6 +1659,10 @@ def main(): check_top_directory() + if options.imply: + imply_config(configs) + return + config_db = {} db_queue = Queue.Queue() t = DatabaseThread(config_db, db_queue) -- cgit v0.10.2 From 6b20c347a08f754dd02796ed394f81cf83ae30cd Mon Sep 17 00:00:00 2001 From: Alison Chaiken Date: Sun, 4 Jun 2017 15:11:20 -0700 Subject: sandbox: README: fix partition command invocation The instructions for creating a disk image that are presently in README.sandbox fail because sfdisk doesn't know about GPT. Signed-off-by: Alison Chaiken Reviewed-by: Simon Glass Tested-by: Simon Glass diff --git a/board/sandbox/README.sandbox b/board/sandbox/README.sandbox index 02d8ab3..9dc2eb0 100644 --- a/board/sandbox/README.sandbox +++ b/board/sandbox/README.sandbox @@ -333,7 +333,7 @@ the contents of the root directory on the second partion of the image A disk image can be created using the following commands: $> truncate -s 1200M ./disk.raw -$> echo -e "label: gpt\n,64M,U\n,,L" | /usr/sbin/sfdisk ./disk.raw +$> echo -e "label: gpt\n,64M,U\n,,L" | /usr/sbin/sgdisk ./disk.raw $> lodev=`sudo losetup -P -f --show ./disk.raw` $> sudo mkfs.vfat -n EFI -v ${lodev}p1 $> sudo mkfs.ext4 -L ROOT -v ${lodev}p2 -- cgit v0.10.2 From 564cf25d5b1b90ae790e2b7619292935f40b13e6 Mon Sep 17 00:00:00 2001 From: Alison Chaiken Date: Sun, 4 Jun 2017 15:11:21 -0700 Subject: cmd gpt: test in sandbox Make minor changes to README.gpt and sandbox_defconfig to support testing of the gpt command's functionality in the sandbox. Signed-off-by: Alison Chaiken diff --git a/doc/README.gpt b/doc/README.gpt index 3fcd835..c0acc8a 100644 --- a/doc/README.gpt +++ b/doc/README.gpt @@ -210,6 +210,16 @@ U-BOOT> gpt verify mmc 0 $partitions U-BOOT> if test $? = 0; then echo "GPT OK"; else echo "GPT ERR"; fi +The GPT functionality may be tested with the 'sandbox' board by +creating a disk image as described under 'Block Device Emulation' in +board/sandbox/README.sandbox: + +=>host bind 0 ./disk.raw +=> gpt read host 0 +[ . . . ] +=> gpt flip host 0 +[ . . . ] + Partition type GUID: ==================== -- cgit v0.10.2 From 2cce586651bbeb0489c6cc6f04489f65bd039b9e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 13 Jun 2017 21:10:06 -0600 Subject: dtoc: Support multiple compatible strings in a node Sometimes a node will have multiple compatible strings. Drivers may use one or the other so the best approach seems to be to #define them to be equivalent. Update dtoc to support this. Signed-off-by: Simon Glass Tested-by: Kever Yang diff --git a/doc/driver-model/of-plat.txt b/doc/driver-model/of-plat.txt index 0063bfe..3ed8c75 100644 --- a/doc/driver-model/of-plat.txt +++ b/doc/driver-model/of-plat.txt @@ -156,6 +156,11 @@ This avoids the code overhead of converting the device tree data to platform data in the driver. The ofdata_to_platdata() method should therefore do nothing in such a driver. +Where a node has multiple compatible strings, a #define is used to make them +equivalent, e.g.: + +#define dtd_rockchip_rk3299_dw_mshc dtd_rockchip_rk3288_dw_mshc + Converting of-platdata to a useful form --------------------------------------- diff --git a/tools/dtoc/dtoc.py b/tools/dtoc/dtoc.py index 08e35f1..c0ab13a 100755 --- a/tools/dtoc/dtoc.py +++ b/tools/dtoc/dtoc.py @@ -88,6 +88,7 @@ class DtbPlatdata: self._phandle_node = {} self._outfile = None self._lines = [] + self._aliases = {} def SetupOutput(self, fname): """Set up the output destination @@ -159,9 +160,10 @@ class DtbPlatdata: C identifier for the first compatible string """ compat = node.props['compatible'].value + aliases = [] if type(compat) == list: - compat = compat[0] - return Conv_name_to_c(compat) + compat, aliases = compat[0], compat[1:] + return Conv_name_to_c(compat), [Conv_name_to_c(a) for a in aliases] def ScanDtb(self): """Scan the device tree to obtain a tree of notes and properties @@ -239,7 +241,7 @@ class DtbPlatdata: """ structs = {} for node in self._valid_nodes: - node_name = self.GetCompatName(node) + node_name, _ = self.GetCompatName(node) fields = {} # Get a list of all the valid properties in this node. @@ -263,12 +265,17 @@ class DtbPlatdata: upto = 0 for node in self._valid_nodes: - node_name = self.GetCompatName(node) + node_name, _ = self.GetCompatName(node) struct = structs[node_name] for name, prop in node.props.items(): if name not in PROP_IGNORE_LIST and name[0] != '#': prop.Widen(struct[name]) upto += 1 + + struct_name, aliases = self.GetCompatName(node) + for alias in aliases: + self._aliases[alias] = struct_name + return structs def ScanPhandles(self): @@ -327,13 +334,17 @@ class DtbPlatdata: self.Out(';\n') self.Out('};\n') + for alias, struct_name in self._aliases.iteritems(): + self.Out('#define %s%s %s%s\n'% (STRUCT_PREFIX, alias, + STRUCT_PREFIX, struct_name)) + def OutputNode(self, node): """Output the C code for a node Args: node: node to output """ - struct_name = self.GetCompatName(node) + struct_name, _ = self.GetCompatName(node) var_name = Conv_name_to_c(node.name) self.Buf('static struct %s%s %s%s = {\n' % (STRUCT_PREFIX, struct_name, VAL_PREFIX, var_name)) @@ -384,8 +395,11 @@ class DtbPlatdata: """Generate device defintions for the platform data This writes out C platform data initialisation data and - U_BOOT_DEVICE() declarations for each valid node. See the - documentation in README.of-plat for more information. + U_BOOT_DEVICE() declarations for each valid node. Where a node has + multiple compatible strings, a #define is used to make them equivalent. + + See the documentation in doc/driver-model/of-plat.txt for more + information. """ self.Out('#include \n') self.Out('#include \n') -- cgit v0.10.2 From fedb428c5beb8776451118f5adc976770a526a33 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 14 Jun 2017 21:28:21 -0600 Subject: Convert CONFIG_SCSI to Kconfig This converts the following to Kconfig: CONFIG_SCSI Signed-off-by: Simon Glass Reviewed-by: Bin Meng diff --git a/README b/README index ee35dec..de8ba81 100644 --- a/README +++ b/README @@ -826,7 +826,6 @@ The following options need to be configured: CONFIG_CMD_RUN run command in env variable CONFIG_CMD_SANDBOX * sb command to access sandbox features CONFIG_CMD_SAVES * save S record dump - CONFIG_SCSI * SCSI Support CONFIG_CMD_SDRAM * print SDRAM configuration information (requires CONFIG_CMD_I2C) CONFIG_CMD_SF * Read/write/erase SPI NOR flash diff --git a/arch/Kconfig b/arch/Kconfig index fe1b991..8d5d77a 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -75,6 +75,7 @@ config SANDBOX imply FAT_WRITE imply HASH_VERIFY imply LZMA + imply SCSI config SH bool "SuperH architecture" diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 5f2048b..d43aaac 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -792,6 +792,7 @@ config TARGET_LS2080AQDS select BOARD_LATE_INIT select SUPPORT_SPL select ARCH_MISC_INIT + imply SCSI help Support for Freescale LS2080AQDS platform The LS2080A Development System (QDS) is a high-performance @@ -806,6 +807,7 @@ config TARGET_LS2080ARDB select BOARD_LATE_INIT select SUPPORT_SPL select ARCH_MISC_INIT + imply SCSI help Support for Freescale LS2080ARDB platform. The LS2080A Reference design board (RDB) is a high-performance @@ -866,6 +868,7 @@ config TARGET_LS1012ARDB select ARCH_LS1012A select ARM64 select BOARD_LATE_INIT + imply SCSI help Support for Freescale LS1012ARDB platform. The LS1012A Reference design board (RDB) is a high-performance @@ -894,6 +897,7 @@ config TARGET_LS1021AQDS select LS1_DEEP_SLEEP select SYS_FSL_DDR select BOARD_EARLY_INIT_F + imply SCSI config TARGET_LS1021ATWR bool "Support ls1021atwr" @@ -906,6 +910,7 @@ config TARGET_LS1021ATWR select ARCH_SUPPORT_PSCI select LS1_DEEP_SLEEP select BOARD_EARLY_INIT_F + imply SCSI config TARGET_LS1021AIOT bool "Support ls1021aiot" @@ -916,6 +921,7 @@ config TARGET_LS1021AIOT select SUPPORT_SPL select ARCH_LS1021A select ARCH_SUPPORT_PSCI + imply SCSI help Support for Freescale LS1021AIOT platform. The LS1021A Freescale board (IOT) is a high-performance @@ -930,6 +936,7 @@ config TARGET_LS1043AQDS select BOARD_LATE_INIT select SUPPORT_SPL select BOARD_EARLY_INIT_F + imply SCSI help Support for Freescale LS1043AQDS platform. @@ -941,6 +948,7 @@ config TARGET_LS1043ARDB select BOARD_LATE_INIT select SUPPORT_SPL select BOARD_EARLY_INIT_F + imply SCSI help Support for Freescale LS1043ARDB platform. @@ -953,6 +961,7 @@ config TARGET_LS1046AQDS select SUPPORT_SPL select DM_SPI_FLASH if DM_SPI select BOARD_EARLY_INIT_F + imply SCSI help Support for Freescale LS1046AQDS platform. The LS1046A Development System (QDS) is a high-performance @@ -969,6 +978,7 @@ config TARGET_LS1046ARDB select DM_SPI_FLASH if DM_SPI select POWER_MC34VR500 select BOARD_EARLY_INIT_F + imply SCSI help Support for Freescale LS1046ARDB platform. The LS1046A Reference Design Board (RDB) is a high-performance diff --git a/arch/arm/cpu/armv7/ls102xa/Kconfig b/arch/arm/cpu/armv7/ls102xa/Kconfig index b61f3cd..6a013b2 100644 --- a/arch/arm/cpu/armv7/ls102xa/Kconfig +++ b/arch/arm/cpu/armv7/ls102xa/Kconfig @@ -14,6 +14,7 @@ config ARCH_LS1021A select SYS_FSL_HAS_SEC select SYS_FSL_SEC_COMPAT_5 select SYS_FSL_SEC_LE + imply SCSI menu "LS102xA architecture" depends on ARCH_LS1021A diff --git a/arch/arm/cpu/armv8/fsl-layerscape/Kconfig b/arch/arm/cpu/armv8/fsl-layerscape/Kconfig index d8b285d..5825f9b 100644 --- a/arch/arm/cpu/armv8/fsl-layerscape/Kconfig +++ b/arch/arm/cpu/armv8/fsl-layerscape/Kconfig @@ -26,6 +26,7 @@ config ARCH_LS1043A select SYS_FSL_HAS_DDR4 select ARCH_EARLY_INIT_R select BOARD_EARLY_INIT_F + imply SCSI config ARCH_LS1046A bool @@ -46,6 +47,7 @@ config ARCH_LS1046A select SYS_FSL_SRDS_2 select ARCH_EARLY_INIT_R select BOARD_EARLY_INIT_F + imply SCSI config ARCH_LS2080A bool diff --git a/arch/arm/include/asm/arch-ls102xa/config.h b/arch/arm/include/asm/arch-ls102xa/config.h index 5c4da0f..fc954c5 100644 --- a/arch/arm/include/asm/arch-ls102xa/config.h +++ b/arch/arm/include/asm/arch-ls102xa/config.h @@ -81,7 +81,6 @@ /* SATA */ #define AHCI_BASE_ADDR (CONFIG_SYS_IMMR + 0x02200000) -#define CONFIG_SCSI #define CONFIG_LIBATA #define CONFIG_SCSI_AHCI #define CONFIG_SCSI_AHCI_PLAT diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig index 6ae54ef..89476a6 100644 --- a/arch/arm/mach-mvebu/Kconfig +++ b/arch/arm/mach-mvebu/Kconfig @@ -77,6 +77,7 @@ config TARGET_CLEARFOG config TARGET_MVEBU_ARMADA_37XX bool "Support Armada 37xx platforms" select ARMADA_3700 + imply SCSI config TARGET_DB_88F6720 bool "Support DB-88F6720 Armada 375" @@ -94,6 +95,7 @@ config TARGET_MVEBU_ARMADA_8K bool "Support Armada 7k/8k platforms" select ARMADA_8K select BOARD_LATE_INIT + imply SCSI config TARGET_DB_MV784MP_GP bool "Support db-mv784mp-gp" diff --git a/arch/arm/mach-omap2/omap5/Kconfig b/arch/arm/mach-omap2/omap5/Kconfig index 1a66abd..08f45bc 100644 --- a/arch/arm/mach-omap2/omap5/Kconfig +++ b/arch/arm/mach-omap2/omap5/Kconfig @@ -25,12 +25,14 @@ config TARGET_DRA7XX_EVM select DRA7XX select TI_I2C_BOARD_DETECT select PHYS_64BIT + imply SCSI config TARGET_AM57XX_EVM bool "AM57XX" select BOARD_LATE_INIT select DRA7XX select TI_I2C_BOARD_DETECT + imply SCSI endchoice diff --git a/arch/powerpc/cpu/mpc85xx/Kconfig b/arch/powerpc/cpu/mpc85xx/Kconfig index 4db687c..a4b2761 100644 --- a/arch/powerpc/cpu/mpc85xx/Kconfig +++ b/arch/powerpc/cpu/mpc85xx/Kconfig @@ -117,6 +117,7 @@ config TARGET_MPC8572DS select ARCH_MPC8572 # Use DDR3 controller with DDR2 DIMMs on this board select SYS_FSL_DDRC_GEN3 + imply SCSI config TARGET_P1010RDB_PA bool "Support P1010RDB_PA" diff --git a/arch/powerpc/cpu/mpc86xx/Kconfig b/arch/powerpc/cpu/mpc86xx/Kconfig index fcac658..2cc180d 100644 --- a/arch/powerpc/cpu/mpc86xx/Kconfig +++ b/arch/powerpc/cpu/mpc86xx/Kconfig @@ -21,6 +21,7 @@ config TARGET_MPC8610HPCD config TARGET_MPC8641HPCN bool "Support MPC8641HPCN" select ARCH_MPC8641 + imply SCSI config TARGET_XPEDITE517X bool "Support xpedite517x" diff --git a/board/congatec/Kconfig b/board/congatec/Kconfig index 875d1ae..ff5a1d8 100644 --- a/board/congatec/Kconfig +++ b/board/congatec/Kconfig @@ -13,6 +13,7 @@ choice config TARGET_CONGA_QEVAL20_QA3_E3845 bool "congatec QEVAL 2.0 & conga-QA3/E3845" select BOARD_LATE_INIT + imply SCSI help This is the congatec Qseven 2.0 evaluation carrier board (conga-QEVAL) equipped with the conga-QA3/E3845-4G SoM. diff --git a/board/dfi/Kconfig b/board/dfi/Kconfig index 25d0a11..d2a1d78 100644 --- a/board/dfi/Kconfig +++ b/board/dfi/Kconfig @@ -12,6 +12,7 @@ choice config TARGET_DFI_BT700 bool "DFI BT700 BayTrail" + imply SCSI help This is the DFI Q7X-151 baseboard equipped with the DFI BayTrail Bt700 SoM. It contains an Atom E3845 with diff --git a/configs/A10-OLinuXino-Lime_defconfig b/configs/A10-OLinuXino-Lime_defconfig index ec16a44..9143022 100644 --- a/configs/A10-OLinuXino-Lime_defconfig +++ b/configs/A10-OLinuXino-Lime_defconfig @@ -18,6 +18,7 @@ CONFIG_SPL_I2C_SUPPORT=y # CONFIG_SPL_DOS_PARTITION is not set # CONFIG_SPL_ISO_PARTITION is not set # CONFIG_SPL_EFI_PARTITION is not set +CONFIG_SCSI=y CONFIG_SUN4I_EMAC=y CONFIG_AXP_ALDO3_VOLT=2800 CONFIG_AXP_ALDO4_VOLT=2800 diff --git a/configs/A20-OLinuXino-Lime2_defconfig b/configs/A20-OLinuXino-Lime2_defconfig index 1f2daa6..f7b600b 100644 --- a/configs/A20-OLinuXino-Lime2_defconfig +++ b/configs/A20-OLinuXino-Lime2_defconfig @@ -20,6 +20,7 @@ CONFIG_CMD_USB_MASS_STORAGE=y # CONFIG_SPL_DOS_PARTITION is not set # CONFIG_SPL_ISO_PARTITION is not set # CONFIG_SPL_PARTITION_UUIDS is not set +CONFIG_SCSI=y CONFIG_DFU_RAM=y CONFIG_ETH_DESIGNWARE=y CONFIG_RGMII=y diff --git a/configs/A20-OLinuXino-Lime_defconfig b/configs/A20-OLinuXino-Lime_defconfig index 7f63d4a..182a8f5 100644 --- a/configs/A20-OLinuXino-Lime_defconfig +++ b/configs/A20-OLinuXino-Lime_defconfig @@ -16,6 +16,7 @@ CONFIG_SPL_I2C_SUPPORT=y # CONFIG_SPL_DOS_PARTITION is not set # CONFIG_SPL_ISO_PARTITION is not set # CONFIG_SPL_EFI_PARTITION is not set +CONFIG_SCSI=y CONFIG_ETH_DESIGNWARE=y CONFIG_SUN7I_GMAC=y CONFIG_AXP_ALDO3_VOLT=2800 diff --git a/configs/A20-OLinuXino_MICRO_defconfig b/configs/A20-OLinuXino_MICRO_defconfig index 89e87e7..ae98e41 100644 --- a/configs/A20-OLinuXino_MICRO_defconfig +++ b/configs/A20-OLinuXino_MICRO_defconfig @@ -19,6 +19,7 @@ CONFIG_SPL_I2C_SUPPORT=y # CONFIG_SPL_DOS_PARTITION is not set # CONFIG_SPL_ISO_PARTITION is not set # CONFIG_SPL_EFI_PARTITION is not set +CONFIG_SCSI=y CONFIG_ETH_DESIGNWARE=y CONFIG_SUN7I_GMAC=y CONFIG_AXP_ALDO3_VOLT=2800 diff --git a/configs/A20-Olimex-SOM-EVB_defconfig b/configs/A20-Olimex-SOM-EVB_defconfig index 6c87648..61fe5e6 100644 --- a/configs/A20-Olimex-SOM-EVB_defconfig +++ b/configs/A20-Olimex-SOM-EVB_defconfig @@ -20,6 +20,7 @@ CONFIG_SPL_I2C_SUPPORT=y # CONFIG_SPL_DOS_PARTITION is not set # CONFIG_SPL_ISO_PARTITION is not set # CONFIG_SPL_EFI_PARTITION is not set +CONFIG_SCSI=y CONFIG_ETH_DESIGNWARE=y CONFIG_RGMII=y CONFIG_SUN7I_GMAC=y diff --git a/configs/Bananapi_M2_Ultra_defconfig b/configs/Bananapi_M2_Ultra_defconfig index 4332eca..8c409fa 100644 --- a/configs/Bananapi_M2_Ultra_defconfig +++ b/configs/Bananapi_M2_Ultra_defconfig @@ -14,5 +14,6 @@ CONFIG_SPL_I2C_SUPPORT=y # CONFIG_CMD_IMLS is not set # CONFIG_CMD_FLASH is not set # CONFIG_CMD_FPGA is not set +CONFIG_SCSI=y CONFIG_AXP_DLDO4_VOLT=2500 CONFIG_AXP_ELDO3_VOLT=1200 diff --git a/configs/Bananapi_defconfig b/configs/Bananapi_defconfig index fe75eef..352a18e 100644 --- a/configs/Bananapi_defconfig +++ b/configs/Bananapi_defconfig @@ -17,6 +17,7 @@ CONFIG_SPL_I2C_SUPPORT=y # CONFIG_SPL_ISO_PARTITION is not set # CONFIG_SPL_EFI_PARTITION is not set CONFIG_NETCONSOLE=y +CONFIG_SCSI=y CONFIG_ETH_DESIGNWARE=y CONFIG_RGMII=y CONFIG_SUN7I_GMAC=y diff --git a/configs/Bananapro_defconfig b/configs/Bananapro_defconfig index df65922..4218d5a 100644 --- a/configs/Bananapro_defconfig +++ b/configs/Bananapro_defconfig @@ -19,6 +19,7 @@ CONFIG_SPL_I2C_SUPPORT=y # CONFIG_SPL_ISO_PARTITION is not set # CONFIG_SPL_EFI_PARTITION is not set CONFIG_NETCONSOLE=y +CONFIG_SCSI=y CONFIG_ETH_DESIGNWARE=y CONFIG_RGMII=y CONFIG_SUN7I_GMAC=y diff --git a/configs/Cubieboard2_defconfig b/configs/Cubieboard2_defconfig index 02c503f..dc2722a 100644 --- a/configs/Cubieboard2_defconfig +++ b/configs/Cubieboard2_defconfig @@ -15,6 +15,7 @@ CONFIG_SPL_I2C_SUPPORT=y # CONFIG_SPL_DOS_PARTITION is not set # CONFIG_SPL_ISO_PARTITION is not set # CONFIG_SPL_EFI_PARTITION is not set +CONFIG_SCSI=y CONFIG_ETH_DESIGNWARE=y CONFIG_SUN7I_GMAC=y CONFIG_USB_EHCI_HCD=y diff --git a/configs/Cubieboard_defconfig b/configs/Cubieboard_defconfig index a8e9c98..f83a691 100644 --- a/configs/Cubieboard_defconfig +++ b/configs/Cubieboard_defconfig @@ -15,5 +15,6 @@ CONFIG_SPL_I2C_SUPPORT=y # CONFIG_SPL_DOS_PARTITION is not set # CONFIG_SPL_ISO_PARTITION is not set # CONFIG_SPL_EFI_PARTITION is not set +CONFIG_SCSI=y CONFIG_SUN4I_EMAC=y CONFIG_USB_EHCI_HCD=y diff --git a/configs/Cubietruck_defconfig b/configs/Cubietruck_defconfig index f9d56c8..cbd535c 100644 --- a/configs/Cubietruck_defconfig +++ b/configs/Cubietruck_defconfig @@ -22,6 +22,7 @@ CONFIG_CMD_USB_MASS_STORAGE=y # CONFIG_SPL_DOS_PARTITION is not set # CONFIG_SPL_ISO_PARTITION is not set # CONFIG_SPL_PARTITION_UUIDS is not set +CONFIG_SCSI=y CONFIG_DFU_RAM=y CONFIG_ETH_DESIGNWARE=y CONFIG_RGMII=y diff --git a/configs/Itead_Ibox_A20_defconfig b/configs/Itead_Ibox_A20_defconfig index 4bae19f..bab25b4 100644 --- a/configs/Itead_Ibox_A20_defconfig +++ b/configs/Itead_Ibox_A20_defconfig @@ -15,6 +15,7 @@ CONFIG_SPL_I2C_SUPPORT=y # CONFIG_SPL_DOS_PARTITION is not set # CONFIG_SPL_ISO_PARTITION is not set # CONFIG_SPL_EFI_PARTITION is not set +CONFIG_SCSI=y CONFIG_ETH_DESIGNWARE=y CONFIG_SUN7I_GMAC=y CONFIG_USB_EHCI_HCD=y diff --git a/configs/Lamobo_R1_defconfig b/configs/Lamobo_R1_defconfig index cc29d60..2ec0847 100644 --- a/configs/Lamobo_R1_defconfig +++ b/configs/Lamobo_R1_defconfig @@ -17,6 +17,7 @@ CONFIG_SPL_I2C_SUPPORT=y # CONFIG_SPL_DOS_PARTITION is not set # CONFIG_SPL_ISO_PARTITION is not set # CONFIG_SPL_EFI_PARTITION is not set +CONFIG_SCSI=y CONFIG_ETH_DESIGNWARE=y CONFIG_RGMII=y CONFIG_SUN7I_GMAC=y diff --git a/configs/Linksprite_pcDuino3_Nano_defconfig b/configs/Linksprite_pcDuino3_Nano_defconfig index 80416cb..1e61cd2 100644 --- a/configs/Linksprite_pcDuino3_Nano_defconfig +++ b/configs/Linksprite_pcDuino3_Nano_defconfig @@ -17,6 +17,7 @@ CONFIG_SPL_I2C_SUPPORT=y # CONFIG_SPL_DOS_PARTITION is not set # CONFIG_SPL_ISO_PARTITION is not set # CONFIG_SPL_EFI_PARTITION is not set +CONFIG_SCSI=y CONFIG_ETH_DESIGNWARE=y CONFIG_RGMII=y CONFIG_SUN7I_GMAC=y diff --git a/configs/Linksprite_pcDuino3_defconfig b/configs/Linksprite_pcDuino3_defconfig index b9f89a0..6f4a02f 100644 --- a/configs/Linksprite_pcDuino3_defconfig +++ b/configs/Linksprite_pcDuino3_defconfig @@ -15,6 +15,7 @@ CONFIG_SPL_I2C_SUPPORT=y # CONFIG_SPL_DOS_PARTITION is not set # CONFIG_SPL_ISO_PARTITION is not set # CONFIG_SPL_EFI_PARTITION is not set +CONFIG_SCSI=y CONFIG_ETH_DESIGNWARE=y CONFIG_SUN7I_GMAC=y CONFIG_USB_EHCI_HCD=y diff --git a/configs/MPC8544DS_defconfig b/configs/MPC8544DS_defconfig index aef9bac..cb15afa 100644 --- a/configs/MPC8544DS_defconfig +++ b/configs/MPC8544DS_defconfig @@ -15,6 +15,7 @@ CONFIG_CMD_MII=y CONFIG_CMD_PING=y # CONFIG_CMD_HASH is not set CONFIG_CMD_EXT2=y +CONFIG_SCSI=y # CONFIG_MMC is not set CONFIG_MTD_NOR_FLASH=y CONFIG_NETDEVICES=y diff --git a/configs/MPC8610HPCD_defconfig b/configs/MPC8610HPCD_defconfig index d949990..6aef6d8 100644 --- a/configs/MPC8610HPCD_defconfig +++ b/configs/MPC8610HPCD_defconfig @@ -15,6 +15,7 @@ CONFIG_CMD_PING=y CONFIG_CMD_BMP=y CONFIG_CMD_EXT2=y CONFIG_DOS_PARTITION=y +CONFIG_SCSI=y # CONFIG_MMC is not set CONFIG_MTD_NOR_FLASH=y CONFIG_SYS_NS16550=y diff --git a/configs/Marsboard_A10_defconfig b/configs/Marsboard_A10_defconfig index 6b8bd1a..516a16f 100644 --- a/configs/Marsboard_A10_defconfig +++ b/configs/Marsboard_A10_defconfig @@ -11,6 +11,7 @@ CONFIG_SPL=y # CONFIG_SPL_DOS_PARTITION is not set # CONFIG_SPL_ISO_PARTITION is not set # CONFIG_SPL_EFI_PARTITION is not set +CONFIG_SCSI=y CONFIG_SUN4I_EMAC=y CONFIG_SUNXI_NO_PMIC=y CONFIG_USB_EHCI_HCD=y diff --git a/configs/Mele_A1000_defconfig b/configs/Mele_A1000_defconfig index 0442360..0c9e8d1 100644 --- a/configs/Mele_A1000_defconfig +++ b/configs/Mele_A1000_defconfig @@ -15,5 +15,6 @@ CONFIG_SPL_I2C_SUPPORT=y # CONFIG_SPL_DOS_PARTITION is not set # CONFIG_SPL_ISO_PARTITION is not set # CONFIG_SPL_EFI_PARTITION is not set +CONFIG_SCSI=y CONFIG_SUN4I_EMAC=y CONFIG_USB_EHCI_HCD=y diff --git a/configs/Mele_M5_defconfig b/configs/Mele_M5_defconfig index 4c377e3..400a165 100644 --- a/configs/Mele_M5_defconfig +++ b/configs/Mele_M5_defconfig @@ -16,6 +16,7 @@ CONFIG_SPL_I2C_SUPPORT=y # CONFIG_SPL_DOS_PARTITION is not set # CONFIG_SPL_ISO_PARTITION is not set # CONFIG_SPL_EFI_PARTITION is not set +CONFIG_SCSI=y CONFIG_ETH_DESIGNWARE=y CONFIG_SUN7I_GMAC=y CONFIG_USB_EHCI_HCD=y diff --git a/configs/Orangepi_defconfig b/configs/Orangepi_defconfig index b8c1ea4..ed3e678 100644 --- a/configs/Orangepi_defconfig +++ b/configs/Orangepi_defconfig @@ -19,6 +19,7 @@ CONFIG_SPL_I2C_SUPPORT=y # CONFIG_SPL_DOS_PARTITION is not set # CONFIG_SPL_ISO_PARTITION is not set # CONFIG_SPL_EFI_PARTITION is not set +CONFIG_SCSI=y CONFIG_ETH_DESIGNWARE=y CONFIG_RGMII=y CONFIG_SUN7I_GMAC=y diff --git a/configs/Orangepi_mini_defconfig b/configs/Orangepi_mini_defconfig index 19c35ef..56f405c 100644 --- a/configs/Orangepi_mini_defconfig +++ b/configs/Orangepi_mini_defconfig @@ -21,6 +21,7 @@ CONFIG_SPL_I2C_SUPPORT=y # CONFIG_SPL_DOS_PARTITION is not set # CONFIG_SPL_ISO_PARTITION is not set # CONFIG_SPL_EFI_PARTITION is not set +CONFIG_SCSI=y CONFIG_ETH_DESIGNWARE=y CONFIG_RGMII=y CONFIG_SUN7I_GMAC=y diff --git a/configs/Wits_Pro_A20_DKT_defconfig b/configs/Wits_Pro_A20_DKT_defconfig index 8658ef6..2a2f26d 100644 --- a/configs/Wits_Pro_A20_DKT_defconfig +++ b/configs/Wits_Pro_A20_DKT_defconfig @@ -19,6 +19,7 @@ CONFIG_SPL_I2C_SUPPORT=y # CONFIG_SPL_DOS_PARTITION is not set # CONFIG_SPL_ISO_PARTITION is not set # CONFIG_SPL_EFI_PARTITION is not set +CONFIG_SCSI=y CONFIG_ETH_DESIGNWARE=y CONFIG_RGMII=y CONFIG_SUN7I_GMAC=y diff --git a/configs/bayleybay_defconfig b/configs/bayleybay_defconfig index d2f9f24..14b74c4 100644 --- a/configs/bayleybay_defconfig +++ b/configs/bayleybay_defconfig @@ -46,6 +46,7 @@ CONFIG_EFI_PARTITION=y CONFIG_OF_CONTROL=y CONFIG_REGMAP=y CONFIG_SYSCON=y +CONFIG_SCSI=y CONFIG_CPU=y CONFIG_MMC=y CONFIG_MMC_PCI=y diff --git a/configs/chromebook_link64_defconfig b/configs/chromebook_link64_defconfig index febbeb5..8fb4712 100644 --- a/configs/chromebook_link64_defconfig +++ b/configs/chromebook_link64_defconfig @@ -57,6 +57,7 @@ CONFIG_REGMAP=y CONFIG_SPL_REGMAP=y CONFIG_SYSCON=y CONFIG_SPL_SYSCON=y +CONFIG_SCSI=y CONFIG_CPU=y CONFIG_DM_I2C=y CONFIG_SYS_I2C_INTEL=y diff --git a/configs/chromebook_link_defconfig b/configs/chromebook_link_defconfig index e2f5782..9c0f860 100644 --- a/configs/chromebook_link_defconfig +++ b/configs/chromebook_link_defconfig @@ -40,6 +40,7 @@ CONFIG_EFI_PARTITION=y CONFIG_OF_CONTROL=y CONFIG_REGMAP=y CONFIG_SYSCON=y +CONFIG_SCSI=y CONFIG_CPU=y CONFIG_DM_I2C=y CONFIG_SYS_I2C_INTEL=y diff --git a/configs/chromebook_samus_defconfig b/configs/chromebook_samus_defconfig index 3e12bea..ab2d27e 100644 --- a/configs/chromebook_samus_defconfig +++ b/configs/chromebook_samus_defconfig @@ -40,6 +40,7 @@ CONFIG_EFI_PARTITION=y CONFIG_OF_CONTROL=y CONFIG_REGMAP=y CONFIG_SYSCON=y +CONFIG_SCSI=y CONFIG_CPU=y CONFIG_INTEL_BROADWELL_GPIO=y CONFIG_CROS_EC=y diff --git a/configs/chromebox_panther_defconfig b/configs/chromebox_panther_defconfig index 0d65a90..51a934f 100644 --- a/configs/chromebox_panther_defconfig +++ b/configs/chromebox_panther_defconfig @@ -36,6 +36,7 @@ CONFIG_EFI_PARTITION=y CONFIG_OF_CONTROL=y CONFIG_REGMAP=y CONFIG_SYSCON=y +CONFIG_SCSI=y CONFIG_CROS_EC=y CONFIG_CROS_EC_LPC=y CONFIG_SPI_FLASH=y diff --git a/configs/cm_t54_defconfig b/configs/cm_t54_defconfig index ec26f99..6d18eac 100644 --- a/configs/cm_t54_defconfig +++ b/configs/cm_t54_defconfig @@ -38,6 +38,7 @@ CONFIG_CMD_FAT=y CONFIG_CMD_FS_GENERIC=y CONFIG_ISO_PARTITION=y CONFIG_EFI_PARTITION=y +CONFIG_SCSI=y CONFIG_MMC_OMAP_HS=y CONFIG_SYS_NS16550=y CONFIG_USB=y diff --git a/configs/controlcenterdc_defconfig b/configs/controlcenterdc_defconfig index 31ad014..a46c468 100644 --- a/configs/controlcenterdc_defconfig +++ b/configs/controlcenterdc_defconfig @@ -34,6 +34,7 @@ CONFIG_CMD_EXT4=y CONFIG_EFI_PARTITION=y CONFIG_OF_BOARD_FIXUP=y CONFIG_SPL_OF_TRANSLATE=y +CONFIG_SCSI=y CONFIG_DM_GPIO=y CONFIG_DM_PCA953X=y CONFIG_DM_I2C=y diff --git a/configs/cougarcanyon2_defconfig b/configs/cougarcanyon2_defconfig index f589dec..1008ef7 100644 --- a/configs/cougarcanyon2_defconfig +++ b/configs/cougarcanyon2_defconfig @@ -29,6 +29,7 @@ CONFIG_EFI_PARTITION=y CONFIG_OF_CONTROL=y CONFIG_REGMAP=y CONFIG_SYSCON=y +CONFIG_SCSI=y CONFIG_SPI_FLASH=y CONFIG_SPI_FLASH_WINBOND=y CONFIG_DM_PCI=y diff --git a/configs/crownbay_defconfig b/configs/crownbay_defconfig index 4a88f5f..ac50681 100644 --- a/configs/crownbay_defconfig +++ b/configs/crownbay_defconfig @@ -35,6 +35,7 @@ CONFIG_EFI_PARTITION=y CONFIG_OF_CONTROL=y CONFIG_REGMAP=y CONFIG_SYSCON=y +CONFIG_SCSI=y CONFIG_CPU=y CONFIG_MMC=y CONFIG_MMC_PCI=y diff --git a/configs/db-88f6820-gp_defconfig b/configs/db-88f6820-gp_defconfig index d6068aa..f0b0d69 100644 --- a/configs/db-88f6820-gp_defconfig +++ b/configs/db-88f6820-gp_defconfig @@ -37,6 +37,7 @@ CONFIG_EFI_PARTITION=y # CONFIG_PARTITION_UUIDS is not set # CONFIG_SPL_PARTITION_UUIDS is not set CONFIG_SPL_OF_TRANSLATE=y +CONFIG_SCSI=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_SDMA=y CONFIG_MMC_SDHCI_MV=y diff --git a/configs/highbank_defconfig b/configs/highbank_defconfig index 041d048..6f19492 100644 --- a/configs/highbank_defconfig +++ b/configs/highbank_defconfig @@ -23,5 +23,6 @@ CONFIG_CMD_FS_GENERIC=y CONFIG_ISO_PARTITION=y CONFIG_EFI_PARTITION=y # CONFIG_PARTITION_UUIDS is not set +CONFIG_SCSI=y # CONFIG_MMC is not set CONFIG_OF_LIBFDT=y diff --git a/configs/ls1012aqds_qspi_defconfig b/configs/ls1012aqds_qspi_defconfig index 2124273..695d7d1 100644 --- a/configs/ls1012aqds_qspi_defconfig +++ b/configs/ls1012aqds_qspi_defconfig @@ -31,6 +31,7 @@ CONFIG_OF_CONTROL=y CONFIG_NET_RANDOM_ETHADDR=y CONFIG_DM=y # CONFIG_BLK is not set +CONFIG_SCSI=y CONFIG_DM_MMC=y # CONFIG_DM_MMC_OPS is not set CONFIG_DM_SPI_FLASH=y diff --git a/configs/ls2081ardb_defconfig b/configs/ls2081ardb_defconfig index d8420ba..bc2792e 100644 --- a/configs/ls2081ardb_defconfig +++ b/configs/ls2081ardb_defconfig @@ -21,6 +21,7 @@ CONFIG_CMD_CACHE=y CONFIG_OF_CONTROL=y CONFIG_NET_RANDOM_ETHADDR=y CONFIG_DM=y +CONFIG_SCSI=y CONFIG_FSL_CAAM=y CONFIG_DM_SPI_FLASH=y CONFIG_NETDEVICES=y diff --git a/configs/minnowmax_defconfig b/configs/minnowmax_defconfig index 96a45aa..a64a0a3 100644 --- a/configs/minnowmax_defconfig +++ b/configs/minnowmax_defconfig @@ -47,6 +47,7 @@ CONFIG_EFI_PARTITION=y CONFIG_OF_CONTROL=y CONFIG_REGMAP=y CONFIG_SYSCON=y +CONFIG_SCSI=y CONFIG_CPU=y CONFIG_MMC=y CONFIG_MMC_PCI=y diff --git a/configs/omap5_uevm_defconfig b/configs/omap5_uevm_defconfig index f5ac38b..0af00b1 100644 --- a/configs/omap5_uevm_defconfig +++ b/configs/omap5_uevm_defconfig @@ -32,6 +32,7 @@ CONFIG_CMD_EXT4_WRITE=y CONFIG_CMD_FAT=y CONFIG_CMD_FS_GENERIC=y CONFIG_ISO_PARTITION=y +CONFIG_SCSI=y CONFIG_DFU_MMC=y CONFIG_DFU_RAM=y CONFIG_MMC_OMAP_HS=y diff --git a/configs/som-db5800-som-6867_defconfig b/configs/som-db5800-som-6867_defconfig index ea3d175..56a7e4b 100644 --- a/configs/som-db5800-som-6867_defconfig +++ b/configs/som-db5800-som-6867_defconfig @@ -43,6 +43,7 @@ CONFIG_EFI_PARTITION=y CONFIG_OF_CONTROL=y CONFIG_REGMAP=y CONFIG_SYSCON=y +CONFIG_SCSI=y CONFIG_CPU=y CONFIG_SPI_FLASH=y CONFIG_SPI_FLASH_GIGADEVICE=y diff --git a/configs/xilinx_zynqmp_ep_defconfig b/configs/xilinx_zynqmp_ep_defconfig index a4b4059..578db22 100644 --- a/configs/xilinx_zynqmp_ep_defconfig +++ b/configs/xilinx_zynqmp_ep_defconfig @@ -46,6 +46,7 @@ CONFIG_OF_EMBED=y CONFIG_NET_RANDOM_ETHADDR=y CONFIG_SPL_DM=y CONFIG_SPL_DM_SEQ_ALIAS=y +CONFIG_SCSI=y CONFIG_DM_SCSI=y CONFIG_SATA_CEVA=y CONFIG_DFU_RAM=y diff --git a/configs/xilinx_zynqmp_zcu102_defconfig b/configs/xilinx_zynqmp_zcu102_defconfig index 3616065..4f1524b 100644 --- a/configs/xilinx_zynqmp_zcu102_defconfig +++ b/configs/xilinx_zynqmp_zcu102_defconfig @@ -39,6 +39,7 @@ CONFIG_OF_EMBED=y CONFIG_NET_RANDOM_ETHADDR=y CONFIG_SPL_DM=y CONFIG_SPL_DM_SEQ_ALIAS=y +CONFIG_SCSI=y CONFIG_DM_SCSI=y CONFIG_SATA_CEVA=y CONFIG_DFU_RAM=y diff --git a/configs/xilinx_zynqmp_zcu102_revB_defconfig b/configs/xilinx_zynqmp_zcu102_revB_defconfig index f3ba5a0..4b944cb 100644 --- a/configs/xilinx_zynqmp_zcu102_revB_defconfig +++ b/configs/xilinx_zynqmp_zcu102_revB_defconfig @@ -39,6 +39,7 @@ CONFIG_OF_EMBED=y CONFIG_NET_RANDOM_ETHADDR=y CONFIG_SPL_DM=y CONFIG_SPL_DM_SEQ_ALIAS=y +CONFIG_SCSI=y CONFIG_DM_SCSI=y CONFIG_SATA_CEVA=y CONFIG_DFU_RAM=y diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 931defd..4c2aaa0 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -19,6 +19,15 @@ config AHCI operations at present. The block device interface has not been converted to driver model. +config SCSI + bool "Support SCSI controllers" + help + This enables support for SCSI (Small Computer System Interface), + a parallel interface widely used with storage peripherals such as + hard drives and optical drives. The SCSI standards define physical + interfaces as well as protocols for controlling devices and + tranferring data. + config DM_SCSI bool "Support SCSI controllers with driver model" depends on BLK diff --git a/include/config_cmd_all.h b/include/config_cmd_all.h index b1f41ab..2874a78 100644 --- a/include/config_cmd_all.h +++ b/include/config_cmd_all.h @@ -25,7 +25,6 @@ #define CONFIG_CMD_READ /* Read data from partition */ #define CONFIG_CMD_SANDBOX /* sb command to access sandbox features */ #define CONFIG_CMD_SAVES /* save S record dump */ -#define CONFIG_SCSI /* SCSI Support */ #define CONFIG_CMD_SDRAM /* SDRAM DIMM SPD info printout */ #define CONFIG_CMD_TERMINAL /* built-in Serial Terminal */ #define CONFIG_CMD_UBIFS /* UBIFS Support */ diff --git a/include/configs/MPC8544DS.h b/include/configs/MPC8544DS.h index 3b62449..ffa8796 100644 --- a/include/configs/MPC8544DS.h +++ b/include/configs/MPC8544DS.h @@ -352,7 +352,6 @@ extern unsigned long get_board_sys_clk(unsigned long dummy); #if defined(CONFIG_PCI) #define CONFIG_CMD_PCI - #define CONFIG_SCSI #endif /* diff --git a/include/configs/MPC8572DS.h b/include/configs/MPC8572DS.h index 79e11bb..d8e0dfd 100644 --- a/include/configs/MPC8572DS.h +++ b/include/configs/MPC8572DS.h @@ -551,7 +551,6 @@ #if defined(CONFIG_PCI) #define CONFIG_CMD_PCI -#define CONFIG_SCSI #endif /* diff --git a/include/configs/MPC8610HPCD.h b/include/configs/MPC8610HPCD.h index 2014450..1db3a63 100644 --- a/include/configs/MPC8610HPCD.h +++ b/include/configs/MPC8610HPCD.h @@ -430,7 +430,6 @@ #if defined(CONFIG_PCI) #define CONFIG_CMD_PCI -#define CONFIG_SCSI #endif #define CONFIG_WATCHDOG /* watchdog enabled */ diff --git a/include/configs/MPC8641HPCN.h b/include/configs/MPC8641HPCN.h index 7ec36eb..e87b111 100644 --- a/include/configs/MPC8641HPCN.h +++ b/include/configs/MPC8641HPCN.h @@ -591,7 +591,6 @@ extern unsigned long get_board_sys_clk(unsigned long dummy); #if defined(CONFIG_PCI) #define CONFIG_CMD_PCI - #define CONFIG_SCSI #endif #undef CONFIG_WATCHDOG /* watchdog disabled */ diff --git a/include/configs/am57xx_evm.h b/include/configs/am57xx_evm.h index 7a42d79..98ce6c5 100644 --- a/include/configs/am57xx_evm.h +++ b/include/configs/am57xx_evm.h @@ -99,7 +99,6 @@ #define CONFIG_OMAP_USB3PHY1_HOST /* SATA */ -#define CONFIG_SCSI #define CONFIG_LIBATA #define CONFIG_SCSI_AHCI #define CONFIG_SCSI_AHCI_PLAT diff --git a/include/configs/cm_t54.h b/include/configs/cm_t54.h index 14042ad..3647573 100644 --- a/include/configs/cm_t54.h +++ b/include/configs/cm_t54.h @@ -49,7 +49,6 @@ #define CONFIG_SPL_SATA_BOOT_DEVICE 0 #define CONFIG_SYS_SATA_FAT_BOOT_PARTITION 1 -#define CONFIG_SCSI #define CONFIG_LIBATA #define CONFIG_SCSI_AHCI #define CONFIG_SCSI_AHCI_PLAT diff --git a/include/configs/controlcenterdc.h b/include/configs/controlcenterdc.h index a04af31..f10cdda 100644 --- a/include/configs/controlcenterdc.h +++ b/include/configs/controlcenterdc.h @@ -51,7 +51,6 @@ * SATA/SCSI/AHCI configuration */ #define CONFIG_LIBATA -#define CONFIG_SCSI #define CONFIG_SCSI_AHCI #define CONFIG_SCSI_AHCI_PLAT #define CONFIG_SYS_SCSI_MAX_SCSI_ID 2 diff --git a/include/configs/db-88f6820-gp.h b/include/configs/db-88f6820-gp.h index 0890a4d..292bfb8 100644 --- a/include/configs/db-88f6820-gp.h +++ b/include/configs/db-88f6820-gp.h @@ -25,7 +25,6 @@ * Commands configuration */ #define CONFIG_CMD_PCI -#define CONFIG_SCSI /* I2C */ #define CONFIG_SYS_I2C diff --git a/include/configs/dra7xx_evm.h b/include/configs/dra7xx_evm.h index d6c4a71..d2f7c7c 100644 --- a/include/configs/dra7xx_evm.h +++ b/include/configs/dra7xx_evm.h @@ -162,7 +162,6 @@ #define CONFIG_OMAP_USB2PHY2_HOST /* SATA */ -#define CONFIG_SCSI #define CONFIG_LIBATA #define CONFIG_SCSI_AHCI #define CONFIG_SCSI_AHCI_PLAT diff --git a/include/configs/efi-x86.h b/include/configs/efi-x86.h index 5626061..9dcb481 100644 --- a/include/configs/efi-x86.h +++ b/include/configs/efi-x86.h @@ -16,7 +16,6 @@ #undef CONFIG_ENV_IS_IN_SPI_FLASH #define CONFIG_ENV_IS_NOWHERE #undef CONFIG_SCSI_AHCI -#undef CONFIG_SCSI #undef CONFIG_INTEL_ICH6_GPIO #undef CONFIG_USB_EHCI_PCI diff --git a/include/configs/galileo.h b/include/configs/galileo.h index dcbaade..00c5434 100644 --- a/include/configs/galileo.h +++ b/include/configs/galileo.h @@ -24,7 +24,6 @@ /* SATA is not supported in Quark SoC */ #undef CONFIG_SCSI_AHCI -#undef CONFIG_SCSI /* 10/100M Ethernet support */ #define CONFIG_DESIGNWARE_ETH diff --git a/include/configs/highbank.h b/include/configs/highbank.h index e15b572..533d3e3 100644 --- a/include/configs/highbank.h +++ b/include/configs/highbank.h @@ -46,7 +46,6 @@ /* * Command line configuration. */ -#define CONFIG_SCSI #define CONFIG_BOOT_RETRY_TIME -1 #define CONFIG_RESET_TO_RETRY diff --git a/include/configs/ls1012aqds.h b/include/configs/ls1012aqds.h index 5b8500b..9e6c7a7 100644 --- a/include/configs/ls1012aqds.h +++ b/include/configs/ls1012aqds.h @@ -135,7 +135,6 @@ /* SATA */ #define CONFIG_LIBATA -#define CONFIG_SCSI #define CONFIG_SCSI_AHCI #define CONFIG_SCSI_AHCI_PLAT #define CONFIG_CMD_SCSI diff --git a/include/configs/ls1012ardb.h b/include/configs/ls1012ardb.h index 276fe10..0705bc5 100644 --- a/include/configs/ls1012ardb.h +++ b/include/configs/ls1012ardb.h @@ -51,7 +51,6 @@ /* SATA */ #define CONFIG_LIBATA -#define CONFIG_SCSI #define CONFIG_SCSI_AHCI #define CONFIG_SCSI_AHCI_PLAT #define CONFIG_CMD_SCSI diff --git a/include/configs/ls1043aqds.h b/include/configs/ls1043aqds.h index 04d74ac..87ca36a 100644 --- a/include/configs/ls1043aqds.h +++ b/include/configs/ls1043aqds.h @@ -98,7 +98,6 @@ unsigned long get_board_ddr_clk(void); #define CONFIG_LIBATA #define CONFIG_SCSI_AHCI #define CONFIG_SCSI_AHCI_PLAT -#define CONFIG_SCSI /* EEPROM */ #define CONFIG_ID_EEPROM diff --git a/include/configs/ls1046aqds.h b/include/configs/ls1046aqds.h index 5d2e819..77619ab 100644 --- a/include/configs/ls1046aqds.h +++ b/include/configs/ls1046aqds.h @@ -153,7 +153,6 @@ unsigned long get_board_ddr_clk(void); #define CONFIG_LIBATA #define CONFIG_SCSI_AHCI #define CONFIG_SCSI_AHCI_PLAT -#define CONFIG_SCSI /* EEPROM */ #define CONFIG_ID_EEPROM diff --git a/include/configs/ls1046ardb.h b/include/configs/ls1046ardb.h index 6f649a6..8a6b4e6 100644 --- a/include/configs/ls1046ardb.h +++ b/include/configs/ls1046ardb.h @@ -233,7 +233,6 @@ #define CONFIG_LIBATA #define CONFIG_SCSI_AHCI #define CONFIG_SCSI_AHCI_PLAT -#define CONFIG_SCSI #define CONFIG_SYS_SATA AHCI_BASE_ADDR diff --git a/include/configs/ls2080aqds.h b/include/configs/ls2080aqds.h index 8a8ee9d..5e1867d 100644 --- a/include/configs/ls2080aqds.h +++ b/include/configs/ls2080aqds.h @@ -50,7 +50,6 @@ unsigned long get_board_ddr_clk(void); #define CONFIG_LIBATA #define CONFIG_SCSI_AHCI #define CONFIG_SCSI_AHCI_PLAT -#define CONFIG_SCSI #define CONFIG_SYS_SATA1 AHCI_BASE_ADDR1 #define CONFIG_SYS_SATA2 AHCI_BASE_ADDR2 diff --git a/include/configs/ls2080ardb.h b/include/configs/ls2080ardb.h index 2dab065..e8aacd3 100644 --- a/include/configs/ls2080ardb.h +++ b/include/configs/ls2080ardb.h @@ -68,7 +68,6 @@ unsigned long get_board_sys_clk(void); #define CONFIG_LIBATA #define CONFIG_SCSI_AHCI #define CONFIG_SCSI_AHCI_PLAT -#define CONFIG_SCSI #define CONFIG_SYS_SATA1 AHCI_BASE_ADDR1 #define CONFIG_SYS_SATA2 AHCI_BASE_ADDR2 diff --git a/include/configs/mvebu_armada-37xx.h b/include/configs/mvebu_armada-37xx.h index 5408490..eb80ac5 100644 --- a/include/configs/mvebu_armada-37xx.h +++ b/include/configs/mvebu_armada-37xx.h @@ -113,7 +113,6 @@ /* * SATA/SCSI/AHCI configuration */ -#define CONFIG_SCSI #define CONFIG_SCSI_AHCI #define CONFIG_SCSI_AHCI_PLAT #define CONFIG_LIBATA diff --git a/include/configs/mvebu_armada-8k.h b/include/configs/mvebu_armada-8k.h index 9d3aeef..ac116ed 100644 --- a/include/configs/mvebu_armada-8k.h +++ b/include/configs/mvebu_armada-8k.h @@ -119,7 +119,6 @@ /* * SATA/SCSI/AHCI configuration */ -#define CONFIG_SCSI #define CONFIG_SCSI_AHCI #define CONFIG_SCSI_AHCI_PLAT #define CONFIG_LIBATA diff --git a/include/configs/omap5_uevm.h b/include/configs/omap5_uevm.h index e7fac6d..15d06bb 100644 --- a/include/configs/omap5_uevm.h +++ b/include/configs/omap5_uevm.h @@ -66,7 +66,6 @@ #define CONSOLEDEV "ttyO2" -#define CONFIG_SCSI #define CONFIG_LIBATA #define CONFIG_SCSI_AHCI #define CONFIG_SCSI_AHCI_PLAT diff --git a/include/configs/qemu-x86.h b/include/configs/qemu-x86.h index 3509c2f..05eb5eb 100644 --- a/include/configs/qemu-x86.h +++ b/include/configs/qemu-x86.h @@ -39,7 +39,6 @@ #define CONFIG_ATAPI #undef CONFIG_SCSI_AHCI -#undef CONFIG_SCSI #else #define CONFIG_SCSI_DEV_LIST \ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_AHCI} diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index 31ceb54..3e09e88 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -157,7 +157,6 @@ #define CONFIG_SYS_ATA_STRIDE 4 #endif -#define CONFIG_SCSI #define CONFIG_SCSI_AHCI_PLAT #define CONFIG_SYS_SCSI_MAX_DEVICE 2 #define CONFIG_SYS_SCSI_MAX_SCSI_ID 8 diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h index 9b514ff..fefd58f 100644 --- a/include/configs/sunxi-common.h +++ b/include/configs/sunxi-common.h @@ -122,7 +122,6 @@ #define CONFIG_SYS_SCSI_MAX_LUN 1 #define CONFIG_SYS_SCSI_MAX_DEVICE (CONFIG_SYS_SCSI_MAX_SCSI_ID * \ CONFIG_SYS_SCSI_MAX_LUN) -#define CONFIG_SCSI #endif #define CONFIG_SETUP_MEMORY_TAGS diff --git a/include/configs/x86-common.h b/include/configs/x86-common.h index a5ed852..d104449 100644 --- a/include/configs/x86-common.h +++ b/include/configs/x86-common.h @@ -71,7 +71,6 @@ * Command line configuration. */ #define CONFIG_CMD_PCI -#define CONFIG_SCSI #define CONFIG_CMD_ZBOOT diff --git a/include/configs/xilinx_zynqmp.h b/include/configs/xilinx_zynqmp.h index 86a4579..c7fcd86 100644 --- a/include/configs/xilinx_zynqmp.h +++ b/include/configs/xilinx_zynqmp.h @@ -190,7 +190,6 @@ #define CONFIG_SYS_SCSI_MAX_LUN 1 #define CONFIG_SYS_SCSI_MAX_DEVICE (CONFIG_SYS_SCSI_MAX_SCSI_ID * \ CONFIG_SYS_SCSI_MAX_LUN) -#define CONFIG_SCSI #endif #define CONFIG_SYS_BOOTM_LEN (60 * 1024 * 1024) diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt index 54eee53..5b3aa09 100644 --- a/scripts/config_whitelist.txt +++ b/scripts/config_whitelist.txt @@ -2039,7 +2039,6 @@ CONFIG_SCIF_A CONFIG_SCIF_CONSOLE CONFIG_SCIF_EXT_CLOCK CONFIG_SCIF_USE_EXT_CLK -CONFIG_SCSI CONFIG_SCSI_AHCI CONFIG_SCSI_AHCI_PLAT CONFIG_SCSI_DEV_ID -- cgit v0.10.2 From b8beb6b463676f586a5481993590cd8a6e8c5855 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 14 Jun 2017 21:28:22 -0600 Subject: scsi: Drop sym53c8xx driver This driver is for a PowerPC board that will likely be removed soon. Rather than converting it to driver model, drop it. Signed-off-by: Simon Glass Reviewed-by: Bin Meng diff --git a/README b/README index de8ba81..c73f6dd 100644 --- a/README +++ b/README @@ -1042,16 +1042,11 @@ The following options need to be configured: Default is 32bit. - SCSI Support: - At the moment only there is only support for the - SYM53C8XX SCSI controller; define - CONFIG_SCSI_SYM53C8XX to enable it. - CONFIG_SYS_SCSI_MAX_LUN [8], CONFIG_SYS_SCSI_MAX_SCSI_ID [7] and CONFIG_SYS_SCSI_MAX_DEVICE [CONFIG_SYS_SCSI_MAX_SCSI_ID * CONFIG_SYS_SCSI_MAX_LUN] can be adjusted to define the maximum numbers of LUNs, SCSI ID's and target devices. - CONFIG_SYS_SCSI_SYM53C8XX_CCF to fix clock timing (80Mhz) The environment variable 'scsidevs' is set to the number of SCSI devices found during the last scan. diff --git a/common/scsi.c b/common/scsi.c index c456f5a..4896fb9 100644 --- a/common/scsi.c +++ b/common/scsi.c @@ -17,14 +17,7 @@ #ifdef CONFIG_SCSI_DEV_LIST #define SCSI_DEV_LIST CONFIG_SCSI_DEV_LIST #else -#ifdef CONFIG_SCSI_SYM53C8XX -#define SCSI_VEND_ID 0x1000 -#ifndef CONFIG_SCSI_DEV_ID -#define SCSI_DEV_ID 0x0001 -#else -#define SCSI_DEV_ID CONFIG_SCSI_DEV_ID -#endif -#elif defined CONFIG_SATA_ULI5288 +#ifdef CONFIG_SATA_ULI5288 #define SCSI_VEND_ID 0x10b9 #define SCSI_DEV_ID 0x5288 diff --git a/drivers/block/Makefile b/drivers/block/Makefile index adea6c6..035e078 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -28,6 +28,5 @@ obj-$(CONFIG_SATA_MV) += sata_mv.o obj-$(CONFIG_SATA_SIL3114) += sata_sil3114.o obj-$(CONFIG_SATA_SIL) += sata_sil.o obj-$(CONFIG_SANDBOX) += sandbox.o sandbox_scsi.o sata_sandbox.o -obj-$(CONFIG_SCSI_SYM53C8XX) += sym53c8xx.o obj-$(CONFIG_SYSTEMACE) += systemace.o obj-$(CONFIG_BLOCK_CACHE) += blkcache.o diff --git a/drivers/block/sym53c8xx.c b/drivers/block/sym53c8xx.c deleted file mode 100644 index 50043e6..0000000 --- a/drivers/block/sym53c8xx.c +++ /dev/null @@ -1,851 +0,0 @@ -/* - * (C) Copyright 2001 - * Denis Peter, MPL AG Switzerland, d.peter@mpl.ch. - * - * SPDX-License-Identifier: GPL-2.0+ - * partly derived from - * linux/drivers/scsi/sym53c8xx.c - * - */ - -/* - * SCSI support based on the chip sym53C810. - * - * 09-19-2001 Andreas Heppel, Sysgo RTS GmbH - * The local version of this driver for the BAB750 board does not - * use interrupts but polls the chip instead (see the call of - * 'handle_scsi_int()' in 'scsi_issue()'. - */ - -#include - -#include -#include -#include -#include -#include - -#undef SYM53C8XX_DEBUG - -#ifdef SYM53C8XX_DEBUG -#define PRINTF(fmt,args...) printf (fmt ,##args) -#else -#define PRINTF(fmt,args...) -#endif - -#if defined(CONFIG_SCSI) && defined(CONFIG_SCSI_SYM53C8XX) - -#undef SCSI_SINGLE_STEP -/* - * Single Step is only used for debug purposes - */ -#ifdef SCSI_SINGLE_STEP -static unsigned long start_script_select; -static unsigned long start_script_msgout; -static unsigned long start_script_msgin; -static unsigned long start_script_msg_ext; -static unsigned long start_script_cmd; -static unsigned long start_script_data_in; -static unsigned long start_script_data_out; -static unsigned long start_script_status; -static unsigned long start_script_complete; -static unsigned long start_script_error; -static unsigned long start_script_reselection; -static unsigned int len_script_select; -static unsigned int len_script_msgout; -static unsigned int len_script_msgin; -static unsigned int len_script_msg_ext; -static unsigned int len_script_cmd; -static unsigned int len_script_data_in; -static unsigned int len_script_data_out; -static unsigned int len_script_status; -static unsigned int len_script_complete; -static unsigned int len_script_error; -static unsigned int len_script_reselection; -#endif - - -static unsigned short scsi_int_mask; /* shadow register for SCSI related interrupts */ -static unsigned char script_int_mask; /* shadow register for SCRIPT related interrupts */ -static unsigned long script_select[8]; /* script for selection */ -static unsigned long script_msgout[8]; /* script for message out phase (NOT USED) */ -static unsigned long script_msgin[14]; /* script for message in phase */ -static unsigned long script_msg_ext[32]; /* script for message in phase when more than 1 byte message */ -static unsigned long script_cmd[18]; /* script for command phase */ -static unsigned long script_data_in[8]; /* script for data in phase */ -static unsigned long script_data_out[8]; /* script for data out phase */ -static unsigned long script_status[6]; /* script for status phase */ -static unsigned long script_complete[10]; /* script for complete */ -static unsigned long script_reselection[4]; /* script for reselection (NOT USED) */ -static unsigned long script_error[2]; /* script for error handling */ - -static unsigned long int_stat[3]; /* interrupt status */ -static unsigned long scsi_mem_addr; /* base memory address =SCSI_MEM_ADDRESS; */ - -#define bus_to_phys(a) pci_mem_to_phys(busdevfunc, (unsigned long) (a)) -#define phys_to_bus(a) pci_phys_to_mem(busdevfunc, (unsigned long) (a)) - -#define SCSI_MAX_RETRY 3 /* number of retries in scsi_issue() */ - -#define SCSI_MAX_RETRY_NOT_READY 10 /* number of retries when device is not ready */ -#define SCSI_NOT_READY_TIME_OUT 500 /* timeout per retry when not ready */ - -/********************************************************************************* - * forward declerations - */ - -void scsi_chip_init(void); -void handle_scsi_int(void); - - -/******************************************************************************** - * reports SCSI errors to the user - */ -void scsi_print_error (ccb * pccb) -{ - int i; - - printf ("SCSI Error: Target %d LUN %d Command %02X\n", pccb->target, - pccb->lun, pccb->cmd[0]); - printf (" CCB: "); - for (i = 0; i < pccb->cmdlen; i++) - printf ("%02X ", pccb->cmd[i]); - printf ("(len=%d)\n", pccb->cmdlen); - printf (" Cntrl: "); - switch (pccb->contr_stat) { - case SIR_COMPLETE: - printf ("Complete (no Error)\n"); - break; - case SIR_SEL_ATN_NO_MSG_OUT: - printf ("Selected with ATN no MSG out phase\n"); - break; - case SIR_CMD_OUT_ILL_PH: - printf ("Command out illegal phase\n"); - break; - case SIR_MSG_RECEIVED: - printf ("MSG received Error\n"); - break; - case SIR_DATA_IN_ERR: - printf ("Data in Error\n"); - break; - case SIR_DATA_OUT_ERR: - printf ("Data out Error\n"); - break; - case SIR_SCRIPT_ERROR: - printf ("Script Error\n"); - break; - case SIR_MSG_OUT_NO_CMD: - printf ("MSG out no Command phase\n"); - break; - case SIR_MSG_OVER7: - printf ("MSG in over 7 bytes\n"); - break; - case INT_ON_FY: - printf ("Interrupt on fly\n"); - break; - case SCSI_SEL_TIME_OUT: - printf ("SCSI Selection Timeout\n"); - break; - case SCSI_HNS_TIME_OUT: - printf ("SCSI Handshake Timeout\n"); - break; - case SCSI_MA_TIME_OUT: - printf ("SCSI Phase Error\n"); - break; - case SCSI_UNEXP_DIS: - printf ("SCSI unexpected disconnect\n"); - break; - default: - printf ("unknown status %lx\n", pccb->contr_stat); - break; - } - printf (" Sense: SK %x (", pccb->sense_buf[2] & 0x0f); - switch (pccb->sense_buf[2] & 0xf) { - case SENSE_NO_SENSE: - printf ("No Sense)"); - break; - case SENSE_RECOVERED_ERROR: - printf ("Recovered Error)"); - break; - case SENSE_NOT_READY: - printf ("Not Ready)"); - break; - case SENSE_MEDIUM_ERROR: - printf ("Medium Error)"); - break; - case SENSE_HARDWARE_ERROR: - printf ("Hardware Error)"); - break; - case SENSE_ILLEGAL_REQUEST: - printf ("Illegal request)"); - break; - case SENSE_UNIT_ATTENTION: - printf ("Unit Attention)"); - break; - case SENSE_DATA_PROTECT: - printf ("Data Protect)"); - break; - case SENSE_BLANK_CHECK: - printf ("Blank check)"); - break; - case SENSE_VENDOR_SPECIFIC: - printf ("Vendor specific)"); - break; - case SENSE_COPY_ABORTED: - printf ("Copy aborted)"); - break; - case SENSE_ABORTED_COMMAND: - printf ("Aborted Command)"); - break; - case SENSE_VOLUME_OVERFLOW: - printf ("Volume overflow)"); - break; - case SENSE_MISCOMPARE: - printf ("Misscompare\n"); - break; - default: - printf ("Illegal Sensecode\n"); - break; - } - printf (" ASC %x ASCQ %x\n", pccb->sense_buf[12], - pccb->sense_buf[13]); - printf (" Status: "); - switch (pccb->status) { - case S_GOOD: - printf ("Good\n"); - break; - case S_CHECK_COND: - printf ("Check condition\n"); - break; - case S_COND_MET: - printf ("Condition Met\n"); - break; - case S_BUSY: - printf ("Busy\n"); - break; - case S_INT: - printf ("Intermediate\n"); - break; - case S_INT_COND_MET: - printf ("Intermediate condition met\n"); - break; - case S_CONFLICT: - printf ("Reservation conflict\n"); - break; - case S_TERMINATED: - printf ("Command terminated\n"); - break; - case S_QUEUE_FULL: - printf ("Task set full\n"); - break; - default: - printf ("unknown: %02X\n", pccb->status); - break; - } - -} - - -/****************************************************************************** - * sets-up the SCSI controller - * the base memory address is retrieved via the pci_read_config_dword - */ -void scsi_low_level_init(int busdevfunc) -{ - unsigned int cmd; - unsigned int addr; - unsigned char vec; - - pci_read_config_byte(busdevfunc, PCI_INTERRUPT_LINE, &vec); - pci_read_config_dword(busdevfunc, PCI_BASE_ADDRESS_1, &addr); - - addr = bus_to_phys(addr & ~0xf); - - /* - * Enable bus mastering in case this has not been done, yet. - */ - pci_read_config_dword(busdevfunc, PCI_COMMAND, &cmd); - cmd |= PCI_COMMAND_MASTER; - pci_write_config_dword(busdevfunc, PCI_COMMAND, cmd); - - scsi_mem_addr = addr; - - scsi_chip_init(); - scsi_bus_reset(); -} - - -/************************************************************************************ - * Low level Part of SCSI Driver - */ - -/* - * big-endian -> little endian conversion for the script - */ -unsigned long swap_script(unsigned long val) -{ - return ((val >> 24) & 0xff) | ((val >> 8) & 0xff00) | - ((val << 8) & 0xff0000) | ((val << 24) & 0xff000000); -} - - -void scsi_write_byte(ulong offset,unsigned char val) -{ - out8(scsi_mem_addr+offset,val); -} - - -unsigned char scsi_read_byte(ulong offset) -{ - return(in8(scsi_mem_addr+offset)); -} - - -/******************************************************************************** - * interrupt handler - */ -void handle_scsi_int(void) -{ - unsigned char stat,stat1,stat2; - unsigned short sstat; - int i; -#ifdef SCSI_SINGLE_STEP - unsigned long tt; -#endif - stat=scsi_read_byte(ISTAT); - if((stat & DIP)==DIP) { /* DMA Interrupt pending */ - stat1=scsi_read_byte(DSTAT); -#ifdef SCSI_SINGLE_STEP - if((stat1 & SSI)==SSI) { - tt=in32r(scsi_mem_addr+DSP); - if(((tt)>=start_script_select) && ((tt)>2); - goto end_single; - } - if(((tt)>=start_script_msgout) && ((tt)>2); - goto end_single; - } - if(((tt)>=start_script_msgin) && ((tt)>2); - goto end_single; - } - if(((tt)>=start_script_msg_ext) && ((tt)>2); - goto end_single; - } - if(((tt)>=start_script_cmd) && ((tt)>2); - goto end_single; - } - if(((tt)>=start_script_data_in) && ((tt)>2); - goto end_single; - } - if(((tt)>=start_script_data_out) && ((tt)>2); - goto end_single; - } - if(((tt)>=start_script_status) && ((tt)>2); - goto end_single; - } - if(((tt)>=start_script_complete) && ((tt)>2); - goto end_single; - } - if(((tt)>=start_script_error) && ((tt)>2); - goto end_single; - } - if(((tt)>=start_script_reselection) && ((tt)>2); - goto end_single; - } - printf("sc: %lx\n",tt); -end_single: - stat2=scsi_read_byte(DCNTL); - stat2|=STD; - scsi_write_byte(DCNTL,stat2); - } -#endif - if((stat1 & SIR)==SIR) /* script interrupt */ - { - int_stat[0]=in32(scsi_mem_addr+DSPS); - } - if((stat1 & DFE)==0) { /* fifo not epmty */ - scsi_write_byte(CTEST3,CLF); /* Clear DMA FIFO */ - stat2=scsi_read_byte(STEST3); - scsi_write_byte(STEST3,(stat2 | CSF)); /* Clear SCSI FIFO */ - } - } - if((stat & SIP)==SIP) { /* scsi interrupt */ - sstat = (unsigned short)scsi_read_byte(SIST+1); - sstat <<=8; - sstat |= (unsigned short)scsi_read_byte(SIST); - for(i=0;i<3;i++) { - if(int_stat[i]==0) - break; /* found an empty int status */ - } - int_stat[i]=SCSI_INT_STATE | sstat; - stat1=scsi_read_byte(DSTAT); - if((stat1 & DFE)==0) { /* fifo not epmty */ - scsi_write_byte(CTEST3,CLF); /* Clear DMA FIFO */ - stat2=scsi_read_byte(STEST3); - scsi_write_byte(STEST3,(stat2 | CSF)); /* Clear SCSI FIFO */ - } - } - if((stat & INTF)==INTF) { /* interrupt on Fly */ - scsi_write_byte(ISTAT,stat); /* clear it */ - for(i=0;i<3;i++) { - if(int_stat[i]==0) - break; /* found an empty int status */ - } - int_stat[i]=INT_ON_FY; - } -} - -void scsi_bus_reset(void) -{ - unsigned char t; - int i; - int end = CONFIG_SYS_SCSI_SPIN_UP_TIME*1000; - - t=scsi_read_byte(SCNTL1); - scsi_write_byte(SCNTL1,(t | CRST)); - udelay(50); - scsi_write_byte(SCNTL1,t); - - puts("waiting for devices to spin up"); - for(i=0;i>8)); - scsi_write_byte(DIEN,script_int_mask); -} - -void scsi_write_dsp(unsigned long start) -{ -#ifdef SCSI_SINGLE_STEP - unsigned char t; -#endif - out32r(scsi_mem_addr + DSP,start); -#ifdef SCSI_SINGLE_STEP - t=scsi_read_byte(DCNTL); - t|=STD; - scsi_write_byte(DCNTL,t); -#endif -} - -/* only used for debug purposes */ -void scsi_print_script(void) -{ - printf("script_select @ 0x%08lX\n",(unsigned long)&script_select[0]); - printf("script_msgout @ 0x%08lX\n",(unsigned long)&script_msgout[0]); - printf("script_msgin @ 0x%08lX\n",(unsigned long)&script_msgin[0]); - printf("script_msgext @ 0x%08lX\n",(unsigned long)&script_msg_ext[0]); - printf("script_cmd @ 0x%08lX\n",(unsigned long)&script_cmd[0]); - printf("script_data_in @ 0x%08lX\n",(unsigned long)&script_data_in[0]); - printf("script_data_out @ 0x%08lX\n",(unsigned long)&script_data_out[0]); - printf("script_status @ 0x%08lX\n",(unsigned long)&script_status[0]); - printf("script_complete @ 0x%08lX\n",(unsigned long)&script_complete[0]); - printf("script_error @ 0x%08lX\n",(unsigned long)&script_error[0]); -} - - -void scsi_set_script(ccb *pccb) -{ - int busdevfunc = pccb->priv; - int i; - i=0; - script_select[i++]=swap_script(SCR_REG_REG(GPREG, SCR_AND, 0xfe)); - script_select[i++]=0; /* LED ON */ - script_select[i++]=swap_script(SCR_CLR(SCR_TRG)); /* select initiator mode */ - script_select[i++]=0; - /* script_select[i++]=swap_script(SCR_SEL_ABS_ATN | pccb->target << 16); */ - script_select[i++]=swap_script(SCR_SEL_ABS | pccb->target << 16); - script_select[i++]=swap_script(phys_to_bus(&script_cmd[4])); /* error handling */ - script_select[i++]=swap_script(SCR_JUMP); /* next section */ - /* script_select[i++]=swap_script((unsigned long)&script_msgout[0]); */ /* message out */ - script_select[i++]=swap_script(phys_to_bus(&script_cmd[0])); /* command out */ - -#ifdef SCSI_SINGLE_STEP - start_script_select=(unsigned long)&script_select[0]; - len_script_select=i*4; -#endif - - i=0; - script_msgout[i++]=swap_script(SCR_INT ^ IFFALSE (WHEN (SCR_MSG_OUT))); - script_msgout[i++]=SIR_SEL_ATN_NO_MSG_OUT; - script_msgout[i++]=swap_script( SCR_MOVE_ABS(1) ^ SCR_MSG_OUT); - script_msgout[i++]=swap_script(phys_to_bus(&pccb->msgout[0])); - script_msgout[i++]=swap_script(SCR_JUMP ^ IFTRUE (WHEN (SCR_COMMAND))); /* if Command phase */ - script_msgout[i++]=swap_script(phys_to_bus(&script_cmd[0])); /* switch to command */ - script_msgout[i++]=swap_script(SCR_INT); /* interrupt if not */ - script_msgout[i++]=SIR_MSG_OUT_NO_CMD; - -#ifdef SCSI_SINGLE_STEP - start_script_msgout=(unsigned long)&script_msgout[0]; - len_script_msgout=i*4; -#endif - i=0; - script_cmd[i++]=swap_script(SCR_MOVE_ABS(pccb->cmdlen) ^ SCR_COMMAND); - script_cmd[i++]=swap_script(phys_to_bus(&pccb->cmd[0])); - script_cmd[i++]=swap_script(SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN))); /* message in ? */ - script_cmd[i++]=swap_script(phys_to_bus(&script_msgin[0])); - script_cmd[i++]=swap_script(SCR_JUMP ^ IFTRUE (IF (SCR_DATA_OUT))); /* data out ? */ - script_cmd[i++]=swap_script(phys_to_bus(&script_data_out[0])); - script_cmd[i++]=swap_script(SCR_JUMP ^ IFTRUE (IF (SCR_DATA_IN))); /* data in ? */ - script_cmd[i++]=swap_script(phys_to_bus(&script_data_in[0])); - script_cmd[i++]=swap_script(SCR_JUMP ^ IFTRUE (IF (SCR_STATUS))); /* status ? */ - script_cmd[i++]=swap_script(phys_to_bus(&script_status[0])); - script_cmd[i++]=swap_script(SCR_JUMP ^ IFTRUE (IF (SCR_COMMAND))); /* command ? */ - script_cmd[i++]=swap_script(phys_to_bus(&script_cmd[0])); - script_cmd[i++]=swap_script(SCR_JUMP ^ IFTRUE (IF (SCR_MSG_OUT))); /* message out ? */ - script_cmd[i++]=swap_script(phys_to_bus(&script_msgout[0])); - script_cmd[i++]=swap_script(SCR_JUMP ^ IFTRUE (IF (SCR_MSG_IN))); /* just for error handling message in ? */ - script_cmd[i++]=swap_script(phys_to_bus(&script_msgin[0])); - script_cmd[i++]=swap_script(SCR_INT); /* interrupt if not */ - script_cmd[i++]=SIR_CMD_OUT_ILL_PH; -#ifdef SCSI_SINGLE_STEP - start_script_cmd=(unsigned long)&script_cmd[0]; - len_script_cmd=i*4; -#endif - i=0; - script_data_out[i++]=swap_script(SCR_MOVE_ABS(pccb->datalen)^ SCR_DATA_OUT); /* move */ - script_data_out[i++]=swap_script(phys_to_bus(pccb->pdata)); /* pointer to buffer */ - script_data_out[i++]=swap_script(SCR_JUMP ^ IFTRUE (WHEN (SCR_STATUS))); - script_data_out[i++]=swap_script(phys_to_bus(&script_status[0])); - script_data_out[i++]=swap_script(SCR_INT); - script_data_out[i++]=SIR_DATA_OUT_ERR; - -#ifdef SCSI_SINGLE_STEP - start_script_data_out=(unsigned long)&script_data_out[0]; - len_script_data_out=i*4; -#endif - i=0; - script_data_in[i++]=swap_script(SCR_MOVE_ABS(pccb->datalen)^ SCR_DATA_IN); /* move */ - script_data_in[i++]=swap_script(phys_to_bus(pccb->pdata)); /* pointer to buffer */ - script_data_in[i++]=swap_script(SCR_JUMP ^ IFTRUE (WHEN (SCR_STATUS))); - script_data_in[i++]=swap_script(phys_to_bus(&script_status[0])); - script_data_in[i++]=swap_script(SCR_INT); - script_data_in[i++]=SIR_DATA_IN_ERR; -#ifdef SCSI_SINGLE_STEP - start_script_data_in=(unsigned long)&script_data_in[0]; - len_script_data_in=i*4; -#endif - i=0; - script_msgin[i++]=swap_script(SCR_MOVE_ABS (1) ^ SCR_MSG_IN); - script_msgin[i++]=swap_script(phys_to_bus(&pccb->msgin[0])); - script_msgin[i++]=swap_script(SCR_JUMP ^ IFTRUE (DATA (M_COMPLETE))); - script_msgin[i++]=swap_script(phys_to_bus(&script_complete[0])); - script_msgin[i++]=swap_script(SCR_JUMP ^ IFTRUE (DATA (M_DISCONNECT))); - script_msgin[i++]=swap_script(phys_to_bus(&script_complete[0])); - script_msgin[i++]=swap_script(SCR_JUMP ^ IFTRUE (DATA (M_SAVE_DP))); - script_msgin[i++]=swap_script(phys_to_bus(&script_complete[0])); - script_msgin[i++]=swap_script(SCR_JUMP ^ IFTRUE (DATA (M_RESTORE_DP))); - script_msgin[i++]=swap_script(phys_to_bus(&script_complete[0])); - script_msgin[i++]=swap_script(SCR_JUMP ^ IFTRUE (DATA (M_EXTENDED))); - script_msgin[i++]=swap_script(phys_to_bus(&script_msg_ext[0])); - script_msgin[i++]=swap_script(SCR_INT); - script_msgin[i++]=SIR_MSG_RECEIVED; -#ifdef SCSI_SINGLE_STEP - start_script_msgin=(unsigned long)&script_msgin[0]; - len_script_msgin=i*4; -#endif - i=0; - script_msg_ext[i++]=swap_script(SCR_CLR (SCR_ACK)); /* clear ACK */ - script_msg_ext[i++]=0; - script_msg_ext[i++]=swap_script(SCR_MOVE_ABS (1) ^ SCR_MSG_IN); /* assuming this is the msg length */ - script_msg_ext[i++]=swap_script(phys_to_bus(&pccb->msgin[1])); - script_msg_ext[i++]=swap_script(SCR_JUMP ^ IFFALSE (IF (SCR_MSG_IN))); - script_msg_ext[i++]=swap_script(phys_to_bus(&script_complete[0])); /* no more bytes */ - script_msg_ext[i++]=swap_script(SCR_MOVE_ABS (1) ^ SCR_MSG_IN); /* next */ - script_msg_ext[i++]=swap_script(phys_to_bus(&pccb->msgin[2])); - script_msg_ext[i++]=swap_script(SCR_JUMP ^ IFFALSE (IF (SCR_MSG_IN))); - script_msg_ext[i++]=swap_script(phys_to_bus(&script_complete[0])); /* no more bytes */ - script_msg_ext[i++]=swap_script(SCR_MOVE_ABS (1) ^ SCR_MSG_IN); /* next */ - script_msg_ext[i++]=swap_script(phys_to_bus(&pccb->msgin[3])); - script_msg_ext[i++]=swap_script(SCR_JUMP ^ IFFALSE (IF (SCR_MSG_IN))); - script_msg_ext[i++]=swap_script(phys_to_bus(&script_complete[0])); /* no more bytes */ - script_msg_ext[i++]=swap_script(SCR_MOVE_ABS (1) ^ SCR_MSG_IN); /* next */ - script_msg_ext[i++]=swap_script(phys_to_bus(&pccb->msgin[4])); - script_msg_ext[i++]=swap_script(SCR_JUMP ^ IFFALSE (IF (SCR_MSG_IN))); - script_msg_ext[i++]=swap_script(phys_to_bus(&script_complete[0])); /* no more bytes */ - script_msg_ext[i++]=swap_script(SCR_MOVE_ABS (1) ^ SCR_MSG_IN); /* next */ - script_msg_ext[i++]=swap_script(phys_to_bus(&pccb->msgin[5])); - script_msg_ext[i++]=swap_script(SCR_JUMP ^ IFFALSE (IF (SCR_MSG_IN))); - script_msg_ext[i++]=swap_script(phys_to_bus(&script_complete[0])); /* no more bytes */ - script_msg_ext[i++]=swap_script(SCR_MOVE_ABS (1) ^ SCR_MSG_IN); /* next */ - script_msg_ext[i++]=swap_script(phys_to_bus(&pccb->msgin[6])); - script_msg_ext[i++]=swap_script(SCR_JUMP ^ IFFALSE (IF (SCR_MSG_IN))); - script_msg_ext[i++]=swap_script(phys_to_bus(&script_complete[0])); /* no more bytes */ - script_msg_ext[i++]=swap_script(SCR_MOVE_ABS (1) ^ SCR_MSG_IN); /* next */ - script_msg_ext[i++]=swap_script(phys_to_bus(&pccb->msgin[7])); - script_msg_ext[i++]=swap_script(SCR_JUMP ^ IFFALSE (IF (SCR_MSG_IN))); - script_msg_ext[i++]=swap_script(phys_to_bus(&script_complete[0])); /* no more bytes */ - script_msg_ext[i++]=swap_script(SCR_INT); - script_msg_ext[i++]=SIR_MSG_OVER7; -#ifdef SCSI_SINGLE_STEP - start_script_msg_ext=(unsigned long)&script_msg_ext[0]; - len_script_msg_ext=i*4; -#endif - i=0; - script_status[i++]=swap_script(SCR_MOVE_ABS (1) ^ SCR_STATUS); - script_status[i++]=swap_script(phys_to_bus(&pccb->status)); - script_status[i++]=swap_script(SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN))); - script_status[i++]=swap_script(phys_to_bus(&script_msgin[0])); - script_status[i++]=swap_script(SCR_INT); - script_status[i++]=SIR_STATUS_ILL_PH; -#ifdef SCSI_SINGLE_STEP - start_script_status=(unsigned long)&script_status[0]; - len_script_status=i*4; -#endif - i=0; - script_complete[i++]=swap_script(SCR_REG_REG (SCNTL2, SCR_AND, 0x7f)); - script_complete[i++]=0; - script_complete[i++]=swap_script(SCR_CLR (SCR_ACK|SCR_ATN)); - script_complete[i++]=0; - script_complete[i++]=swap_script(SCR_WAIT_DISC); - script_complete[i++]=0; - script_complete[i++]=swap_script(SCR_REG_REG(GPREG, SCR_OR, 0x01)); - script_complete[i++]=0; /* LED OFF */ - script_complete[i++]=swap_script(SCR_INT); - script_complete[i++]=SIR_COMPLETE; -#ifdef SCSI_SINGLE_STEP - start_script_complete=(unsigned long)&script_complete[0]; - len_script_complete=i*4; -#endif - i=0; - script_error[i++]=swap_script(SCR_INT); /* interrupt if error */ - script_error[i++]=SIR_SCRIPT_ERROR; -#ifdef SCSI_SINGLE_STEP - start_script_error=(unsigned long)&script_error[0]; - len_script_error=i*4; -#endif - i=0; - script_reselection[i++]=swap_script(SCR_CLR (SCR_TRG)); /* target status */ - script_reselection[i++]=0; - script_reselection[i++]=swap_script(SCR_WAIT_RESEL); - script_reselection[i++]=swap_script(phys_to_bus(&script_select[0])); /* len = 4 */ -#ifdef SCSI_SINGLE_STEP - start_script_reselection=(unsigned long)&script_reselection[0]; - len_script_reselection=i*4; -#endif -} - - -void scsi_issue(ccb *pccb) -{ - int busdevfunc = pccb->priv; - int i; - unsigned short sstat; - int retrycnt; /* retry counter */ - for(i=0;i<3;i++) - int_stat[i]=0; /* delete all int status */ - /* struct pccb must be set-up correctly */ - retrycnt=0; - PRINTF("ID %d issue cmd %02X\n",pccb->target,pccb->cmd[0]); - pccb->trans_bytes=0; /* no bytes transferred yet */ - scsi_set_script(pccb); /* fill in SCRIPT */ - scsi_int_mask=STO | UDC | MA; /* | CMP; / * Interrupts which are enabled */ - script_int_mask=0xff; /* enable all Ints */ - scsi_int_enable(); - scsi_write_dsp(phys_to_bus(&script_select[0])); /* start script */ - /* now we have to wait for IRQs */ -retry: - /* - * This version of the driver is _not_ interrupt driven, - * but polls the chip's interrupt registers (ISTAT, DSTAT). - */ - while(int_stat[0]==0) - handle_scsi_int(); - - if(int_stat[0]==SIR_COMPLETE) { - if(pccb->msgin[0]==M_DISCONNECT) { - PRINTF("Wait for reselection\n"); - for(i=0;i<3;i++) - int_stat[i]=0; /* delete all int status */ - scsi_write_dsp(phys_to_bus(&script_reselection[0])); /* start reselection script */ - goto retry; - } - pccb->contr_stat=SIR_COMPLETE; - return; - } - if((int_stat[0] & SCSI_INT_STATE)==SCSI_INT_STATE) { /* scsi interrupt */ - sstat=(unsigned short)int_stat[0]; - if((sstat & STO)==STO) { /* selection timeout */ - pccb->contr_stat=SCSI_SEL_TIME_OUT; - scsi_write_byte(GPREG,0x01); - PRINTF("ID: %X Selection Timeout\n",pccb->target); - return; - } - if((sstat & UDC)==UDC) { /* unexpected disconnect */ - pccb->contr_stat=SCSI_UNEXP_DIS; - scsi_write_byte(GPREG,0x01); - PRINTF("ID: %X Unexpected Disconnect\n",pccb->target); - return; - } - if((sstat & RSL)==RSL) { /* reselection */ - pccb->contr_stat=SCSI_UNEXP_DIS; - scsi_write_byte(GPREG,0x01); - PRINTF("ID: %X Unexpected Disconnect\n",pccb->target); - return; - } - if(((sstat & MA)==MA)||((sstat & HTH)==HTH)) { /* phase missmatch */ - if(retrycnttrans_bytes=pccb->datalen - - ((unsigned long)scsi_read_byte(DBC) | - ((unsigned long)scsi_read_byte(DBC+1)<<8) | - ((unsigned long)scsi_read_byte(DBC+2)<<16)); - for(i=0;i<3;i++) - int_stat[i]=0; /* delete all int status */ - retrycnt++; - PRINTF("ID: %X Phase Missmatch Retry %d Phase %02X transferred %lx\n", - pccb->target,retrycnt,scsi_read_byte(SBCL),pccb->trans_bytes); - scsi_write_dsp(phys_to_bus(&script_cmd[4])); /* start retry script */ - goto retry; - } - if((sstat & MA)==MA) - pccb->contr_stat=SCSI_MA_TIME_OUT; - else - pccb->contr_stat=SCSI_HNS_TIME_OUT; - PRINTF("Phase Missmatch stat %lx\n",pccb->contr_stat); - return; - } /* no phase int */ -/* if((sstat & CMP)==CMP) { - pccb->contr_stat=SIR_COMPLETE; - return; - } -*/ - PRINTF("SCSI INT %lX\n",int_stat[0]); - pccb->contr_stat=int_stat[0]; - return; - } /* end scsi int */ - PRINTF("SCRIPT INT %lX phase %02X\n",int_stat[0],scsi_read_byte(SBCL)); - pccb->contr_stat=int_stat[0]; - return; -} - -int scsi_exec(ccb *pccb) -{ - unsigned char tmpcmd[16],tmpstat; - int i,retrycnt,t; - unsigned long transbytes,datalen; - unsigned char *tmpptr; - retrycnt=0; -retry: - scsi_issue(pccb); - if(pccb->contr_stat!=SIR_COMPLETE) - return false; - if(pccb->status==S_GOOD) - return true; - if(pccb->status==S_CHECK_COND) { /* check condition */ - for(i=0;i<16;i++) - tmpcmd[i]=pccb->cmd[i]; - pccb->cmd[0]=SCSI_REQ_SENSE; - pccb->cmd[1]=pccb->lun<<5; - pccb->cmd[2]=0; - pccb->cmd[3]=0; - pccb->cmd[4]=14; - pccb->cmd[5]=0; - pccb->cmdlen=6; - pccb->msgout[0]=SCSI_IDENTIFY; - transbytes=pccb->trans_bytes; - tmpptr=pccb->pdata; - pccb->pdata = &pccb->sense_buf[0]; - datalen=pccb->datalen; - pccb->datalen=14; - tmpstat=pccb->status; - scsi_issue(pccb); - for(i=0;i<16;i++) - pccb->cmd[i]=tmpcmd[i]; - pccb->trans_bytes=transbytes; - pccb->pdata=tmpptr; - pccb->datalen=datalen; - pccb->status=tmpstat; - PRINTF("Request_sense sense key %x ASC %x ASCQ %x\n",pccb->sense_buf[2]&0x0f, - pccb->sense_buf[12],pccb->sense_buf[13]); - switch(pccb->sense_buf[2]&0xf) { - case SENSE_NO_SENSE: - case SENSE_RECOVERED_ERROR: - /* seems to be ok */ - return true; - break; - case SENSE_NOT_READY: - if((pccb->sense_buf[12]!=0x04)||(pccb->sense_buf[13]!=0x01)) { - /* if device is not in process of becoming ready */ - return false; - break; - } /* else fall through */ - case SENSE_UNIT_ATTENTION: - if(retrycnttarget,retrycnt); - for(t=0;ttarget,retrycnt); - return false; - default: - return false; - } - } - PRINTF("Status = %X\n",pccb->status); - return false; -} - - -void scsi_chip_init(void) -{ - /* first we issue a soft reset */ - scsi_write_byte(ISTAT,SRST); - udelay(1000); - scsi_write_byte(ISTAT,0); - /* setup chip */ - scsi_write_byte(SCNTL0,0xC0); /* full arbitration no start, no message, parity disabled, master */ - scsi_write_byte(SCNTL1,0x00); - scsi_write_byte(SCNTL2,0x00); -#ifndef CONFIG_SYS_SCSI_SYM53C8XX_CCF /* config value for none 40 MHz clocks */ - scsi_write_byte(SCNTL3,0x13); /* synchronous clock 40/4=10MHz, asynchronous 40MHz */ -#else - scsi_write_byte(SCNTL3,CONFIG_SYS_SCSI_SYM53C8XX_CCF); /* config value for none 40 MHz clocks */ -#endif - scsi_write_byte(SCID,0x47); /* ID=7, enable reselection */ - scsi_write_byte(SXFER,0x00); /* synchronous transfer period 10MHz, asynchronous */ - scsi_write_byte(SDID,0x00); /* targed SCSI ID = 0 */ - scsi_int_mask=0x0000; /* no Interrupt is enabled */ - script_int_mask=0x00; - scsi_int_enable(); - scsi_write_byte(GPREG,0x01); /* GPIO0 is LED (off) */ - scsi_write_byte(GPCNTL,0x0E); /* GPIO0 is Output */ - scsi_write_byte(STIME0,0x08); /* handshake timer disabled, selection timeout 512msec */ - scsi_write_byte(RESPID,0x80); /* repond only to the own ID (reselection) */ - scsi_write_byte(STEST1,0x00); /* not isolated, SCLK is used */ - scsi_write_byte(STEST2,0x00); /* no Lowlevel Mode? */ - scsi_write_byte(STEST3,0x80); /* enable tolerANT */ - scsi_write_byte(CTEST3,0x04); /* clear FIFO */ - scsi_write_byte(CTEST4,0x00); - scsi_write_byte(CTEST5,0x00); -#ifdef SCSI_SINGLE_STEP -/* scsi_write_byte(DCNTL,IRQM | SSM); */ - scsi_write_byte(DCNTL,IRQD | SSM); - scsi_write_byte(DMODE,MAN); -#else -/* scsi_write_byte(DCNTL,IRQM); */ - scsi_write_byte(DCNTL,IRQD); - scsi_write_byte(DMODE,0x00); -#endif -} -#endif diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt index 5b3aa09..50220e1 100644 --- a/scripts/config_whitelist.txt +++ b/scripts/config_whitelist.txt @@ -2043,7 +2043,6 @@ CONFIG_SCSI_AHCI CONFIG_SCSI_AHCI_PLAT CONFIG_SCSI_DEV_ID CONFIG_SCSI_DEV_LIST -CONFIG_SCSI_SYM53C8XX CONFIG_SC_TIMER_CLK CONFIG_SDCARD CONFIG_SDRAM_OFFSET_FOR_RT @@ -4625,7 +4624,6 @@ CONFIG_SYS_SCSI_MAX_DEVICE CONFIG_SYS_SCSI_MAX_LUN CONFIG_SYS_SCSI_MAX_SCSI_ID CONFIG_SYS_SCSI_SPIN_UP_TIME -CONFIG_SYS_SCSI_SYM53C8XX_CCF CONFIG_SYS_SDHC_CLK CONFIG_SYS_SDHC_CLK_2_PLL CONFIG_SYS_SDIO0 -- cgit v0.10.2 From a6fb185c70d8ac455ed16d3bae23c3727db07116 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 14 Jun 2017 21:28:23 -0600 Subject: scsi: Drop scsi_print_error() This function is only defined by one driver and is empty. Move it into the SCSI implementation itself. We could remove it, but it should be useful for debugging. Signed-off-by: Simon Glass Reviewed-by: Bin Meng diff --git a/common/scsi.c b/common/scsi.c index 4896fb9..6175e50 100644 --- a/common/scsi.c +++ b/common/scsi.c @@ -48,6 +48,11 @@ static struct blk_desc scsi_dev_desc[CONFIG_SYS_SCSI_MAX_DEVICE]; #define SCSI_MAX_READ_BLK 0xFFFF #define SCSI_LBA48_READ 0xFFFFFFF +static void scsi_print_error(ccb *pccb) +{ + /* Dummy function that could print an error for debugging */ +} + #ifdef CONFIG_SYS_64BIT_LBA void scsi_setup_read16(ccb *pccb, lbaint_t start, unsigned long blocks) { diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c index 3fa14a7..f474471 100644 --- a/drivers/block/ahci.c +++ b/drivers/block/ahci.c @@ -1092,8 +1092,3 @@ __weak void scsi_bus_reset(void) { /*Not implement*/ } - -void scsi_print_error(ccb * pccb) -{ - /*The ahci error info can be read in the ahci driver*/ -} diff --git a/drivers/block/sandbox_scsi.c b/drivers/block/sandbox_scsi.c index ad961bd..f4004a3 100644 --- a/drivers/block/sandbox_scsi.c +++ b/drivers/block/sandbox_scsi.c @@ -23,7 +23,3 @@ int scsi_exec(ccb *pccb) { return 0; } - -void scsi_print_error(ccb *pccb) -{ -} diff --git a/include/scsi.h b/include/scsi.h index 190dacd..621d938 100644 --- a/include/scsi.h +++ b/include/scsi.h @@ -163,7 +163,6 @@ typedef struct SCSI_cmd_block{ * decleration of functions which have to reside in the LowLevel Part Driver */ -void scsi_print_error(ccb *pccb); int scsi_exec(ccb *pccb); void scsi_bus_reset(void); #if !defined(CONFIG_DM_SCSI) -- cgit v0.10.2 From 3bf926c0dd01e7beb3a6815b2e0f28e989fe4120 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 14 Jun 2017 21:28:24 -0600 Subject: Convert CONFIG_CMD_SATA to Kconfig This converts the following to Kconfig: CONFIG_CMD_SATA Signed-off-by: Simon Glass Reviewed-by: Bin Meng diff --git a/arch/Kconfig b/arch/Kconfig index 8d5d77a..7e76abd 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -76,6 +76,7 @@ config SANDBOX imply HASH_VERIFY imply LZMA imply SCSI + imply CMD_SATA config SH bool "SuperH architecture" diff --git a/arch/arm/cpu/armv7/mx6/Kconfig b/arch/arm/cpu/armv7/mx6/Kconfig index 4fd60d4..1e5dc9a 100644 --- a/arch/arm/cpu/armv7/mx6/Kconfig +++ b/arch/arm/cpu/armv7/mx6/Kconfig @@ -77,6 +77,7 @@ config TARGET_ADVANTECH_DMS_BA16 bool "Advantech dms-ba16" select BOARD_LATE_INIT select MX6Q + imply CMD_SATA config TARGET_APALIS_IMX6 bool "Toradex Apalis iMX6 board" @@ -85,6 +86,7 @@ config TARGET_APALIS_IMX6 select DM select DM_SERIAL select DM_THERMAL + imply CMD_SATA config TARGET_ARISTAINETOS bool "aristainetos" @@ -141,6 +143,7 @@ config TARGET_GE_B850V3 config TARGET_GW_VENTANA bool "gw_ventana" select SUPPORT_SPL + imply CMD_SATA config TARGET_KOSAGI_NOVENA bool "Kosagi Novena" @@ -302,6 +305,7 @@ config TARGET_OPOS6ULDEV config TARGET_OT1200 bool "Bachmann OT1200" select SUPPORT_SPL + imply CMD_SATA config TARGET_PICO_IMX6UL bool "PICO-IMX6UL-EMMC" diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig index 89476a6..3e48d58 100644 --- a/arch/arm/mach-mvebu/Kconfig +++ b/arch/arm/mach-mvebu/Kconfig @@ -57,6 +57,7 @@ config MV78230 config MV78260 bool select ARMADA_XP + imply CMD_SATA config MV78460 bool @@ -113,6 +114,7 @@ config TARGET_THEADORABLE bool "Support theadorable Armada XP" select BOARD_LATE_INIT if USB select MV78260 + imply CMD_SATA config TARGET_CONTROLCENTERDC bool "Support CONTROLCENTERDC" diff --git a/arch/powerpc/cpu/mpc83xx/Kconfig b/arch/powerpc/cpu/mpc83xx/Kconfig index 0772b7c..cdd21a2 100644 --- a/arch/powerpc/cpu/mpc83xx/Kconfig +++ b/arch/powerpc/cpu/mpc83xx/Kconfig @@ -54,6 +54,7 @@ config TARGET_MPC8349ITX config TARGET_MPC837XEMDS bool "Support MPC837XEMDS" select BOARD_EARLY_INIT_F + imply CMD_SATA config TARGET_MPC837XERDB bool "Support MPC837XERDB" diff --git a/arch/powerpc/cpu/mpc85xx/Kconfig b/arch/powerpc/cpu/mpc85xx/Kconfig index a4b2761..0bff79a 100644 --- a/arch/powerpc/cpu/mpc85xx/Kconfig +++ b/arch/powerpc/cpu/mpc85xx/Kconfig @@ -63,30 +63,35 @@ config TARGET_P3041DS select PHYS_64BIT select ARCH_P3041 select BOARD_LATE_INIT if CHAIN_OF_TRUST + imply CMD_SATA config TARGET_P4080DS bool "Support P4080DS" select PHYS_64BIT select ARCH_P4080 select BOARD_LATE_INIT if CHAIN_OF_TRUST + imply CMD_SATA config TARGET_P5020DS bool "Support P5020DS" select PHYS_64BIT select ARCH_P5020 select BOARD_LATE_INIT if CHAIN_OF_TRUST + imply CMD_SATA config TARGET_P5040DS bool "Support P5040DS" select PHYS_64BIT select ARCH_P5040 select BOARD_LATE_INIT if CHAIN_OF_TRUST + imply CMD_SATA config TARGET_MPC8536DS bool "Support MPC8536DS" select ARCH_MPC8536 # Use DDR3 controller with DDR2 DIMMs on this board select SYS_FSL_DDRC_GEN3 + imply CMD_SATA config TARGET_MPC8541CDS bool "Support MPC8541CDS" @@ -126,6 +131,7 @@ config TARGET_P1010RDB_PA select SUPPORT_SPL select SUPPORT_TPL imply CMD_EEPROM + imply CMD_SATA config TARGET_P1010RDB_PB bool "Support P1010RDB_PB" @@ -134,12 +140,14 @@ config TARGET_P1010RDB_PB select SUPPORT_SPL select SUPPORT_TPL imply CMD_EEPROM + imply CMD_SATA config TARGET_P1022DS bool "Support P1022DS" select ARCH_P1022 select SUPPORT_SPL select SUPPORT_TPL + imply CMD_SATA config TARGET_P1023RDB bool "Support P1023RDB" @@ -152,6 +160,7 @@ config TARGET_P1020MBG select SUPPORT_TPL select ARCH_P1020 imply CMD_EEPROM + imply CMD_SATA config TARGET_P1020RDB_PC bool "Support P1020RDB-PC" @@ -159,6 +168,7 @@ config TARGET_P1020RDB_PC select SUPPORT_TPL select ARCH_P1020 imply CMD_EEPROM + imply CMD_SATA config TARGET_P1020RDB_PD bool "Support P1020RDB-PD" @@ -166,6 +176,7 @@ config TARGET_P1020RDB_PD select SUPPORT_TPL select ARCH_P1020 imply CMD_EEPROM + imply CMD_SATA config TARGET_P1020UTM bool "Support P1020UTM" @@ -173,6 +184,7 @@ config TARGET_P1020UTM select SUPPORT_TPL select ARCH_P1020 imply CMD_EEPROM + imply CMD_SATA config TARGET_P1021RDB bool "Support P1021RDB" @@ -180,6 +192,7 @@ config TARGET_P1021RDB select SUPPORT_TPL select ARCH_P1021 imply CMD_EEPROM + imply CMD_SATA config TARGET_P1024RDB bool "Support P1024RDB" @@ -187,6 +200,7 @@ config TARGET_P1024RDB select SUPPORT_TPL select ARCH_P1024 imply CMD_EEPROM + imply CMD_SATA config TARGET_P1025RDB bool "Support P1025RDB" @@ -194,6 +208,7 @@ config TARGET_P1025RDB select SUPPORT_TPL select ARCH_P1025 imply CMD_EEPROM + imply CMD_SATA config TARGET_P2020RDB bool "Support P2020RDB-PC" @@ -201,6 +216,7 @@ config TARGET_P2020RDB select SUPPORT_TPL select ARCH_P2020 imply CMD_EEPROM + imply CMD_SATA config TARGET_P1_TWR bool "Support p1_twr" @@ -211,6 +227,7 @@ config TARGET_P2041RDB select ARCH_P2041 select BOARD_LATE_INIT if CHAIN_OF_TRUST select PHYS_64BIT + imply CMD_SATA config TARGET_QEMU_PPCE500 bool "Support qemu-ppce500" @@ -224,6 +241,7 @@ config TARGET_T1024QDS select SUPPORT_SPL select PHYS_64BIT imply CMD_EEPROM + imply CMD_SATA config TARGET_T1023RDB bool "Support T1023RDB" @@ -247,6 +265,7 @@ config TARGET_T1040QDS select BOARD_LATE_INIT if CHAIN_OF_TRUST select PHYS_64BIT imply CMD_EEPROM + imply CMD_SATA config TARGET_T1040RDB bool "Support T1040RDB" @@ -254,6 +273,7 @@ config TARGET_T1040RDB select BOARD_LATE_INIT if CHAIN_OF_TRUST select SUPPORT_SPL select PHYS_64BIT + imply CMD_SATA config TARGET_T1040D4RDB bool "Support T1040D4RDB" @@ -261,6 +281,7 @@ config TARGET_T1040D4RDB select BOARD_LATE_INIT if CHAIN_OF_TRUST select SUPPORT_SPL select PHYS_64BIT + imply CMD_SATA config TARGET_T1042RDB bool "Support T1042RDB" @@ -268,6 +289,7 @@ config TARGET_T1042RDB select BOARD_LATE_INIT if CHAIN_OF_TRUST select SUPPORT_SPL select PHYS_64BIT + imply CMD_SATA config TARGET_T1042D4RDB bool "Support T1042D4RDB" @@ -275,6 +297,7 @@ config TARGET_T1042D4RDB select BOARD_LATE_INIT if CHAIN_OF_TRUST select SUPPORT_SPL select PHYS_64BIT + imply CMD_SATA config TARGET_T1042RDB_PI bool "Support T1042RDB_PI" @@ -282,6 +305,7 @@ config TARGET_T1042RDB_PI select BOARD_LATE_INIT if CHAIN_OF_TRUST select SUPPORT_SPL select PHYS_64BIT + imply CMD_SATA config TARGET_T2080QDS bool "Support T2080QDS" @@ -289,6 +313,7 @@ config TARGET_T2080QDS select BOARD_LATE_INIT if CHAIN_OF_TRUST select SUPPORT_SPL select PHYS_64BIT + imply CMD_SATA config TARGET_T2080RDB bool "Support T2080RDB" @@ -296,6 +321,7 @@ config TARGET_T2080RDB select BOARD_LATE_INIT if CHAIN_OF_TRUST select SUPPORT_SPL select PHYS_64BIT + imply CMD_SATA config TARGET_T2081QDS bool "Support T2081QDS" @@ -309,6 +335,7 @@ config TARGET_T4160QDS select BOARD_LATE_INIT if CHAIN_OF_TRUST select SUPPORT_SPL select PHYS_64BIT + imply CMD_SATA config TARGET_T4160RDB bool "Support T4160RDB" @@ -322,12 +349,14 @@ config TARGET_T4240QDS select BOARD_LATE_INIT if CHAIN_OF_TRUST select SUPPORT_SPL select PHYS_64BIT + imply CMD_SATA config TARGET_T4240RDB bool "Support T4240RDB" select ARCH_T4240 select SUPPORT_SPL select PHYS_64BIT + imply CMD_SATA config TARGET_CONTROLCENTERD bool "Support controlcenterd" @@ -357,6 +386,7 @@ config TARGET_XPEDITE550X config TARGET_UCP1020 bool "Support uCP1020" select ARCH_P1020 + imply CMD_SATA config TARGET_CYRUS_P5020 bool "Support Varisys Cyrus P5020" @@ -478,6 +508,7 @@ config ARCH_MPC8536 select SYS_FSL_SEC_COMPAT_2 select SYS_PPC_E500_USE_DEBUG_TLB select FSL_ELBC + imply CMD_SATA config ARCH_MPC8540 bool @@ -586,6 +617,7 @@ config ARCH_P1010 select SYS_PPC_E500_USE_DEBUG_TLB select FSL_IFC imply CMD_EEPROM + imply CMD_SATA config ARCH_P1011 bool @@ -614,6 +646,7 @@ config ARCH_P1020 select SYS_FSL_SEC_COMPAT_2 select SYS_PPC_E500_USE_DEBUG_TLB select FSL_ELBC + imply CMD_SATA config ARCH_P1021 bool @@ -628,6 +661,7 @@ config ARCH_P1021 select SYS_FSL_SEC_COMPAT_2 select SYS_PPC_E500_USE_DEBUG_TLB select FSL_ELBC + imply CMD_SATA config ARCH_P1022 bool @@ -671,6 +705,7 @@ config ARCH_P1024 select SYS_PPC_E500_USE_DEBUG_TLB select FSL_ELBC imply CMD_EEPROM + imply CMD_SATA config ARCH_P1025 bool @@ -685,6 +720,7 @@ config ARCH_P1025 select SYS_FSL_SEC_COMPAT_2 select SYS_PPC_E500_USE_DEBUG_TLB select FSL_ELBC + imply CMD_SATA config ARCH_P2020 bool @@ -747,6 +783,7 @@ config ARCH_P3041 select SYS_FSL_SEC_BE select SYS_FSL_SEC_COMPAT_4 select FSL_ELBC + imply CMD_SATA config ARCH_P4080 bool @@ -782,6 +819,7 @@ config ARCH_P4080 select SYS_FSL_SEC_BE select SYS_FSL_SEC_COMPAT_4 select FSL_ELBC + imply CMD_SATA config ARCH_P5020 bool @@ -803,6 +841,7 @@ config ARCH_P5020 select SYS_FSL_SEC_COMPAT_4 select SYS_PPC64 select FSL_ELBC + imply CMD_SATA config ARCH_P5040 bool @@ -824,6 +863,7 @@ config ARCH_P5040 select SYS_FSL_SEC_COMPAT_4 select SYS_PPC64 select FSL_ELBC + imply CMD_SATA config ARCH_QEMU_E500 bool @@ -881,6 +921,7 @@ config ARCH_T1040 select SYS_FSL_SEC_BE select SYS_FSL_SEC_COMPAT_5 select FSL_IFC + imply CMD_SATA config ARCH_T1042 bool @@ -899,6 +940,7 @@ config ARCH_T1042 select SYS_FSL_SEC_BE select SYS_FSL_SEC_COMPAT_5 select FSL_IFC + imply CMD_SATA config ARCH_T2080 bool @@ -921,6 +963,7 @@ config ARCH_T2080 select SYS_FSL_SEC_COMPAT_4 select SYS_PPC64 select FSL_IFC + imply CMD_SATA config ARCH_T2081 bool @@ -962,6 +1005,7 @@ config ARCH_T4160 select SYS_FSL_SEC_COMPAT_4 select SYS_PPC64 select FSL_IFC + imply CMD_SATA config ARCH_T4240 bool @@ -986,6 +1030,7 @@ config ARCH_T4240 select SYS_FSL_SEC_COMPAT_4 select SYS_PPC64 select FSL_IFC + imply CMD_SATA config BOOKE bool diff --git a/cmd/Kconfig b/cmd/Kconfig index 6758db1..90d9337 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -734,6 +734,18 @@ config CMD_FDC help The 'fdtboot' command allows booting an image from a floppy disk. +config CMD_SATA + bool "sata - Access SATA subsystem" + help + SATA (Serial Advanced Technology Attachment) is a serial bus + standard for connecting to hard drives and other storage devices. + This command provides information about attached devices and allows + reading, writing and other operations. + + SATA replaces PATA (originally just ATA), which stands for Parallel AT + Attachment, where AT refers to an IBM AT (Advanced Technology) + computer released in 1984. + endmenu diff --git a/configs/MPC8315ERDB_defconfig b/configs/MPC8315ERDB_defconfig index 38417e7..32b88fc 100644 --- a/configs/MPC8315ERDB_defconfig +++ b/configs/MPC8315ERDB_defconfig @@ -7,6 +7,7 @@ CONFIG_BOOTDELAY=6 CONFIG_HUSH_PARSER=y CONFIG_CMD_I2C=y CONFIG_CMD_USB=y +CONFIG_CMD_SATA=y # CONFIG_CMD_SETEXPR is not set CONFIG_CMD_MII=y CONFIG_CMD_PING=y diff --git a/configs/MPC8349ITX_LOWBOOT_defconfig b/configs/MPC8349ITX_LOWBOOT_defconfig index 9cec452..c7f093e 100644 --- a/configs/MPC8349ITX_LOWBOOT_defconfig +++ b/configs/MPC8349ITX_LOWBOOT_defconfig @@ -10,6 +10,7 @@ CONFIG_SYS_PROMPT="MPC8349E-mITX> " CONFIG_CMD_IDE=y CONFIG_CMD_I2C=y CONFIG_CMD_USB=y +CONFIG_CMD_SATA=y # CONFIG_CMD_SETEXPR is not set CONFIG_CMD_DHCP=y CONFIG_CMD_PING=y diff --git a/configs/MPC8349ITX_defconfig b/configs/MPC8349ITX_defconfig index 9145ada..e508b3d 100644 --- a/configs/MPC8349ITX_defconfig +++ b/configs/MPC8349ITX_defconfig @@ -10,6 +10,7 @@ CONFIG_SYS_PROMPT="MPC8349E-mITX> " CONFIG_CMD_IDE=y CONFIG_CMD_I2C=y CONFIG_CMD_USB=y +CONFIG_CMD_SATA=y # CONFIG_CMD_SETEXPR is not set CONFIG_CMD_DHCP=y CONFIG_CMD_PING=y diff --git a/configs/MPC837XERDB_defconfig b/configs/MPC837XERDB_defconfig index 2f3e7b0..fc21671 100644 --- a/configs/MPC837XERDB_defconfig +++ b/configs/MPC837XERDB_defconfig @@ -8,6 +8,7 @@ CONFIG_HUSH_PARSER=y CONFIG_CMD_MMC=y CONFIG_CMD_I2C=y CONFIG_CMD_USB=y +CONFIG_CMD_SATA=y # CONFIG_CMD_SETEXPR is not set CONFIG_CMD_MII=y CONFIG_CMD_PING=y diff --git a/configs/cgtqmx6eval_defconfig b/configs/cgtqmx6eval_defconfig index 77dd227..94d7e76 100644 --- a/configs/cgtqmx6eval_defconfig +++ b/configs/cgtqmx6eval_defconfig @@ -33,6 +33,7 @@ CONFIG_CMD_USB=y CONFIG_CMD_DFU=y CONFIG_CMD_USB_MASS_STORAGE=y CONFIG_CMD_GPIO=y +CONFIG_CMD_SATA=y # CONFIG_CMD_SETEXPR is not set CONFIG_CMD_DHCP=y CONFIG_CMD_MII=y diff --git a/configs/cm_fx6_defconfig b/configs/cm_fx6_defconfig index dc587a6..a548d8f 100644 --- a/configs/cm_fx6_defconfig +++ b/configs/cm_fx6_defconfig @@ -35,6 +35,7 @@ CONFIG_CMD_I2C=y CONFIG_CMD_USB=y # CONFIG_CMD_FPGA is not set CONFIG_CMD_GPIO=y +CONFIG_CMD_SATA=y # CONFIG_CMD_SETEXPR is not set CONFIG_CMD_DHCP=y CONFIG_CMD_PING=y diff --git a/configs/controlcenterd_36BIT_SDCARD_DEVELOP_defconfig b/configs/controlcenterd_36BIT_SDCARD_DEVELOP_defconfig index cff3f45..d05f35d 100644 --- a/configs/controlcenterd_36BIT_SDCARD_DEVELOP_defconfig +++ b/configs/controlcenterd_36BIT_SDCARD_DEVELOP_defconfig @@ -22,6 +22,7 @@ CONFIG_CMD_MMC=y CONFIG_CMD_SF=y CONFIG_CMD_I2C=y CONFIG_CMD_USB=y +CONFIG_CMD_SATA=y CONFIG_CMD_MII=y CONFIG_CMD_PING=y CONFIG_CMD_BMP=y diff --git a/configs/controlcenterd_36BIT_SDCARD_defconfig b/configs/controlcenterd_36BIT_SDCARD_defconfig index f155089..d2af507 100644 --- a/configs/controlcenterd_36BIT_SDCARD_defconfig +++ b/configs/controlcenterd_36BIT_SDCARD_defconfig @@ -22,6 +22,7 @@ CONFIG_CMD_MMC=y CONFIG_CMD_SF=y CONFIG_CMD_I2C=y CONFIG_CMD_USB=y +CONFIG_CMD_SATA=y CONFIG_CMD_MII=y CONFIG_CMD_PING=y CONFIG_CMD_BMP=y diff --git a/configs/db-mv784mp-gp_defconfig b/configs/db-mv784mp-gp_defconfig index 9e7e89e..99533b9 100644 --- a/configs/db-mv784mp-gp_defconfig +++ b/configs/db-mv784mp-gp_defconfig @@ -21,6 +21,7 @@ CONFIG_CMD_SF=y CONFIG_CMD_SPI=y CONFIG_CMD_I2C=y CONFIG_CMD_USB=y +CONFIG_CMD_SATA=y # CONFIG_CMD_SETEXPR is not set CONFIG_CMD_TFTPPUT=y CONFIG_CMD_DHCP=y diff --git a/configs/m53evk_defconfig b/configs/m53evk_defconfig index cc4a74c..afcaf58 100644 --- a/configs/m53evk_defconfig +++ b/configs/m53evk_defconfig @@ -24,6 +24,7 @@ CONFIG_CMD_GREPENV=y CONFIG_CMD_MMC=y CONFIG_CMD_I2C=y CONFIG_CMD_USB=y +CONFIG_CMD_SATA=y CONFIG_CMD_DHCP=y CONFIG_CMD_MII=y CONFIG_CMD_PING=y diff --git a/configs/mx53loco_defconfig b/configs/mx53loco_defconfig index 5727356..6e2f585 100644 --- a/configs/mx53loco_defconfig +++ b/configs/mx53loco_defconfig @@ -14,6 +14,7 @@ CONFIG_CMD_BOOTZ=y # CONFIG_CMD_IMLS is not set CONFIG_CMD_MMC=y CONFIG_CMD_USB=y +CONFIG_CMD_SATA=y # CONFIG_CMD_SETEXPR is not set CONFIG_CMD_DHCP=y CONFIG_CMD_MII=y diff --git a/configs/mx6qsabrelite_defconfig b/configs/mx6qsabrelite_defconfig index a542799..32bd271 100644 --- a/configs/mx6qsabrelite_defconfig +++ b/configs/mx6qsabrelite_defconfig @@ -19,6 +19,7 @@ CONFIG_CMD_I2C=y CONFIG_CMD_USB=y CONFIG_CMD_USB_MASS_STORAGE=y CONFIG_CMD_GPIO=y +CONFIG_CMD_SATA=y CONFIG_CMD_DHCP=y CONFIG_CMD_MII=y CONFIG_CMD_PING=y diff --git a/configs/nitrogen6q2g_defconfig b/configs/nitrogen6q2g_defconfig index a19d093..baa509d 100644 --- a/configs/nitrogen6q2g_defconfig +++ b/configs/nitrogen6q2g_defconfig @@ -19,6 +19,7 @@ CONFIG_CMD_I2C=y CONFIG_CMD_USB=y CONFIG_CMD_USB_MASS_STORAGE=y CONFIG_CMD_GPIO=y +CONFIG_CMD_SATA=y CONFIG_CMD_DHCP=y CONFIG_CMD_MII=y CONFIG_CMD_PING=y diff --git a/configs/nitrogen6q_defconfig b/configs/nitrogen6q_defconfig index edf4b63..ebfa843 100644 --- a/configs/nitrogen6q_defconfig +++ b/configs/nitrogen6q_defconfig @@ -19,6 +19,7 @@ CONFIG_CMD_I2C=y CONFIG_CMD_USB=y CONFIG_CMD_USB_MASS_STORAGE=y CONFIG_CMD_GPIO=y +CONFIG_CMD_SATA=y CONFIG_CMD_DHCP=y CONFIG_CMD_MII=y CONFIG_CMD_PING=y diff --git a/configs/novena_defconfig b/configs/novena_defconfig index afacea7..3f8b98e 100644 --- a/configs/novena_defconfig +++ b/configs/novena_defconfig @@ -28,6 +28,7 @@ CONFIG_CMD_MMC=y CONFIG_CMD_I2C=y CONFIG_CMD_USB=y CONFIG_CMD_GPIO=y +CONFIG_CMD_SATA=y CONFIG_CMD_CACHE=y CONFIG_CMD_TIME=y CONFIG_CMD_EXT4_WRITE=y diff --git a/configs/tbs2910_defconfig b/configs/tbs2910_defconfig index ac8f9c6..90a238c 100644 --- a/configs/tbs2910_defconfig +++ b/configs/tbs2910_defconfig @@ -21,6 +21,7 @@ CONFIG_CMD_I2C=y CONFIG_CMD_USB=y CONFIG_CMD_USB_MASS_STORAGE=y CONFIG_CMD_GPIO=y +CONFIG_CMD_SATA=y CONFIG_CMD_DHCP=y CONFIG_CMD_MII=y CONFIG_CMD_PING=y diff --git a/configs/udoo_defconfig b/configs/udoo_defconfig index 3bf5505..7e52bdc 100644 --- a/configs/udoo_defconfig +++ b/configs/udoo_defconfig @@ -19,6 +19,7 @@ CONFIG_CMD_BOOTZ=y # CONFIG_CMD_IMLS is not set CONFIG_CMD_MMC=y CONFIG_CMD_GPIO=y +CONFIG_CMD_SATA=y CONFIG_CMD_DHCP=y CONFIG_CMD_MII=y CONFIG_CMD_PING=y diff --git a/configs/wandboard_defconfig b/configs/wandboard_defconfig index b4b3283..95a14ca 100644 --- a/configs/wandboard_defconfig +++ b/configs/wandboard_defconfig @@ -25,6 +25,7 @@ CONFIG_CMD_MMC=y CONFIG_CMD_I2C=y CONFIG_CMD_USB=y CONFIG_CMD_GPIO=y +CONFIG_CMD_SATA=y CONFIG_CMD_CACHE=y CONFIG_CMD_EXT4_WRITE=y CONFIG_DM=y diff --git a/include/configs/MPC8315ERDB.h b/include/configs/MPC8315ERDB.h index fbe033a..522f12c 100644 --- a/include/configs/MPC8315ERDB.h +++ b/include/configs/MPC8315ERDB.h @@ -415,7 +415,6 @@ #ifdef CONFIG_FSL_SATA #define CONFIG_LBA48 -#define CONFIG_CMD_SATA #endif /* diff --git a/include/configs/MPC8349ITX.h b/include/configs/MPC8349ITX.h index 46f09d6..53e089a 100644 --- a/include/configs/MPC8349ITX.h +++ b/include/configs/MPC8349ITX.h @@ -485,10 +485,6 @@ boards, we say we have two, but don't display a message if we find only one. */ #define CONFIG_SUPPORT_VFAT #endif -#ifdef CONFIG_SATA_SIL3114 - #define CONFIG_CMD_SATA -#endif - #if defined(CONFIG_SATA_SIL3114) || defined(CONFIG_USB_STORAGE) #endif diff --git a/include/configs/MPC837XEMDS.h b/include/configs/MPC837XEMDS.h index fcced0e..459efb5 100644 --- a/include/configs/MPC837XEMDS.h +++ b/include/configs/MPC837XEMDS.h @@ -436,7 +436,6 @@ extern int board_pci_host_broken(void); #ifdef CONFIG_FSL_SATA #define CONFIG_LBA48 -#define CONFIG_CMD_SATA #endif /* diff --git a/include/configs/MPC837XERDB.h b/include/configs/MPC837XERDB.h index 607b926..7afbc90 100644 --- a/include/configs/MPC837XERDB.h +++ b/include/configs/MPC837XERDB.h @@ -449,7 +449,6 @@ #ifdef CONFIG_FSL_SATA #define CONFIG_LBA48 -#define CONFIG_CMD_SATA #endif /* diff --git a/include/configs/MPC8536DS.h b/include/configs/MPC8536DS.h index 18b6b4e..470bb72 100644 --- a/include/configs/MPC8536DS.h +++ b/include/configs/MPC8536DS.h @@ -522,7 +522,6 @@ #ifdef CONFIG_FSL_SATA #define CONFIG_LBA48 -#define CONFIG_CMD_SATA #endif #if defined(CONFIG_TSEC_ENET) diff --git a/include/configs/P1010RDB.h b/include/configs/P1010RDB.h index 220b070..0dc062a 100644 --- a/include/configs/P1010RDB.h +++ b/include/configs/P1010RDB.h @@ -657,7 +657,6 @@ extern unsigned long get_sdram_size(void); #define CONFIG_SYS_SATA2 CONFIG_SYS_MPC85xx_SATA2_ADDR #define CONFIG_SYS_SATA2_FLAGS FLAGS_DMA -#define CONFIG_CMD_SATA #define CONFIG_LBA48 #endif /* #ifdef CONFIG_FSL_SATA */ diff --git a/include/configs/P1022DS.h b/include/configs/P1022DS.h index 3d12c84..2ee6c64 100644 --- a/include/configs/P1022DS.h +++ b/include/configs/P1022DS.h @@ -497,7 +497,6 @@ #ifdef CONFIG_FSL_SATA #define CONFIG_LBA48 -#define CONFIG_CMD_SATA #endif #ifdef CONFIG_MMC diff --git a/include/configs/P2041RDB.h b/include/configs/P2041RDB.h index b008e3d..967c83c 100644 --- a/include/configs/P2041RDB.h +++ b/include/configs/P2041RDB.h @@ -548,7 +548,6 @@ unsigned long get_board_sys_clk(unsigned long dummy); #define CONFIG_SYS_SATA2_FLAGS FLAGS_DMA #define CONFIG_LBA48 -#define CONFIG_CMD_SATA #endif #ifdef CONFIG_FMAN_ENET diff --git a/include/configs/P4080DS.h b/include/configs/P4080DS.h index a6fa6a8..f192181 100644 --- a/include/configs/P4080DS.h +++ b/include/configs/P4080DS.h @@ -12,7 +12,6 @@ #define CONFIG_PCIE3 -#define CONFIG_CMD_SATA #define CONFIG_SATA_SIL #define CONFIG_SYS_SATA_MAX_DEVICE 2 #define CONFIG_LIBATA diff --git a/include/configs/T102xQDS.h b/include/configs/T102xQDS.h index 2209cfd..2e3a8c1 100644 --- a/include/configs/T102xQDS.h +++ b/include/configs/T102xQDS.h @@ -628,7 +628,6 @@ unsigned long get_board_ddr_clk(void); #define CONFIG_SYS_SATA1 CONFIG_SYS_MPC85xx_SATA1_ADDR #define CONFIG_SYS_SATA1_FLAGS FLAGS_DMA #define CONFIG_LBA48 -#define CONFIG_CMD_SATA #endif /* diff --git a/include/configs/T1040QDS.h b/include/configs/T1040QDS.h index 3953145..86f7880 100644 --- a/include/configs/T1040QDS.h +++ b/include/configs/T1040QDS.h @@ -518,7 +518,6 @@ unsigned long get_board_ddr_clk(void); #define CONFIG_SYS_SATA2_FLAGS FLAGS_DMA #define CONFIG_LBA48 -#define CONFIG_CMD_SATA #endif /* diff --git a/include/configs/T104xRDB.h b/include/configs/T104xRDB.h index 0035e67..350daca 100644 --- a/include/configs/T104xRDB.h +++ b/include/configs/T104xRDB.h @@ -628,7 +628,6 @@ $(SRCTREE)/board/freescale/t104xrdb/t1042d4_sd_rcw.cfg #define CONFIG_SYS_SATA1_FLAGS FLAGS_DMA #define CONFIG_LBA48 -#define CONFIG_CMD_SATA #endif /* diff --git a/include/configs/T208xQDS.h b/include/configs/T208xQDS.h index e792ec5..9edf190 100644 --- a/include/configs/T208xQDS.h +++ b/include/configs/T208xQDS.h @@ -695,7 +695,6 @@ unsigned long get_board_ddr_clk(void); #define CONFIG_SYS_SATA2 CONFIG_SYS_MPC85xx_SATA2_ADDR #define CONFIG_SYS_SATA2_FLAGS FLAGS_DMA #define CONFIG_LBA48 -#define CONFIG_CMD_SATA #endif /* diff --git a/include/configs/T208xRDB.h b/include/configs/T208xRDB.h index fdafeeb..0e70aa8 100644 --- a/include/configs/T208xRDB.h +++ b/include/configs/T208xRDB.h @@ -645,7 +645,6 @@ unsigned long get_board_ddr_clk(void); #define CONFIG_SYS_SATA2 CONFIG_SYS_MPC85xx_SATA2_ADDR #define CONFIG_SYS_SATA2_FLAGS FLAGS_DMA #define CONFIG_LBA48 -#define CONFIG_CMD_SATA #endif /* diff --git a/include/configs/T4240QDS.h b/include/configs/T4240QDS.h index dc3ebfa..f69746b 100644 --- a/include/configs/T4240QDS.h +++ b/include/configs/T4240QDS.h @@ -489,7 +489,6 @@ unsigned long get_board_ddr_clk(void); #define CONFIG_SYS_SATA2_FLAGS FLAGS_DMA #define CONFIG_LBA48 -#define CONFIG_CMD_SATA #endif #ifdef CONFIG_FMAN_ENET diff --git a/include/configs/T4240RDB.h b/include/configs/T4240RDB.h index 0d9cdfb..ed3b0f7 100644 --- a/include/configs/T4240RDB.h +++ b/include/configs/T4240RDB.h @@ -254,7 +254,6 @@ #define CONFIG_SYS_SATA2_FLAGS FLAGS_DMA #define CONFIG_LBA48 -#define CONFIG_CMD_SATA #endif #ifdef CONFIG_FMAN_ENET @@ -671,7 +670,6 @@ unsigned long get_board_ddr_clk(void); #define CONFIG_SYS_SATA2_FLAGS FLAGS_DMA #define CONFIG_LBA48 -#define CONFIG_CMD_SATA #endif #ifdef CONFIG_FMAN_ENET diff --git a/include/configs/UCP1020.h b/include/configs/UCP1020.h index 8579290..9a7aa81 100644 --- a/include/configs/UCP1020.h +++ b/include/configs/UCP1020.h @@ -118,7 +118,6 @@ #define CONFIG_ENV_OVERWRITE -#define CONFIG_CMD_SATA #define CONFIG_SATA_SIL #define CONFIG_SYS_SATA_MAX_DEVICE 2 #define CONFIG_LIBATA diff --git a/include/configs/advantech_dms-ba16.h b/include/configs/advantech_dms-ba16.h index f320792..66ee167 100644 --- a/include/configs/advantech_dms-ba16.h +++ b/include/configs/advantech_dms-ba16.h @@ -39,7 +39,6 @@ #define CONFIG_MXC_OCOTP /* SATA Configs */ -#define CONFIG_CMD_SATA #define CONFIG_DWC_AHSATA #define CONFIG_SYS_SATA_MAX_DEVICE 1 #define CONFIG_DWC_AHSATA_PORT_ID 0 diff --git a/include/configs/apalis_imx6.h b/include/configs/apalis_imx6.h index 8be586b..b4006a3 100644 --- a/include/configs/apalis_imx6.h +++ b/include/configs/apalis_imx6.h @@ -67,10 +67,6 @@ #define CONFIG_SUPPORT_EMMC_BOOT /* eMMC specific */ #define CONFIG_BOUNCE_BUFFER -#ifdef CONFIG_MX6Q -#define CONFIG_CMD_SATA -#endif - /* * SATA Configs */ diff --git a/include/configs/cgtqmx6eval.h b/include/configs/cgtqmx6eval.h index cad1357..5d797b4 100644 --- a/include/configs/cgtqmx6eval.h +++ b/include/configs/cgtqmx6eval.h @@ -95,7 +95,6 @@ #define CONFIG_IMX_HDMI /* SATA */ -#define CONFIG_CMD_SATA #define CONFIG_DWC_AHSATA #define CONFIG_SYS_SATA_MAX_DEVICE 1 #define CONFIG_DWC_AHSATA_PORT_ID 0 diff --git a/include/configs/cm_fx6.h b/include/configs/cm_fx6.h index dd8010c..1d9c165 100644 --- a/include/configs/cm_fx6.h +++ b/include/configs/cm_fx6.h @@ -224,7 +224,6 @@ #define CONFIG_SYS_I2C_EEPROM_BUS 2 /* SATA */ -#define CONFIG_CMD_SATA #define CONFIG_SYS_SATA_MAX_DEVICE 1 #define CONFIG_LIBATA #define CONFIG_LBA48 diff --git a/include/configs/controlcenterd.h b/include/configs/controlcenterd.h index 6641408..072650d 100644 --- a/include/configs/controlcenterd.h +++ b/include/configs/controlcenterd.h @@ -248,7 +248,6 @@ */ #define CONFIG_LIBATA #define CONFIG_LBA48 -#define CONFIG_CMD_SATA #define CONFIG_FSL_SATA #define CONFIG_SYS_SATA_MAX_DEVICE 2 diff --git a/include/configs/corenet_ds.h b/include/configs/corenet_ds.h index 7bbe31c..92e6ee0 100644 --- a/include/configs/corenet_ds.h +++ b/include/configs/corenet_ds.h @@ -562,7 +562,6 @@ #define CONFIG_SYS_SATA2_FLAGS FLAGS_DMA #define CONFIG_LBA48 -#define CONFIG_CMD_SATA #endif #ifdef CONFIG_FMAN_ENET diff --git a/include/configs/cyrus.h b/include/configs/cyrus.h index a23da19..6079540 100644 --- a/include/configs/cyrus.h +++ b/include/configs/cyrus.h @@ -392,7 +392,6 @@ #define CONFIG_SYS_SATA2_FLAGS FLAGS_DMA #define CONFIG_LBA48 -#define CONFIG_CMD_SATA #endif #ifdef CONFIG_FMAN_ENET diff --git a/include/configs/db-mv784mp-gp.h b/include/configs/db-mv784mp-gp.h index 821aa9d..187ead3 100644 --- a/include/configs/db-mv784mp-gp.h +++ b/include/configs/db-mv784mp-gp.h @@ -27,7 +27,6 @@ */ #define CONFIG_CMD_NAND #define CONFIG_CMD_PCI -#define CONFIG_CMD_SATA /* I2C */ #define CONFIG_SYS_I2C diff --git a/include/configs/gw_ventana.h b/include/configs/gw_ventana.h index 2227eea..de08f2c 100644 --- a/include/configs/gw_ventana.h +++ b/include/configs/gw_ventana.h @@ -109,7 +109,6 @@ /* * SATA Configs */ -#define CONFIG_CMD_SATA #ifdef CONFIG_CMD_SATA #define CONFIG_DWC_AHSATA #define CONFIG_SYS_SATA_MAX_DEVICE 1 diff --git a/include/configs/m53evk.h b/include/configs/m53evk.h index 5181225..a92c228 100644 --- a/include/configs/m53evk.h +++ b/include/configs/m53evk.h @@ -22,7 +22,6 @@ */ #define CONFIG_CMD_NAND #define CONFIG_CMD_NAND_TRIMFFS -#define CONFIG_CMD_SATA /* * Memory configurations diff --git a/include/configs/mx53loco.h b/include/configs/mx53loco.h index 1b6d868..c82e426 100644 --- a/include/configs/mx53loco.h +++ b/include/configs/mx53loco.h @@ -189,7 +189,6 @@ #define CONFIG_ENV_IS_IN_MMC #define CONFIG_SYS_MMC_ENV_DEV 0 -#define CONFIG_CMD_SATA #ifdef CONFIG_CMD_SATA #define CONFIG_DWC_AHSATA #define CONFIG_SYS_SATA_MAX_DEVICE 1 diff --git a/include/configs/nitrogen6x.h b/include/configs/nitrogen6x.h index 00b84f7..576b7b0 100644 --- a/include/configs/nitrogen6x.h +++ b/include/configs/nitrogen6x.h @@ -47,10 +47,6 @@ #define CONFIG_SYS_FSL_ESDHC_ADDR 0 #define CONFIG_SYS_FSL_USDHC_NUM 2 -#ifdef CONFIG_MX6Q -#define CONFIG_CMD_SATA -#endif - /* * SATA Configs */ diff --git a/include/configs/novena.h b/include/configs/novena.h index 1f1bf15..0411598 100644 --- a/include/configs/novena.h +++ b/include/configs/novena.h @@ -18,7 +18,6 @@ /* U-Boot Commands */ #define CONFIG_CMD_PCI -#define CONFIG_CMD_SATA /* U-Boot general configurations */ diff --git a/include/configs/ot1200.h b/include/configs/ot1200.h index 0582fa3..7aeae7b 100644 --- a/include/configs/ot1200.h +++ b/include/configs/ot1200.h @@ -57,10 +57,6 @@ #define CONFIG_MXC_USB_PORTSC (PORT_PTS_UTMI | PORT_PTS_PTW) #define CONFIG_USB_MAX_CONTROLLER_COUNT 2 -#ifdef CONFIG_MX6Q -#define CONFIG_CMD_SATA -#endif - /* * SATA Configs */ diff --git a/include/configs/p1_p2_rdb_pc.h b/include/configs/p1_p2_rdb_pc.h index 71b4f40..a72a57c 100644 --- a/include/configs/p1_p2_rdb_pc.h +++ b/include/configs/p1_p2_rdb_pc.h @@ -270,7 +270,6 @@ #define CONFIG_TSEC_ENET /* tsec ethernet support */ #define CONFIG_ENV_OVERWRITE -#define CONFIG_CMD_SATA #define CONFIG_SATA_SIL #define CONFIG_SYS_SATA_MAX_DEVICE 2 #define CONFIG_LIBATA diff --git a/include/configs/p1_twr.h b/include/configs/p1_twr.h index fd644f2..dffb15a 100644 --- a/include/configs/p1_twr.h +++ b/include/configs/p1_twr.h @@ -50,7 +50,6 @@ #define CONFIG_TSEC_ENET /* tsec ethernet support */ #define CONFIG_ENV_OVERWRITE -#define CONFIG_CMD_SATA #define CONFIG_SATA_SIL3114 #define CONFIG_SYS_SATA_MAX_DEVICE 2 #define CONFIG_LIBATA diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index 3e09e88..9276cf9 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -162,7 +162,6 @@ #define CONFIG_SYS_SCSI_MAX_SCSI_ID 8 #define CONFIG_SYS_SCSI_MAX_LUN 4 -#define CONFIG_CMD_SATA #define CONFIG_SYS_SATA_MAX_DEVICE 2 #define CONFIG_SYSTEMACE diff --git a/include/configs/t4qds.h b/include/configs/t4qds.h index 260cdee..6d8c78f 100644 --- a/include/configs/t4qds.h +++ b/include/configs/t4qds.h @@ -223,7 +223,6 @@ #define CONFIG_SYS_SATA2_FLAGS FLAGS_DMA #define CONFIG_LBA48 -#define CONFIG_CMD_SATA #endif #ifdef CONFIG_FMAN_ENET diff --git a/include/configs/tbs2910.h b/include/configs/tbs2910.h index 84ca1c4..79f6b16 100644 --- a/include/configs/tbs2910.h +++ b/include/configs/tbs2910.h @@ -80,7 +80,6 @@ #endif /* SATA */ -#define CONFIG_CMD_SATA #ifdef CONFIG_CMD_SATA #define CONFIG_DWC_AHSATA #define CONFIG_SYS_SATA_MAX_DEVICE 1 diff --git a/include/configs/theadorable.h b/include/configs/theadorable.h index 27cae9d..94e207c 100644 --- a/include/configs/theadorable.h +++ b/include/configs/theadorable.h @@ -23,7 +23,6 @@ /* * Commands configuration */ -#define CONFIG_CMD_SATA /* * The debugging version enables USB support via defconfig. diff --git a/include/configs/udoo.h b/include/configs/udoo.h index d84aa16..aef4563 100644 --- a/include/configs/udoo.h +++ b/include/configs/udoo.h @@ -24,7 +24,6 @@ /* SATA Configs */ -#define CONFIG_CMD_SATA #ifdef CONFIG_CMD_SATA #define CONFIG_DWC_AHSATA #define CONFIG_SYS_SATA_MAX_DEVICE 1 diff --git a/include/configs/wandboard.h b/include/configs/wandboard.h index 2a6c6fb..afc5edf 100644 --- a/include/configs/wandboard.h +++ b/include/configs/wandboard.h @@ -24,7 +24,6 @@ /* SATA Configs */ -#define CONFIG_CMD_SATA #ifdef CONFIG_CMD_SATA #define CONFIG_DWC_AHSATA #define CONFIG_SYS_SATA_MAX_DEVICE 1 diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt index 50220e1..181408c 100644 --- a/scripts/config_whitelist.txt +++ b/scripts/config_whitelist.txt @@ -312,7 +312,6 @@ CONFIG_CMD_READ CONFIG_CMD_REGINFO CONFIG_CMD_REISER CONFIG_CMD_SANDBOX -CONFIG_CMD_SATA CONFIG_CMD_SAVES CONFIG_CMD_SCSI CONFIG_CMD_SDRAM -- cgit v0.10.2 From 10e40d54b38b9b1916c35fc5c4ed2eff4b4bf117 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 14 Jun 2017 21:28:25 -0600 Subject: Kconfig: Add CONFIG_SATA to enable SATA At present CONFIG_CMD_SATA enables the 'sata' command which also brings in SATA support. Some boards may wish to enable SATA without the command. Add a separate CONFIG to permit this. Signed-off-by: Simon Glass Reviewed-by: Bin Meng diff --git a/api/api_storage.c b/api/api_storage.c index 8bed2f3..6fc6f44 100644 --- a/api/api_storage.c +++ b/api/api_storage.c @@ -63,7 +63,7 @@ void dev_stor_init(void) specs[ENUM_MMC].type = DEV_TYP_STOR | DT_STOR_MMC; specs[ENUM_MMC].name = "mmc"; #endif -#if defined(CONFIG_CMD_SATA) +#if defined(CONFIG_SATA) specs[ENUM_SATA].max_dev = CONFIG_SYS_SATA_MAX_DEVICE; specs[ENUM_SATA].enum_started = 0; specs[ENUM_SATA].enum_ended = 0; diff --git a/arch/arm/cpu/armv7/mx6/clock.c b/arch/arm/cpu/armv7/mx6/clock.c index 84bc213..1f2739e 100644 --- a/arch/arm/cpu/armv7/mx6/clock.c +++ b/arch/arm/cpu/armv7/mx6/clock.c @@ -1042,7 +1042,7 @@ u32 imx_get_fecclk(void) return mxc_get_clock(MXC_IPG_CLK); } -#if defined(CONFIG_CMD_SATA) || defined(CONFIG_PCIE_IMX) +#if defined(CONFIG_SATA) || defined(CONFIG_PCIE_IMX) static int enable_enet_pll(uint32_t en) { struct mxc_ccm_reg *const imx_ccm @@ -1069,7 +1069,7 @@ static int enable_enet_pll(uint32_t en) } #endif -#ifdef CONFIG_CMD_SATA +#ifdef CONFIG_SATA static void ungate_sata_clock(void) { struct mxc_ccm_reg *const imx_ccm = @@ -1143,7 +1143,7 @@ int enable_pcie_clock(void) clrbits_le32(&ccm_regs->cbcmr, MXC_CCM_CBCMR_PCIE_AXI_CLK_SEL); /* Party time! Ungate the clock to the PCIe. */ -#ifdef CONFIG_CMD_SATA +#ifdef CONFIG_SATA ungate_sata_clock(); #endif ungate_pcie_clock(); diff --git a/arch/arm/imx-common/Makefile b/arch/arm/imx-common/Makefile index b7cb434..fc69172 100644 --- a/arch/arm/imx-common/Makefile +++ b/arch/arm/imx-common/Makefile @@ -25,7 +25,7 @@ obj-$(CONFIG_SYSCOUNTER_TIMER) += syscounter.o endif ifeq ($(SOC),$(filter $(SOC),mx6 mx7)) obj-y += cache.o init.o -obj-$(CONFIG_CMD_SATA) += sata.o +obj-$(CONFIG_SATA) += sata.o obj-$(CONFIG_IMX_VIDEO_SKIP) += video.o obj-$(CONFIG_IMX_RDC) += rdc-sema.o obj-$(CONFIG_IMX_BOOTAUX) += imx_bootaux.o diff --git a/arch/arm/imx-common/cpu.c b/arch/arm/imx-common/cpu.c index 74bdd24..9e83b42 100644 --- a/arch/arm/imx-common/cpu.c +++ b/arch/arm/imx-common/cpu.c @@ -278,7 +278,7 @@ void arch_preboot_os(void) #if defined(CONFIG_PCIE_IMX) imx_pcie_remove(); #endif -#if defined(CONFIG_CMD_SATA) +#if defined(CONFIG_SATA) sata_stop(); #if defined(CONFIG_MX6) disable_sata_clock(); diff --git a/arch/powerpc/cpu/mpc85xx/cpu_init.c b/arch/powerpc/cpu/mpc85xx/cpu_init.c index f5bf67c..388fe2b 100644 --- a/arch/powerpc/cpu/mpc85xx/cpu_init.c +++ b/arch/powerpc/cpu/mpc85xx/cpu_init.c @@ -1024,7 +1024,7 @@ void arch_preboot_os(void) mtmsr(msr); } -#if defined(CONFIG_CMD_SATA) && defined(CONFIG_FSL_SATA) +#if defined(CONFIG_SATA) && defined(CONFIG_FSL_SATA) int sata_initialize(void) { if (is_serdes_configured(SATA1) || is_serdes_configured(SATA2)) diff --git a/board/advantech/dms-ba16/dms-ba16.c b/board/advantech/dms-ba16/dms-ba16.c index 91e96ab..2dab906 100644 --- a/board/advantech/dms-ba16/dms-ba16.c +++ b/board/advantech/dms-ba16/dms-ba16.c @@ -609,7 +609,7 @@ int board_late_init(void) pwm_enable(0); #endif -#ifdef CONFIG_CMD_SATA +#ifdef CONFIG_SATA setup_ba16_sata(); #endif diff --git a/board/bachmann/ot1200/ot1200.c b/board/bachmann/ot1200/ot1200.c index c0a8b64..74f652e 100644 --- a/board/bachmann/ot1200/ot1200.c +++ b/board/bachmann/ot1200/ot1200.c @@ -338,7 +338,7 @@ int board_init(void) leds_on(); -#ifdef CONFIG_CMD_SATA +#ifdef CONFIG_SATA setup_sata(); #endif diff --git a/board/boundary/nitrogen6x/nitrogen6x.c b/board/boundary/nitrogen6x/nitrogen6x.c index ab8b2be..1145af5 100644 --- a/board/boundary/nitrogen6x/nitrogen6x.c +++ b/board/boundary/nitrogen6x/nitrogen6x.c @@ -903,7 +903,7 @@ int board_init(void) setup_i2c(1, CONFIG_SYS_I2C_SPEED, 0x7f, &i2c_pad_info1); setup_i2c(2, CONFIG_SYS_I2C_SPEED, 0x7f, &i2c_pad_info2); -#ifdef CONFIG_CMD_SATA +#ifdef CONFIG_SATA setup_sata(); #endif diff --git a/board/congatec/cgtqmx6eval/cgtqmx6eval.c b/board/congatec/cgtqmx6eval/cgtqmx6eval.c index 24956a8..fe7db91 100644 --- a/board/congatec/cgtqmx6eval/cgtqmx6eval.c +++ b/board/congatec/cgtqmx6eval/cgtqmx6eval.c @@ -702,7 +702,7 @@ int board_init(void) else setup_i2c(1, CONFIG_SYS_I2C_SPEED, 0x7f, &mx6dl_i2c_pad_info1); -#ifdef CONFIG_CMD_SATA +#ifdef CONFIG_SATA setup_sata(); #endif diff --git a/board/gateworks/gw_ventana/gw_ventana.c b/board/gateworks/gw_ventana/gw_ventana.c index 6b950ee..40ee1b6 100644 --- a/board/gateworks/gw_ventana/gw_ventana.c +++ b/board/gateworks/gw_ventana/gw_ventana.c @@ -633,7 +633,7 @@ int board_init(void) #endif setup_ventana_i2c(); -#ifdef CONFIG_CMD_SATA +#ifdef CONFIG_SATA setup_sata(); #endif /* read Gateworks EEPROM into global struct (used later) */ diff --git a/board/kosagi/novena/novena.c b/board/kosagi/novena/novena.c index f6972c2..17c2b13 100644 --- a/board/kosagi/novena/novena.c +++ b/board/kosagi/novena/novena.c @@ -167,7 +167,7 @@ int board_init(void) /* address of boot parameters */ gd->bd->bi_boot_params = PHYS_SDRAM + 0x100; -#ifdef CONFIG_CMD_SATA +#ifdef CONFIG_SATA setup_sata(); #endif diff --git a/board/toradex/apalis_imx6/apalis_imx6.c b/board/toradex/apalis_imx6/apalis_imx6.c index 7c49ddf..166b93f 100644 --- a/board/toradex/apalis_imx6/apalis_imx6.c +++ b/board/toradex/apalis_imx6/apalis_imx6.c @@ -784,7 +784,7 @@ int board_init(void) (void) pmic_init(); #endif -#ifdef CONFIG_CMD_SATA +#ifdef CONFIG_SATA setup_sata(); #endif diff --git a/board/toradex/colibri_imx6/colibri_imx6.c b/board/toradex/colibri_imx6/colibri_imx6.c index 69467ca..87e2447 100644 --- a/board/toradex/colibri_imx6/colibri_imx6.c +++ b/board/toradex/colibri_imx6/colibri_imx6.c @@ -657,7 +657,7 @@ int board_init(void) (void) pmic_init(); #endif -#ifdef CONFIG_CMD_SATA +#ifdef CONFIG_SATA setup_sata(); #endif diff --git a/board/udoo/udoo.c b/board/udoo/udoo.c index eb7ab65..d2cbbaa 100644 --- a/board/udoo/udoo.c +++ b/board/udoo/udoo.c @@ -244,7 +244,7 @@ int board_init(void) /* address of boot parameters */ gd->bd->bi_boot_params = PHYS_SDRAM + 0x100; -#ifdef CONFIG_CMD_SATA +#ifdef CONFIG_SATA if (is_cpu_type(MXC_CPU_MX6Q)) setup_sata(); #endif diff --git a/board/wandboard/wandboard.c b/board/wandboard/wandboard.c index 2c9dc8b..438bc0e 100644 --- a/board/wandboard/wandboard.c +++ b/board/wandboard/wandboard.c @@ -379,7 +379,7 @@ int board_early_init_f(void) #if defined(CONFIG_VIDEO_IPUV3) setup_display(); #endif -#ifdef CONFIG_CMD_SATA +#ifdef CONFIG_SATA /* Only mx6q wandboard has SATA */ if (is_cpu_type(MXC_CPU_MX6Q)) setup_sata(); diff --git a/cmd/Kconfig b/cmd/Kconfig index 90d9337..c80ac36 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -736,6 +736,7 @@ config CMD_FDC config CMD_SATA bool "sata - Access SATA subsystem" + select SATA help SATA (Serial Advanced Technology Attachment) is a serial bus standard for connecting to hard drives and other storage devices. diff --git a/common/Makefile b/common/Makefile index 8540fbc..fdf5c31 100644 --- a/common/Makefile +++ b/common/Makefile @@ -79,7 +79,7 @@ obj-$(CONFIG_LCD_ROTATION) += lcd_console_rotation.o obj-$(CONFIG_LCD_DT_SIMPLEFB) += lcd_simplefb.o obj-$(CONFIG_LYNXKDI) += lynxkdi.o obj-$(CONFIG_MENU) += menu.o -obj-$(CONFIG_CMD_SATA) += sata.o +obj-$(CONFIG_SATA) += sata.o obj-$(CONFIG_SCSI) += scsi.o obj-$(CONFIG_UPDATE_TFTP) += update.o obj-$(CONFIG_DFU_TFTP) += update.o diff --git a/common/splash_source.c b/common/splash_source.c index d1647c8..ee055dd 100644 --- a/common/splash_source.c +++ b/common/splash_source.c @@ -162,7 +162,7 @@ static inline int splash_init_usb(void) } #endif -#ifdef CONFIG_CMD_SATA +#ifdef CONFIG_SATA static int splash_init_sata(void) { return sata_initialize(); diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 4c2aaa0..ed7fa88 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -19,6 +19,19 @@ config AHCI operations at present. The block device interface has not been converted to driver model. +config SATA + bool "Support SATA controllers" + help + This enables support for SATA (Serial Advanced Technology + Attachment), a serial bus standard for connecting to hard drives and + other storage devices. + + SATA replaces PATA (originally just ATA), which stands for Parallel AT + Attachment, where AT refers to an IBM AT (Advanced Technology) + computer released in 1984. + + See also CMD_SATA which provides command-line support. + config SCSI bool "Support SCSI controllers" help diff --git a/fs/fat/fat.c b/fs/fat/fat.c index a71bad1..9ad18f9 100644 --- a/fs/fat/fat.c +++ b/fs/fat/fat.c @@ -1251,7 +1251,7 @@ int file_fat_detectfs(void) } #if defined(CONFIG_IDE) || \ - defined(CONFIG_CMD_SATA) || \ + defined(CONFIG_SATA) || \ defined(CONFIG_SCSI) || \ defined(CONFIG_CMD_USB) || \ defined(CONFIG_MMC) diff --git a/include/config_distro_bootcmd.h b/include/config_distro_bootcmd.h index 4b2c493..d8dab8e 100644 --- a/include/config_distro_bootcmd.h +++ b/include/config_distro_bootcmd.h @@ -149,16 +149,16 @@ #define SCAN_DEV_FOR_EFI #endif -#ifdef CONFIG_CMD_SATA +#ifdef CONFIG_SATA #define BOOTENV_SHARED_SATA BOOTENV_SHARED_BLKDEV(sata) #define BOOTENV_DEV_SATA BOOTENV_DEV_BLKDEV #define BOOTENV_DEV_NAME_SATA BOOTENV_DEV_NAME_BLKDEV #else #define BOOTENV_SHARED_SATA #define BOOTENV_DEV_SATA \ - BOOT_TARGET_DEVICES_references_SATA_without_CONFIG_CMD_SATA + BOOT_TARGET_DEVICES_references_SATA_without_CONFIG_SATA #define BOOTENV_DEV_NAME_SATA \ - BOOT_TARGET_DEVICES_references_SATA_without_CONFIG_CMD_SATA + BOOT_TARGET_DEVICES_references_SATA_without_CONFIG_SATA #endif #ifdef CONFIG_SCSI diff --git a/include/config_fallbacks.h b/include/config_fallbacks.h index 2656c75..d1411f0 100644 --- a/include/config_fallbacks.h +++ b/include/config_fallbacks.h @@ -48,7 +48,7 @@ /* Rather than repeat this expression each time, add a define for it */ #if defined(CONFIG_IDE) || \ - defined(CONFIG_CMD_SATA) || \ + defined(CONFIG_SATA) || \ defined(CONFIG_SCSI) || \ defined(CONFIG_CMD_USB) || \ defined(CONFIG_CMD_PART) || \ -- cgit v0.10.2 From f2105c61821b67bc1d572304d901518e88ee007b Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 14 Jun 2017 21:28:26 -0600 Subject: sata: Move drivers into new drivers/ata directory At present we have the SATA and PATA drivers mixed up in the drivers/block directory. It is better to split them out into their own place. Use drivers/ata which is what Linux does. Signed-off-by: Simon Glass Reviewed-by: Bin Meng diff --git a/arch/powerpc/cpu/mpc85xx/cpu_init.c b/arch/powerpc/cpu/mpc85xx/cpu_init.c index 388fe2b..a3076d8 100644 --- a/arch/powerpc/cpu/mpc85xx/cpu_init.c +++ b/arch/powerpc/cpu/mpc85xx/cpu_init.c @@ -48,7 +48,7 @@ #ifndef CONFIG_ARCH_QEMU_E500 #include #endif -#include "../../../../drivers/block/fsl_sata.h" +#include "../../../../drivers/ata/fsl_sata.h" #ifdef CONFIG_U_QE #include #endif diff --git a/common/Makefile b/common/Makefile index fdf5c31..f04ddc8 100644 --- a/common/Makefile +++ b/common/Makefile @@ -79,7 +79,6 @@ obj-$(CONFIG_LCD_ROTATION) += lcd_console_rotation.o obj-$(CONFIG_LCD_DT_SIMPLEFB) += lcd_simplefb.o obj-$(CONFIG_LYNXKDI) += lynxkdi.o obj-$(CONFIG_MENU) += menu.o -obj-$(CONFIG_SATA) += sata.o obj-$(CONFIG_SCSI) += scsi.o obj-$(CONFIG_UPDATE_TFTP) += update.o obj-$(CONFIG_DFU_TFTP) += update.o diff --git a/common/sata.c b/common/sata.c deleted file mode 100644 index 42ff5c7..0000000 --- a/common/sata.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2000-2005, DENX Software Engineering - * Wolfgang Denk - * Copyright (C) Procsys. All rights reserved. - * Mushtaq Khan - * - * Copyright (C) 2008 Freescale Semiconductor, Inc. - * Dave Liu - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include - -struct blk_desc sata_dev_desc[CONFIG_SYS_SATA_MAX_DEVICE]; - -#ifdef CONFIG_PARTITIONS -struct blk_desc *sata_get_dev(int dev) -{ - return (dev < CONFIG_SYS_SATA_MAX_DEVICE) ? &sata_dev_desc[dev] : NULL; -} -#endif - -#ifdef CONFIG_BLK -static unsigned long sata_bread(struct udevice *dev, lbaint_t start, - lbaint_t blkcnt, void *dst) -{ - return -ENOSYS; -} - -static unsigned long sata_bwrite(struct udevice *dev, lbaint_t start, - lbaint_t blkcnt, const void *buffer) -{ - return -ENOSYS; -} -#else -static unsigned long sata_bread(struct blk_desc *block_dev, lbaint_t start, - lbaint_t blkcnt, void *dst) -{ - return sata_read(block_dev->devnum, start, blkcnt, dst); -} - -static unsigned long sata_bwrite(struct blk_desc *block_dev, lbaint_t start, - lbaint_t blkcnt, const void *buffer) -{ - return sata_write(block_dev->devnum, start, blkcnt, buffer); -} -#endif - -int __sata_initialize(void) -{ - int rc, ret = -1; - int i; - - for (i = 0; i < CONFIG_SYS_SATA_MAX_DEVICE; i++) { - memset(&sata_dev_desc[i], 0, sizeof(struct blk_desc)); - sata_dev_desc[i].if_type = IF_TYPE_SATA; - sata_dev_desc[i].devnum = i; - sata_dev_desc[i].part_type = PART_TYPE_UNKNOWN; - sata_dev_desc[i].type = DEV_TYPE_HARDDISK; - sata_dev_desc[i].lba = 0; - sata_dev_desc[i].blksz = 512; - sata_dev_desc[i].log2blksz = LOG2(sata_dev_desc[i].blksz); -#ifndef CONFIG_BLK - sata_dev_desc[i].block_read = sata_bread; - sata_dev_desc[i].block_write = sata_bwrite; -#endif - rc = init_sata(i); - if (!rc) { - rc = scan_sata(i); - if (!rc && sata_dev_desc[i].lba > 0 && - sata_dev_desc[i].blksz > 0) { - part_init(&sata_dev_desc[i]); - ret = i; - } - } - } - - return ret; -} -int sata_initialize(void) __attribute__((weak, alias("__sata_initialize"))); - -__weak int __sata_stop(void) -{ - int i, err = 0; - - for (i = 0; i < CONFIG_SYS_SATA_MAX_DEVICE; i++) - err |= reset_sata(i); - - if (err) - printf("Could not reset some SATA devices\n"); - - return err; -} -int sata_stop(void) __attribute__((weak, alias("__sata_stop"))); - -#ifdef CONFIG_BLK -static const struct blk_ops sata_blk_ops = { - .read = sata_bread, - .write = sata_bwrite, -}; - -U_BOOT_DRIVER(sata_blk) = { - .name = "sata_blk", - .id = UCLASS_BLK, - .ops = &sata_blk_ops, -}; -#else -U_BOOT_LEGACY_BLK(sata) = { - .if_typename = "sata", - .if_type = IF_TYPE_SATA, - .max_devs = CONFIG_SYS_SATA_MAX_DEVICE, - .desc = sata_dev_desc, -}; -#endif diff --git a/drivers/Kconfig b/drivers/Kconfig index a736386..63e4034 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -6,6 +6,8 @@ source "drivers/core/Kconfig" source "drivers/adc/Kconfig" +source "drivers/ata/Kconfig" + source "drivers/block/Kconfig" source "drivers/clk/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 058bccb..9bbcc7b 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -45,7 +45,7 @@ obj-$(CONFIG_SPL_DFU_SUPPORT) += dfu/ obj-$(CONFIG_SPL_WATCHDOG_SUPPORT) += watchdog/ obj-$(CONFIG_SPL_USB_HOST_SUPPORT) += usb/host/ obj-$(CONFIG_OMAP_USB_PHY) += usb/phy/ -obj-$(CONFIG_SPL_SATA_SUPPORT) += block/ +obj-$(CONFIG_SPL_SATA_SUPPORT) += ata/ obj-$(CONFIG_SPL_USB_HOST_SUPPORT) += block/ obj-$(CONFIG_SPL_MMC_SUPPORT) += block/ endif @@ -66,6 +66,7 @@ endif ifeq ($(CONFIG_SPL_BUILD)$(CONFIG_TPL_BUILD),) obj-y += adc/ +obj-y += ata/ obj-$(CONFIG_DM_DEMO) += demo/ obj-$(CONFIG_BIOSEMU) += bios_emulator/ obj-y += block/ diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig new file mode 100644 index 0000000..6427f1b --- /dev/null +++ b/drivers/ata/Kconfig @@ -0,0 +1,62 @@ +config AHCI + bool "Support SATA controllers with driver model" + depends on DM + help + This enables a uclass for disk controllers in U-Boot. Various driver + types can use this, such as AHCI/SATA. It does not provide any standard + operations at present. The block device interface has not been converted + to driver model. + +config SATA + bool "Support SATA controllers" + help + This enables support for SATA (Serial Advanced Technology + Attachment), a serial bus standard for connecting to hard drives and + other storage devices. + + SATA replaces PATA (originally just ATA), which stands for Parallel AT + Attachment, where AT refers to an IBM AT (Advanced Technology) + computer released in 1984. + + See also CMD_SATA which provides command-line support. + +config SCSI + bool "Support SCSI controllers" + help + This enables support for SCSI (Small Computer System Interface), + a parallel interface widely used with storage peripherals such as + hard drives and optical drives. The SCSI standards define physical + interfaces as well as protocols for controlling devices and + tranferring data. + +config DM_SCSI + bool "Support SCSI controllers with driver model" + depends on BLK + help + This option enables the SCSI (Small Computer System Interface) uclass + which supports SCSI and SATA HDDs. For every device configuration + (IDs/LUNs) a block device is created with RAW read/write and + filesystem support. + +menu "SATA/SCSI device support" + +config SATA_CEVA + bool "Ceva Sata controller" + depends on AHCI + depends on DM_SCSI + help + This option enables Ceva Sata controller hard IP available on Xilinx + ZynqMP. Support up to 2 external devices. Complient with SATA 3.1 and + AHCI 1.3 specifications with hot-plug detect feature. + + +config DWC_AHCI + bool "Enable Synopsys DWC AHCI driver support" + select SCSI_AHCI + select PHY + depends on DM_SCSI + help + Enable this driver to support Sata devices through + Synopsys DWC AHCI module. + +endmenu diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile new file mode 100644 index 0000000..c48184c --- /dev/null +++ b/drivers/ata/Makefile @@ -0,0 +1,22 @@ +# +# (C) Copyright 2000-2007 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-$(CONFIG_DWC_AHCI) += dwc_ahci.o +obj-$(CONFIG_AHCI) += ahci-uclass.o +obj-$(CONFIG_SCSI_AHCI) += ahci.o +obj-$(CONFIG_DWC_AHSATA) += dwc_ahsata.o +obj-$(CONFIG_FSL_SATA) += fsl_sata.o +obj-$(CONFIG_LIBATA) += libata.o +obj-$(CONFIG_MVSATA_IDE) += mvsata_ide.o +obj-$(CONFIG_MX51_PATA) += mxc_ata.o +obj-$(CONFIG_SATA) += sata.o +obj-$(CONFIG_SATA_CEVA) += sata_ceva.o +obj-$(CONFIG_SATA_DWC) += sata_dwc.o +obj-$(CONFIG_SATA_MV) += sata_mv.o +obj-$(CONFIG_SATA_SIL3114) += sata_sil3114.o +obj-$(CONFIG_SATA_SIL) += sata_sil.o +obj-$(CONFIG_SANDBOX) += sata_sandbox.o diff --git a/drivers/ata/ahci-uclass.c b/drivers/ata/ahci-uclass.c new file mode 100644 index 0000000..7b8c326 --- /dev/null +++ b/drivers/ata/ahci-uclass.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2015 Google, Inc + * Written by Simon Glass + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include + +UCLASS_DRIVER(ahci) = { + .id = UCLASS_AHCI, + .name = "ahci", +}; diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c new file mode 100644 index 0000000..f474471 --- /dev/null +++ b/drivers/ata/ahci.c @@ -0,0 +1,1094 @@ +/* + * Copyright (C) Freescale Semiconductor, Inc. 2006. + * Author: Jason Jin + * Zhang Wei + * + * SPDX-License-Identifier: GPL-2.0+ + * + * with the reference on libata and ahci drvier in kernel + */ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int ata_io_flush(u8 port); + +struct ahci_probe_ent *probe_ent = NULL; +u16 *ataid[AHCI_MAX_PORTS]; + +#define writel_with_flush(a,b) do { writel(a,b); readl(b); } while (0) + +/* + * Some controllers limit number of blocks they can read/write at once. + * Contemporary SSD devices work much faster if the read/write size is aligned + * to a power of 2. Let's set default to 128 and allowing to be overwritten if + * needed. + */ +#ifndef MAX_SATA_BLOCKS_READ_WRITE +#define MAX_SATA_BLOCKS_READ_WRITE 0x80 +#endif + +/* Maximum timeouts for each event */ +#define WAIT_MS_SPINUP 20000 +#define WAIT_MS_DATAIO 10000 +#define WAIT_MS_FLUSH 5000 +#define WAIT_MS_LINKUP 200 + +__weak void __iomem *ahci_port_base(void __iomem *base, u32 port) +{ + return base + 0x100 + (port * 0x80); +} + + +static void ahci_setup_port(struct ahci_ioports *port, void __iomem *base, + unsigned int port_idx) +{ + base = ahci_port_base(base, port_idx); + + port->cmd_addr = base; + port->scr_addr = base + PORT_SCR; +} + + +#define msleep(a) udelay(a * 1000) + +static void ahci_dcache_flush_range(unsigned long begin, unsigned long len) +{ + const unsigned long start = begin; + const unsigned long end = start + len; + + debug("%s: flush dcache: [%#lx, %#lx)\n", __func__, start, end); + flush_dcache_range(start, end); +} + +/* + * SATA controller DMAs to physical RAM. Ensure data from the + * controller is invalidated from dcache; next access comes from + * physical RAM. + */ +static void ahci_dcache_invalidate_range(unsigned long begin, unsigned long len) +{ + const unsigned long start = begin; + const unsigned long end = start + len; + + debug("%s: invalidate dcache: [%#lx, %#lx)\n", __func__, start, end); + invalidate_dcache_range(start, end); +} + +/* + * Ensure data for SATA controller is flushed out of dcache and + * written to physical memory. + */ +static void ahci_dcache_flush_sata_cmd(struct ahci_ioports *pp) +{ + ahci_dcache_flush_range((unsigned long)pp->cmd_slot, + AHCI_PORT_PRIV_DMA_SZ); +} + +static int waiting_for_cmd_completed(void __iomem *offset, + int timeout_msec, + u32 sign) +{ + int i; + u32 status; + + for (i = 0; ((status = readl(offset)) & sign) && i < timeout_msec; i++) + msleep(1); + + return (i < timeout_msec) ? 0 : -1; +} + +int __weak ahci_link_up(struct ahci_probe_ent *probe_ent, u8 port) +{ + u32 tmp; + int j = 0; + void __iomem *port_mmio = probe_ent->port[port].port_mmio; + + /* + * Bring up SATA link. + * SATA link bringup time is usually less than 1 ms; only very + * rarely has it taken between 1-2 ms. Never seen it above 2 ms. + */ + while (j < WAIT_MS_LINKUP) { + tmp = readl(port_mmio + PORT_SCR_STAT); + tmp &= PORT_SCR_STAT_DET_MASK; + if (tmp == PORT_SCR_STAT_DET_PHYRDY) + return 0; + udelay(1000); + j++; + } + return 1; +} + +#ifdef CONFIG_SUNXI_AHCI +/* The sunxi AHCI controller requires this undocumented setup */ +static void sunxi_dma_init(void __iomem *port_mmio) +{ + clrsetbits_le32(port_mmio + PORT_P0DMACR, 0x0000ff00, 0x00004400); +} +#endif + +int ahci_reset(void __iomem *base) +{ + int i = 1000; + u32 __iomem *host_ctl_reg = base + HOST_CTL; + u32 tmp = readl(host_ctl_reg); /* global controller reset */ + + if ((tmp & HOST_RESET) == 0) + writel_with_flush(tmp | HOST_RESET, host_ctl_reg); + + /* + * reset must complete within 1 second, or + * the hardware should be considered fried. + */ + do { + udelay(1000); + tmp = readl(host_ctl_reg); + i--; + } while ((i > 0) && (tmp & HOST_RESET)); + + if (i == 0) { + printf("controller reset failed (0x%x)\n", tmp); + return -1; + } + + return 0; +} + +static int ahci_host_init(struct ahci_probe_ent *probe_ent) +{ +#if !defined(CONFIG_SCSI_AHCI_PLAT) && !defined(CONFIG_DM_SCSI) +# ifdef CONFIG_DM_PCI + struct udevice *dev = probe_ent->dev; + struct pci_child_platdata *pplat = dev_get_parent_platdata(dev); +# else + pci_dev_t pdev = probe_ent->dev; + unsigned short vendor; +# endif + u16 tmp16; +#endif + void __iomem *mmio = probe_ent->mmio_base; + u32 tmp, cap_save, cmd; + int i, j, ret; + void __iomem *port_mmio; + u32 port_map; + + debug("ahci_host_init: start\n"); + + cap_save = readl(mmio + HOST_CAP); + cap_save &= ((1 << 28) | (1 << 17)); + cap_save |= (1 << 27); /* Staggered Spin-up. Not needed. */ + + ret = ahci_reset(probe_ent->mmio_base); + if (ret) + return ret; + + writel_with_flush(HOST_AHCI_EN, mmio + HOST_CTL); + writel(cap_save, mmio + HOST_CAP); + writel_with_flush(0xf, mmio + HOST_PORTS_IMPL); + +#if !defined(CONFIG_SCSI_AHCI_PLAT) && !defined(CONFIG_DM_SCSI) +# ifdef CONFIG_DM_PCI + if (pplat->vendor == PCI_VENDOR_ID_INTEL) { + u16 tmp16; + + dm_pci_read_config16(dev, 0x92, &tmp16); + dm_pci_write_config16(dev, 0x92, tmp16 | 0xf); + } +# else + pci_read_config_word(pdev, PCI_VENDOR_ID, &vendor); + + if (vendor == PCI_VENDOR_ID_INTEL) { + u16 tmp16; + pci_read_config_word(pdev, 0x92, &tmp16); + tmp16 |= 0xf; + pci_write_config_word(pdev, 0x92, tmp16); + } +# endif +#endif + probe_ent->cap = readl(mmio + HOST_CAP); + probe_ent->port_map = readl(mmio + HOST_PORTS_IMPL); + port_map = probe_ent->port_map; + probe_ent->n_ports = (probe_ent->cap & 0x1f) + 1; + + debug("cap 0x%x port_map 0x%x n_ports %d\n", + probe_ent->cap, probe_ent->port_map, probe_ent->n_ports); + + if (probe_ent->n_ports > CONFIG_SYS_SCSI_MAX_SCSI_ID) + probe_ent->n_ports = CONFIG_SYS_SCSI_MAX_SCSI_ID; + + for (i = 0; i < probe_ent->n_ports; i++) { + if (!(port_map & (1 << i))) + continue; + probe_ent->port[i].port_mmio = ahci_port_base(mmio, i); + port_mmio = (u8 *) probe_ent->port[i].port_mmio; + ahci_setup_port(&probe_ent->port[i], mmio, i); + + /* make sure port is not active */ + tmp = readl(port_mmio + PORT_CMD); + if (tmp & (PORT_CMD_LIST_ON | PORT_CMD_FIS_ON | + PORT_CMD_FIS_RX | PORT_CMD_START)) { + debug("Port %d is active. Deactivating.\n", i); + tmp &= ~(PORT_CMD_LIST_ON | PORT_CMD_FIS_ON | + PORT_CMD_FIS_RX | PORT_CMD_START); + writel_with_flush(tmp, port_mmio + PORT_CMD); + + /* spec says 500 msecs for each bit, so + * this is slightly incorrect. + */ + msleep(500); + } + +#ifdef CONFIG_SUNXI_AHCI + sunxi_dma_init(port_mmio); +#endif + + /* Add the spinup command to whatever mode bits may + * already be on in the command register. + */ + cmd = readl(port_mmio + PORT_CMD); + cmd |= PORT_CMD_SPIN_UP; + writel_with_flush(cmd, port_mmio + PORT_CMD); + + /* Bring up SATA link. */ + ret = ahci_link_up(probe_ent, i); + if (ret) { + printf("SATA link %d timeout.\n", i); + continue; + } else { + debug("SATA link ok.\n"); + } + + /* Clear error status */ + tmp = readl(port_mmio + PORT_SCR_ERR); + if (tmp) + writel(tmp, port_mmio + PORT_SCR_ERR); + + debug("Spinning up device on SATA port %d... ", i); + + j = 0; + while (j < WAIT_MS_SPINUP) { + tmp = readl(port_mmio + PORT_TFDATA); + if (!(tmp & (ATA_BUSY | ATA_DRQ))) + break; + udelay(1000); + tmp = readl(port_mmio + PORT_SCR_STAT); + tmp &= PORT_SCR_STAT_DET_MASK; + if (tmp == PORT_SCR_STAT_DET_PHYRDY) + break; + j++; + } + + tmp = readl(port_mmio + PORT_SCR_STAT) & PORT_SCR_STAT_DET_MASK; + if (tmp == PORT_SCR_STAT_DET_COMINIT) { + debug("SATA link %d down (COMINIT received), retrying...\n", i); + i--; + continue; + } + + printf("Target spinup took %d ms.\n", j); + if (j == WAIT_MS_SPINUP) + debug("timeout.\n"); + else + debug("ok.\n"); + + tmp = readl(port_mmio + PORT_SCR_ERR); + debug("PORT_SCR_ERR 0x%x\n", tmp); + writel(tmp, port_mmio + PORT_SCR_ERR); + + /* ack any pending irq events for this port */ + tmp = readl(port_mmio + PORT_IRQ_STAT); + debug("PORT_IRQ_STAT 0x%x\n", tmp); + if (tmp) + writel(tmp, port_mmio + PORT_IRQ_STAT); + + writel(1 << i, mmio + HOST_IRQ_STAT); + + /* register linkup ports */ + tmp = readl(port_mmio + PORT_SCR_STAT); + debug("SATA port %d status: 0x%x\n", i, tmp); + if ((tmp & PORT_SCR_STAT_DET_MASK) == PORT_SCR_STAT_DET_PHYRDY) + probe_ent->link_port_map |= (0x01 << i); + } + + tmp = readl(mmio + HOST_CTL); + debug("HOST_CTL 0x%x\n", tmp); + writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL); + tmp = readl(mmio + HOST_CTL); + debug("HOST_CTL 0x%x\n", tmp); +#if !defined(CONFIG_DM_SCSI) +#ifndef CONFIG_SCSI_AHCI_PLAT +# ifdef CONFIG_DM_PCI + dm_pci_read_config16(dev, PCI_COMMAND, &tmp16); + tmp |= PCI_COMMAND_MASTER; + dm_pci_write_config16(dev, PCI_COMMAND, tmp16); +# else + pci_read_config_word(pdev, PCI_COMMAND, &tmp16); + tmp |= PCI_COMMAND_MASTER; + pci_write_config_word(pdev, PCI_COMMAND, tmp16); +# endif +#endif +#endif + return 0; +} + + +static void ahci_print_info(struct ahci_probe_ent *probe_ent) +{ +#if !defined(CONFIG_SCSI_AHCI_PLAT) && !defined(CONFIG_DM_SCSI) +# if defined(CONFIG_DM_PCI) + struct udevice *dev = probe_ent->dev; +# else + pci_dev_t pdev = probe_ent->dev; +# endif + u16 cc; +#endif + void __iomem *mmio = probe_ent->mmio_base; + u32 vers, cap, cap2, impl, speed; + const char *speed_s; + const char *scc_s; + + vers = readl(mmio + HOST_VERSION); + cap = probe_ent->cap; + cap2 = readl(mmio + HOST_CAP2); + impl = probe_ent->port_map; + + speed = (cap >> 20) & 0xf; + if (speed == 1) + speed_s = "1.5"; + else if (speed == 2) + speed_s = "3"; + else if (speed == 3) + speed_s = "6"; + else + speed_s = "?"; + +#if defined(CONFIG_SCSI_AHCI_PLAT) || defined(CONFIG_DM_SCSI) + scc_s = "SATA"; +#else +# ifdef CONFIG_DM_PCI + dm_pci_read_config16(dev, 0x0a, &cc); +# else + pci_read_config_word(pdev, 0x0a, &cc); +# endif + if (cc == 0x0101) + scc_s = "IDE"; + else if (cc == 0x0106) + scc_s = "SATA"; + else if (cc == 0x0104) + scc_s = "RAID"; + else + scc_s = "unknown"; +#endif + printf("AHCI %02x%02x.%02x%02x " + "%u slots %u ports %s Gbps 0x%x impl %s mode\n", + (vers >> 24) & 0xff, + (vers >> 16) & 0xff, + (vers >> 8) & 0xff, + vers & 0xff, + ((cap >> 8) & 0x1f) + 1, (cap & 0x1f) + 1, speed_s, impl, scc_s); + + printf("flags: " + "%s%s%s%s%s%s%s" + "%s%s%s%s%s%s%s" + "%s%s%s%s%s%s\n", + cap & (1 << 31) ? "64bit " : "", + cap & (1 << 30) ? "ncq " : "", + cap & (1 << 28) ? "ilck " : "", + cap & (1 << 27) ? "stag " : "", + cap & (1 << 26) ? "pm " : "", + cap & (1 << 25) ? "led " : "", + cap & (1 << 24) ? "clo " : "", + cap & (1 << 19) ? "nz " : "", + cap & (1 << 18) ? "only " : "", + cap & (1 << 17) ? "pmp " : "", + cap & (1 << 16) ? "fbss " : "", + cap & (1 << 15) ? "pio " : "", + cap & (1 << 14) ? "slum " : "", + cap & (1 << 13) ? "part " : "", + cap & (1 << 7) ? "ccc " : "", + cap & (1 << 6) ? "ems " : "", + cap & (1 << 5) ? "sxs " : "", + cap2 & (1 << 2) ? "apst " : "", + cap2 & (1 << 1) ? "nvmp " : "", + cap2 & (1 << 0) ? "boh " : ""); +} + +#ifndef CONFIG_SCSI_AHCI_PLAT +# if defined(CONFIG_DM_PCI) || defined(CONFIG_DM_SCSI) +static int ahci_init_one(struct udevice *dev) +# else +static int ahci_init_one(pci_dev_t dev) +# endif +{ +#if !defined(CONFIG_DM_SCSI) + u16 vendor; +#endif + int rc; + + probe_ent = malloc(sizeof(struct ahci_probe_ent)); + if (!probe_ent) { + printf("%s: No memory for probe_ent\n", __func__); + return -ENOMEM; + } + + memset(probe_ent, 0, sizeof(struct ahci_probe_ent)); + probe_ent->dev = dev; + + probe_ent->host_flags = ATA_FLAG_SATA + | ATA_FLAG_NO_LEGACY + | ATA_FLAG_MMIO + | ATA_FLAG_PIO_DMA + | ATA_FLAG_NO_ATAPI; + probe_ent->pio_mask = 0x1f; + probe_ent->udma_mask = 0x7f; /*Fixme,assume to support UDMA6 */ + +#if !defined(CONFIG_DM_SCSI) +#ifdef CONFIG_DM_PCI + probe_ent->mmio_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_5, + PCI_REGION_MEM); + + /* Take from kernel: + * JMicron-specific fixup: + * make sure we're in AHCI mode + */ + dm_pci_read_config16(dev, PCI_VENDOR_ID, &vendor); + if (vendor == 0x197b) + dm_pci_write_config8(dev, 0x41, 0xa1); +#else + probe_ent->mmio_base = pci_map_bar(dev, PCI_BASE_ADDRESS_5, + PCI_REGION_MEM); + + /* Take from kernel: + * JMicron-specific fixup: + * make sure we're in AHCI mode + */ + pci_read_config_word(dev, PCI_VENDOR_ID, &vendor); + if (vendor == 0x197b) + pci_write_config_byte(dev, 0x41, 0xa1); +#endif +#else + struct scsi_platdata *plat = dev_get_platdata(dev); + probe_ent->mmio_base = (void *)plat->base; +#endif + + debug("ahci mmio_base=0x%p\n", probe_ent->mmio_base); + /* initialize adapter */ + rc = ahci_host_init(probe_ent); + if (rc) + goto err_out; + + ahci_print_info(probe_ent); + + return 0; + + err_out: + return rc; +} +#endif + +#define MAX_DATA_BYTE_COUNT (4*1024*1024) + +static int ahci_fill_sg(u8 port, unsigned char *buf, int buf_len) +{ + struct ahci_ioports *pp = &(probe_ent->port[port]); + struct ahci_sg *ahci_sg = pp->cmd_tbl_sg; + u32 sg_count; + int i; + + sg_count = ((buf_len - 1) / MAX_DATA_BYTE_COUNT) + 1; + if (sg_count > AHCI_MAX_SG) { + printf("Error:Too much sg!\n"); + return -1; + } + + for (i = 0; i < sg_count; i++) { + ahci_sg->addr = + cpu_to_le32((unsigned long) buf + i * MAX_DATA_BYTE_COUNT); + ahci_sg->addr_hi = 0; + ahci_sg->flags_size = cpu_to_le32(0x3fffff & + (buf_len < MAX_DATA_BYTE_COUNT + ? (buf_len - 1) + : (MAX_DATA_BYTE_COUNT - 1))); + ahci_sg++; + buf_len -= MAX_DATA_BYTE_COUNT; + } + + return sg_count; +} + + +static void ahci_fill_cmd_slot(struct ahci_ioports *pp, u32 opts) +{ + pp->cmd_slot->opts = cpu_to_le32(opts); + pp->cmd_slot->status = 0; + pp->cmd_slot->tbl_addr = cpu_to_le32((u32)pp->cmd_tbl & 0xffffffff); +#ifdef CONFIG_PHYS_64BIT + pp->cmd_slot->tbl_addr_hi = + cpu_to_le32((u32)(((pp->cmd_tbl) >> 16) >> 16)); +#endif +} + +static int wait_spinup(void __iomem *port_mmio) +{ + ulong start; + u32 tf_data; + + start = get_timer(0); + do { + tf_data = readl(port_mmio + PORT_TFDATA); + if (!(tf_data & ATA_BUSY)) + return 0; + } while (get_timer(start) < WAIT_MS_SPINUP); + + return -ETIMEDOUT; +} + +static int ahci_port_start(u8 port) +{ + struct ahci_ioports *pp = &(probe_ent->port[port]); + void __iomem *port_mmio = pp->port_mmio; + u32 port_status; + void __iomem *mem; + + debug("Enter start port: %d\n", port); + port_status = readl(port_mmio + PORT_SCR_STAT); + debug("Port %d status: %x\n", port, port_status); + if ((port_status & 0xf) != 0x03) { + printf("No Link on this port!\n"); + return -1; + } + + mem = malloc(AHCI_PORT_PRIV_DMA_SZ + 2048); + if (!mem) { + free(pp); + printf("%s: No mem for table!\n", __func__); + return -ENOMEM; + } + + /* Aligned to 2048-bytes */ + mem = memalign(2048, AHCI_PORT_PRIV_DMA_SZ); + memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ); + + /* + * First item in chunk of DMA memory: 32-slot command table, + * 32 bytes each in size + */ + pp->cmd_slot = + (struct ahci_cmd_hdr *)(uintptr_t)virt_to_phys((void *)mem); + debug("cmd_slot = %p\n", pp->cmd_slot); + mem += (AHCI_CMD_SLOT_SZ + 224); + + /* + * Second item: Received-FIS area + */ + pp->rx_fis = virt_to_phys((void *)mem); + mem += AHCI_RX_FIS_SZ; + + /* + * Third item: data area for storing a single command + * and its scatter-gather table + */ + pp->cmd_tbl = virt_to_phys((void *)mem); + debug("cmd_tbl_dma = %lx\n", pp->cmd_tbl); + + mem += AHCI_CMD_TBL_HDR; + pp->cmd_tbl_sg = + (struct ahci_sg *)(uintptr_t)virt_to_phys((void *)mem); + + writel_with_flush((unsigned long)pp->cmd_slot, + port_mmio + PORT_LST_ADDR); + + writel_with_flush(pp->rx_fis, port_mmio + PORT_FIS_ADDR); + +#ifdef CONFIG_SUNXI_AHCI + sunxi_dma_init(port_mmio); +#endif + + writel_with_flush(PORT_CMD_ICC_ACTIVE | PORT_CMD_FIS_RX | + PORT_CMD_POWER_ON | PORT_CMD_SPIN_UP | + PORT_CMD_START, port_mmio + PORT_CMD); + + debug("Exit start port %d\n", port); + + /* + * Make sure interface is not busy based on error and status + * information from task file data register before proceeding + */ + return wait_spinup(port_mmio); +} + + +static int ahci_device_data_io(u8 port, u8 *fis, int fis_len, u8 *buf, + int buf_len, u8 is_write) +{ + + struct ahci_ioports *pp = &(probe_ent->port[port]); + void __iomem *port_mmio = pp->port_mmio; + u32 opts; + u32 port_status; + int sg_count; + + debug("Enter %s: for port %d\n", __func__, port); + + if (port > probe_ent->n_ports) { + printf("Invalid port number %d\n", port); + return -1; + } + + port_status = readl(port_mmio + PORT_SCR_STAT); + if ((port_status & 0xf) != 0x03) { + debug("No Link on port %d!\n", port); + return -1; + } + + memcpy((unsigned char *)pp->cmd_tbl, fis, fis_len); + + sg_count = ahci_fill_sg(port, buf, buf_len); + opts = (fis_len >> 2) | (sg_count << 16) | (is_write << 6); + ahci_fill_cmd_slot(pp, opts); + + ahci_dcache_flush_sata_cmd(pp); + ahci_dcache_flush_range((unsigned long)buf, (unsigned long)buf_len); + + writel_with_flush(1, port_mmio + PORT_CMD_ISSUE); + + if (waiting_for_cmd_completed(port_mmio + PORT_CMD_ISSUE, + WAIT_MS_DATAIO, 0x1)) { + printf("timeout exit!\n"); + return -1; + } + + ahci_dcache_invalidate_range((unsigned long)buf, + (unsigned long)buf_len); + debug("%s: %d byte transferred.\n", __func__, pp->cmd_slot->status); + + return 0; +} + + +static char *ata_id_strcpy(u16 *target, u16 *src, int len) +{ + int i; + for (i = 0; i < len / 2; i++) + target[i] = swab16(src[i]); + return (char *)target; +} + +/* + * SCSI INQUIRY command operation. + */ +static int ata_scsiop_inquiry(ccb *pccb) +{ + static const u8 hdr[] = { + 0, + 0, + 0x5, /* claim SPC-3 version compatibility */ + 2, + 95 - 4, + }; + u8 fis[20]; + u16 *idbuf; + ALLOC_CACHE_ALIGN_BUFFER(u16, tmpid, ATA_ID_WORDS); + u8 port; + + /* Clean ccb data buffer */ + memset(pccb->pdata, 0, pccb->datalen); + + memcpy(pccb->pdata, hdr, sizeof(hdr)); + + if (pccb->datalen <= 35) + return 0; + + memset(fis, 0, sizeof(fis)); + /* Construct the FIS */ + fis[0] = 0x27; /* Host to device FIS. */ + fis[1] = 1 << 7; /* Command FIS. */ + fis[2] = ATA_CMD_ID_ATA; /* Command byte. */ + + /* Read id from sata */ + port = pccb->target; + + if (ahci_device_data_io(port, (u8 *) &fis, sizeof(fis), (u8 *)tmpid, + ATA_ID_WORDS * 2, 0)) { + debug("scsi_ahci: SCSI inquiry command failure.\n"); + return -EIO; + } + + if (!ataid[port]) { + ataid[port] = malloc(ATA_ID_WORDS * 2); + if (!ataid[port]) { + printf("%s: No memory for ataid[port]\n", __func__); + return -ENOMEM; + } + } + + idbuf = ataid[port]; + + memcpy(idbuf, tmpid, ATA_ID_WORDS * 2); + ata_swap_buf_le16(idbuf, ATA_ID_WORDS); + + memcpy(&pccb->pdata[8], "ATA ", 8); + ata_id_strcpy((u16 *)&pccb->pdata[16], &idbuf[ATA_ID_PROD], 16); + ata_id_strcpy((u16 *)&pccb->pdata[32], &idbuf[ATA_ID_FW_REV], 4); + +#ifdef DEBUG + ata_dump_id(idbuf); +#endif + return 0; +} + + +/* + * SCSI READ10/WRITE10 command operation. + */ +static int ata_scsiop_read_write(ccb *pccb, u8 is_write) +{ + lbaint_t lba = 0; + u16 blocks = 0; + u8 fis[20]; + u8 *user_buffer = pccb->pdata; + u32 user_buffer_size = pccb->datalen; + + /* Retrieve the base LBA number from the ccb structure. */ + if (pccb->cmd[0] == SCSI_READ16) { + memcpy(&lba, pccb->cmd + 2, 8); + lba = be64_to_cpu(lba); + } else { + u32 temp; + memcpy(&temp, pccb->cmd + 2, 4); + lba = be32_to_cpu(temp); + } + + /* + * Retrieve the base LBA number and the block count from + * the ccb structure. + * + * For 10-byte and 16-byte SCSI R/W commands, transfer + * length 0 means transfer 0 block of data. + * However, for ATA R/W commands, sector count 0 means + * 256 or 65536 sectors, not 0 sectors as in SCSI. + * + * WARNING: one or two older ATA drives treat 0 as 0... + */ + if (pccb->cmd[0] == SCSI_READ16) + blocks = (((u16)pccb->cmd[13]) << 8) | ((u16) pccb->cmd[14]); + else + blocks = (((u16)pccb->cmd[7]) << 8) | ((u16) pccb->cmd[8]); + + debug("scsi_ahci: %s %u blocks starting from lba 0x" LBAFU "\n", + is_write ? "write" : "read", blocks, lba); + + /* Preset the FIS */ + memset(fis, 0, sizeof(fis)); + fis[0] = 0x27; /* Host to device FIS. */ + fis[1] = 1 << 7; /* Command FIS. */ + /* Command byte (read/write). */ + fis[2] = is_write ? ATA_CMD_WRITE_EXT : ATA_CMD_READ_EXT; + + while (blocks) { + u16 now_blocks; /* number of blocks per iteration */ + u32 transfer_size; /* number of bytes per iteration */ + + now_blocks = min((u16)MAX_SATA_BLOCKS_READ_WRITE, blocks); + + transfer_size = ATA_SECT_SIZE * now_blocks; + if (transfer_size > user_buffer_size) { + printf("scsi_ahci: Error: buffer too small.\n"); + return -EIO; + } + + /* + * LBA48 SATA command but only use 32bit address range within + * that (unless we've enabled 64bit LBA support). The next + * smaller command range (28bit) is too small. + */ + fis[4] = (lba >> 0) & 0xff; + fis[5] = (lba >> 8) & 0xff; + fis[6] = (lba >> 16) & 0xff; + fis[7] = 1 << 6; /* device reg: set LBA mode */ + fis[8] = ((lba >> 24) & 0xff); +#ifdef CONFIG_SYS_64BIT_LBA + if (pccb->cmd[0] == SCSI_READ16) { + fis[9] = ((lba >> 32) & 0xff); + fis[10] = ((lba >> 40) & 0xff); + } +#endif + + fis[3] = 0xe0; /* features */ + + /* Block (sector) count */ + fis[12] = (now_blocks >> 0) & 0xff; + fis[13] = (now_blocks >> 8) & 0xff; + + /* Read/Write from ahci */ + if (ahci_device_data_io(pccb->target, (u8 *) &fis, sizeof(fis), + user_buffer, transfer_size, + is_write)) { + debug("scsi_ahci: SCSI %s10 command failure.\n", + is_write ? "WRITE" : "READ"); + return -EIO; + } + + /* If this transaction is a write, do a following flush. + * Writes in u-boot are so rare, and the logic to know when is + * the last write and do a flush only there is sufficiently + * difficult. Just do a flush after every write. This incurs, + * usually, one extra flush when the rare writes do happen. + */ + if (is_write) { + if (-EIO == ata_io_flush(pccb->target)) + return -EIO; + } + user_buffer += transfer_size; + user_buffer_size -= transfer_size; + blocks -= now_blocks; + lba += now_blocks; + } + + return 0; +} + + +/* + * SCSI READ CAPACITY10 command operation. + */ +static int ata_scsiop_read_capacity10(ccb *pccb) +{ + u32 cap; + u64 cap64; + u32 block_size; + + if (!ataid[pccb->target]) { + printf("scsi_ahci: SCSI READ CAPACITY10 command failure. " + "\tNo ATA info!\n" + "\tPlease run SCSI command INQUIRY first!\n"); + return -EPERM; + } + + cap64 = ata_id_n_sectors(ataid[pccb->target]); + if (cap64 > 0x100000000ULL) + cap64 = 0xffffffff; + + cap = cpu_to_be32(cap64); + memcpy(pccb->pdata, &cap, sizeof(cap)); + + block_size = cpu_to_be32((u32)512); + memcpy(&pccb->pdata[4], &block_size, 4); + + return 0; +} + + +/* + * SCSI READ CAPACITY16 command operation. + */ +static int ata_scsiop_read_capacity16(ccb *pccb) +{ + u64 cap; + u64 block_size; + + if (!ataid[pccb->target]) { + printf("scsi_ahci: SCSI READ CAPACITY16 command failure. " + "\tNo ATA info!\n" + "\tPlease run SCSI command INQUIRY first!\n"); + return -EPERM; + } + + cap = ata_id_n_sectors(ataid[pccb->target]); + cap = cpu_to_be64(cap); + memcpy(pccb->pdata, &cap, sizeof(cap)); + + block_size = cpu_to_be64((u64)512); + memcpy(&pccb->pdata[8], &block_size, 8); + + return 0; +} + + +/* + * SCSI TEST UNIT READY command operation. + */ +static int ata_scsiop_test_unit_ready(ccb *pccb) +{ + return (ataid[pccb->target]) ? 0 : -EPERM; +} + + +int scsi_exec(ccb *pccb) +{ + int ret; + + switch (pccb->cmd[0]) { + case SCSI_READ16: + case SCSI_READ10: + ret = ata_scsiop_read_write(pccb, 0); + break; + case SCSI_WRITE10: + ret = ata_scsiop_read_write(pccb, 1); + break; + case SCSI_RD_CAPAC10: + ret = ata_scsiop_read_capacity10(pccb); + break; + case SCSI_RD_CAPAC16: + ret = ata_scsiop_read_capacity16(pccb); + break; + case SCSI_TST_U_RDY: + ret = ata_scsiop_test_unit_ready(pccb); + break; + case SCSI_INQUIRY: + ret = ata_scsiop_inquiry(pccb); + break; + default: + printf("Unsupport SCSI command 0x%02x\n", pccb->cmd[0]); + return false; + } + + if (ret) { + debug("SCSI command 0x%02x ret errno %d\n", pccb->cmd[0], ret); + return false; + } + return true; + +} + +#if defined(CONFIG_DM_SCSI) +void scsi_low_level_init(int busdevfunc, struct udevice *dev) +#else +void scsi_low_level_init(int busdevfunc) +#endif +{ + int i; + u32 linkmap; + +#ifndef CONFIG_SCSI_AHCI_PLAT +# if defined(CONFIG_DM_PCI) + struct udevice *dev; + int ret; + + ret = dm_pci_bus_find_bdf(busdevfunc, &dev); + if (ret) + return; + ahci_init_one(dev); +# elif defined(CONFIG_DM_SCSI) + ahci_init_one(dev); +# else + ahci_init_one(busdevfunc); +# endif +#endif + + linkmap = probe_ent->link_port_map; + + for (i = 0; i < CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) { + if (((linkmap >> i) & 0x01)) { + if (ahci_port_start((u8) i)) { + printf("Can not start port %d\n", i); + continue; + } + } + } +} + +#ifdef CONFIG_SCSI_AHCI_PLAT +int ahci_init(void __iomem *base) +{ + int i, rc = 0; + u32 linkmap; + + probe_ent = malloc(sizeof(struct ahci_probe_ent)); + if (!probe_ent) { + printf("%s: No memory for probe_ent\n", __func__); + return -ENOMEM; + } + + memset(probe_ent, 0, sizeof(struct ahci_probe_ent)); + + probe_ent->host_flags = ATA_FLAG_SATA + | ATA_FLAG_NO_LEGACY + | ATA_FLAG_MMIO + | ATA_FLAG_PIO_DMA + | ATA_FLAG_NO_ATAPI; + probe_ent->pio_mask = 0x1f; + probe_ent->udma_mask = 0x7f; /*Fixme,assume to support UDMA6 */ + + probe_ent->mmio_base = base; + + /* initialize adapter */ + rc = ahci_host_init(probe_ent); + if (rc) + goto err_out; + + ahci_print_info(probe_ent); + + linkmap = probe_ent->link_port_map; + + for (i = 0; i < CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) { + if (((linkmap >> i) & 0x01)) { + if (ahci_port_start((u8) i)) { + printf("Can not start port %d\n", i); + continue; + } + } + } +err_out: + return rc; +} + +void __weak scsi_init(void) +{ +} + +#endif + +/* + * In the general case of generic rotating media it makes sense to have a + * flush capability. It probably even makes sense in the case of SSDs because + * one cannot always know for sure what kind of internal cache/flush mechanism + * is embodied therein. At first it was planned to invoke this after the last + * write to disk and before rebooting. In practice, knowing, a priori, which + * is the last write is difficult. Because writing to the disk in u-boot is + * very rare, this flush command will be invoked after every block write. + */ +static int ata_io_flush(u8 port) +{ + u8 fis[20]; + struct ahci_ioports *pp = &(probe_ent->port[port]); + void __iomem *port_mmio = pp->port_mmio; + u32 cmd_fis_len = 5; /* five dwords */ + + /* Preset the FIS */ + memset(fis, 0, 20); + fis[0] = 0x27; /* Host to device FIS. */ + fis[1] = 1 << 7; /* Command FIS. */ + fis[2] = ATA_CMD_FLUSH_EXT; + + memcpy((unsigned char *)pp->cmd_tbl, fis, 20); + ahci_fill_cmd_slot(pp, cmd_fis_len); + ahci_dcache_flush_sata_cmd(pp); + writel_with_flush(1, port_mmio + PORT_CMD_ISSUE); + + if (waiting_for_cmd_completed(port_mmio + PORT_CMD_ISSUE, + WAIT_MS_FLUSH, 0x1)) { + debug("scsi_ahci: flush command timeout on port %d.\n", port); + return -EIO; + } + + return 0; +} + + +__weak void scsi_bus_reset(void) +{ + /*Not implement*/ +} diff --git a/drivers/ata/dwc_ahci.c b/drivers/ata/dwc_ahci.c new file mode 100644 index 0000000..3f839bf --- /dev/null +++ b/drivers/ata/dwc_ahci.c @@ -0,0 +1,101 @@ +/* + * DWC SATA platform driver + * + * (C) Copyright 2016 + * Texas Instruments Incorporated, + * + * Author: Mugunthan V N + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +struct dwc_ahci_priv { + void *base; + void *wrapper_base; +}; + +static int dwc_ahci_ofdata_to_platdata(struct udevice *dev) +{ + struct dwc_ahci_priv *priv = dev_get_priv(dev); + struct scsi_platdata *plat = dev_get_platdata(dev); + fdt_addr_t addr; + + plat->max_id = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev), + "max-id", CONFIG_SYS_SCSI_MAX_SCSI_ID); + plat->max_lun = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev), + "max-lun", CONFIG_SYS_SCSI_MAX_LUN); + + priv->base = map_physmem(devfdt_get_addr(dev), sizeof(void *), + MAP_NOCACHE); + + addr = devfdt_get_addr_index(dev, 1); + if (addr != FDT_ADDR_T_NONE) { + priv->wrapper_base = map_physmem(addr, sizeof(void *), + MAP_NOCACHE); + } else { + priv->wrapper_base = NULL; + } + + return 0; +} + +static int dwc_ahci_probe(struct udevice *dev) +{ + struct dwc_ahci_priv *priv = dev_get_priv(dev); + int ret; + struct phy phy; + + ret = generic_phy_get_by_name(dev, "sata-phy", &phy); + if (ret) { + error("can't get the phy from DT\n"); + return ret; + } + + ret = generic_phy_init(&phy); + if (ret) { + error("unable to initialize the sata phy\n"); + return ret; + } + + ret = generic_phy_power_on(&phy); + if (ret) { + error("unable to power on the sata phy\n"); + return ret; + } + + if (priv->wrapper_base) { + u32 val = TI_SATA_IDLE_NO | TI_SATA_STANDBY_NO; + + /* Enable SATA module, No Idle, No Standby */ + writel(val, priv->wrapper_base + TI_SATA_SYSCONFIG); + } + + return ahci_init(priv->base); +} + +static const struct udevice_id dwc_ahci_ids[] = { + { .compatible = "snps,dwc-ahci" }, + { } +}; + +U_BOOT_DRIVER(dwc_ahci) = { + .name = "dwc_ahci", + .id = UCLASS_SCSI, + .of_match = dwc_ahci_ids, + .ofdata_to_platdata = dwc_ahci_ofdata_to_platdata, + .probe = dwc_ahci_probe, + .priv_auto_alloc_size = sizeof(struct dwc_ahci_priv), + .platdata_auto_alloc_size = sizeof(struct scsi_platdata), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +}; diff --git a/drivers/ata/dwc_ahsata.c b/drivers/ata/dwc_ahsata.c new file mode 100644 index 0000000..c306e92 --- /dev/null +++ b/drivers/ata/dwc_ahsata.c @@ -0,0 +1,1018 @@ +/* + * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. + * Terry Lv + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include "dwc_ahsata.h" + +struct sata_port_regs { + u32 clb; + u32 clbu; + u32 fb; + u32 fbu; + u32 is; + u32 ie; + u32 cmd; + u32 res1[1]; + u32 tfd; + u32 sig; + u32 ssts; + u32 sctl; + u32 serr; + u32 sact; + u32 ci; + u32 sntf; + u32 res2[1]; + u32 dmacr; + u32 res3[1]; + u32 phycr; + u32 physr; +}; + +struct sata_host_regs { + u32 cap; + u32 ghc; + u32 is; + u32 pi; + u32 vs; + u32 ccc_ctl; + u32 ccc_ports; + u32 res1[2]; + u32 cap2; + u32 res2[30]; + u32 bistafr; + u32 bistcr; + u32 bistfctr; + u32 bistsr; + u32 bistdecr; + u32 res3[2]; + u32 oobr; + u32 res4[8]; + u32 timer1ms; + u32 res5[1]; + u32 gparam1r; + u32 gparam2r; + u32 pparamr; + u32 testr; + u32 versionr; + u32 idr; +}; + +#define MAX_DATA_BYTES_PER_SG (4 * 1024 * 1024) +#define MAX_BYTES_PER_TRANS (AHCI_MAX_SG * MAX_DATA_BYTES_PER_SG) + +#define writel_with_flush(a, b) do { writel(a, b); readl(b); } while (0) + +static int is_ready; + +static inline void __iomem *ahci_port_base(void __iomem *base, u32 port) +{ + return base + 0x100 + (port * 0x80); +} + +static int waiting_for_cmd_completed(u8 *offset, + int timeout_msec, + u32 sign) +{ + int i; + u32 status; + + for (i = 0; + ((status = readl(offset)) & sign) && i < timeout_msec; + ++i) + mdelay(1); + + return (i < timeout_msec) ? 0 : -1; +} + +static int ahci_setup_oobr(struct ahci_probe_ent *probe_ent, + int clk) +{ + struct sata_host_regs *host_mmio = + (struct sata_host_regs *)probe_ent->mmio_base; + + writel(SATA_HOST_OOBR_WE, &(host_mmio->oobr)); + writel(0x02060b14, &(host_mmio->oobr)); + + return 0; +} + +static int ahci_host_init(struct ahci_probe_ent *probe_ent) +{ + u32 tmp, cap_save, num_ports; + int i, j, timeout = 1000; + struct sata_port_regs *port_mmio = NULL; + struct sata_host_regs *host_mmio = + (struct sata_host_regs *)probe_ent->mmio_base; + int clk = mxc_get_clock(MXC_SATA_CLK); + + cap_save = readl(&(host_mmio->cap)); + cap_save |= SATA_HOST_CAP_SSS; + + /* global controller reset */ + tmp = readl(&(host_mmio->ghc)); + if ((tmp & SATA_HOST_GHC_HR) == 0) + writel_with_flush(tmp | SATA_HOST_GHC_HR, &(host_mmio->ghc)); + + while ((readl(&(host_mmio->ghc)) & SATA_HOST_GHC_HR) + && --timeout) + ; + + if (timeout <= 0) { + debug("controller reset failed (0x%x)\n", tmp); + return -1; + } + + /* Set timer 1ms */ + writel(clk / 1000, &(host_mmio->timer1ms)); + + ahci_setup_oobr(probe_ent, 0); + + writel_with_flush(SATA_HOST_GHC_AE, &(host_mmio->ghc)); + writel(cap_save, &(host_mmio->cap)); + num_ports = (cap_save & SATA_HOST_CAP_NP_MASK) + 1; + writel_with_flush((1 << num_ports) - 1, + &(host_mmio->pi)); + + /* + * Determine which Ports are implemented by the DWC_ahsata, + * by reading the PI register. This bit map value aids the + * software to determine how many Ports are available and + * which Port registers need to be initialized. + */ + probe_ent->cap = readl(&(host_mmio->cap)); + probe_ent->port_map = readl(&(host_mmio->pi)); + + /* Determine how many command slots the HBA supports */ + probe_ent->n_ports = + (probe_ent->cap & SATA_HOST_CAP_NP_MASK) + 1; + + debug("cap 0x%x port_map 0x%x n_ports %d\n", + probe_ent->cap, probe_ent->port_map, probe_ent->n_ports); + + for (i = 0; i < probe_ent->n_ports; i++) { + probe_ent->port[i].port_mmio = + ahci_port_base(host_mmio, i); + port_mmio = + (struct sata_port_regs *)probe_ent->port[i].port_mmio; + + /* Ensure that the DWC_ahsata is in idle state */ + tmp = readl(&(port_mmio->cmd)); + + /* + * When P#CMD.ST, P#CMD.CR, P#CMD.FRE and P#CMD.FR + * are all cleared, the Port is in an idle state. + */ + if (tmp & (SATA_PORT_CMD_CR | SATA_PORT_CMD_FR | + SATA_PORT_CMD_FRE | SATA_PORT_CMD_ST)) { + + /* + * System software places a Port into the idle state by + * clearing P#CMD.ST and waiting for P#CMD.CR to return + * 0 when read. + */ + tmp &= ~SATA_PORT_CMD_ST; + writel_with_flush(tmp, &(port_mmio->cmd)); + + /* + * spec says 500 msecs for each bit, so + * this is slightly incorrect. + */ + mdelay(500); + + timeout = 1000; + while ((readl(&(port_mmio->cmd)) & SATA_PORT_CMD_CR) + && --timeout) + ; + + if (timeout <= 0) { + debug("port reset failed (0x%x)\n", tmp); + return -1; + } + } + + /* Spin-up device */ + tmp = readl(&(port_mmio->cmd)); + writel((tmp | SATA_PORT_CMD_SUD), &(port_mmio->cmd)); + + /* Wait for spin-up to finish */ + timeout = 1000; + while (!(readl(&(port_mmio->cmd)) | SATA_PORT_CMD_SUD) + && --timeout) + ; + if (timeout <= 0) { + debug("Spin-Up can't finish!\n"); + return -1; + } + + for (j = 0; j < 100; ++j) { + mdelay(10); + tmp = readl(&(port_mmio->ssts)); + if (((tmp & SATA_PORT_SSTS_DET_MASK) == 0x3) || + ((tmp & SATA_PORT_SSTS_DET_MASK) == 0x1)) + break; + } + + /* Wait for COMINIT bit 26 (DIAG_X) in SERR */ + timeout = 1000; + while (!(readl(&(port_mmio->serr)) | SATA_PORT_SERR_DIAG_X) + && --timeout) + ; + if (timeout <= 0) { + debug("Can't find DIAG_X set!\n"); + return -1; + } + + /* + * For each implemented Port, clear the P#SERR + * register, by writing ones to each implemented\ + * bit location. + */ + tmp = readl(&(port_mmio->serr)); + debug("P#SERR 0x%x\n", + tmp); + writel(tmp, &(port_mmio->serr)); + + /* Ack any pending irq events for this port */ + tmp = readl(&(host_mmio->is)); + debug("IS 0x%x\n", tmp); + if (tmp) + writel(tmp, &(host_mmio->is)); + + writel(1 << i, &(host_mmio->is)); + + /* set irq mask (enables interrupts) */ + writel(DEF_PORT_IRQ, &(port_mmio->ie)); + + /* register linkup ports */ + tmp = readl(&(port_mmio->ssts)); + debug("Port %d status: 0x%x\n", i, tmp); + if ((tmp & SATA_PORT_SSTS_DET_MASK) == 0x03) + probe_ent->link_port_map |= (0x01 << i); + } + + tmp = readl(&(host_mmio->ghc)); + debug("GHC 0x%x\n", tmp); + writel(tmp | SATA_HOST_GHC_IE, &(host_mmio->ghc)); + tmp = readl(&(host_mmio->ghc)); + debug("GHC 0x%x\n", tmp); + + return 0; +} + +static void ahci_print_info(struct ahci_probe_ent *probe_ent) +{ + struct sata_host_regs *host_mmio = + (struct sata_host_regs *)probe_ent->mmio_base; + u32 vers, cap, impl, speed; + const char *speed_s; + const char *scc_s; + + vers = readl(&(host_mmio->vs)); + cap = probe_ent->cap; + impl = probe_ent->port_map; + + speed = (cap & SATA_HOST_CAP_ISS_MASK) + >> SATA_HOST_CAP_ISS_OFFSET; + if (speed == 1) + speed_s = "1.5"; + else if (speed == 2) + speed_s = "3"; + else + speed_s = "?"; + + scc_s = "SATA"; + + printf("AHCI %02x%02x.%02x%02x " + "%u slots %u ports %s Gbps 0x%x impl %s mode\n", + (vers >> 24) & 0xff, + (vers >> 16) & 0xff, + (vers >> 8) & 0xff, + vers & 0xff, + ((cap >> 8) & 0x1f) + 1, + (cap & 0x1f) + 1, + speed_s, + impl, + scc_s); + + printf("flags: " + "%s%s%s%s%s%s" + "%s%s%s%s%s%s%s\n", + cap & (1 << 31) ? "64bit " : "", + cap & (1 << 30) ? "ncq " : "", + cap & (1 << 28) ? "ilck " : "", + cap & (1 << 27) ? "stag " : "", + cap & (1 << 26) ? "pm " : "", + cap & (1 << 25) ? "led " : "", + cap & (1 << 24) ? "clo " : "", + cap & (1 << 19) ? "nz " : "", + cap & (1 << 18) ? "only " : "", + cap & (1 << 17) ? "pmp " : "", + cap & (1 << 15) ? "pio " : "", + cap & (1 << 14) ? "slum " : "", + cap & (1 << 13) ? "part " : ""); +} + +static int ahci_init_one(int pdev) +{ + int rc; + struct ahci_probe_ent *probe_ent = NULL; + + probe_ent = malloc(sizeof(struct ahci_probe_ent)); + memset(probe_ent, 0, sizeof(struct ahci_probe_ent)); + probe_ent->dev = pdev; + + probe_ent->host_flags = ATA_FLAG_SATA + | ATA_FLAG_NO_LEGACY + | ATA_FLAG_MMIO + | ATA_FLAG_PIO_DMA + | ATA_FLAG_NO_ATAPI; + + probe_ent->mmio_base = (void __iomem *)CONFIG_DWC_AHSATA_BASE_ADDR; + + /* initialize adapter */ + rc = ahci_host_init(probe_ent); + if (rc) + goto err_out; + + ahci_print_info(probe_ent); + + /* Save the private struct to block device struct */ + sata_dev_desc[pdev].priv = (void *)probe_ent; + + return 0; + +err_out: + return rc; +} + +static int ahci_fill_sg(struct ahci_probe_ent *probe_ent, + u8 port, unsigned char *buf, int buf_len) +{ + struct ahci_ioports *pp = &(probe_ent->port[port]); + struct ahci_sg *ahci_sg = pp->cmd_tbl_sg; + u32 sg_count, max_bytes; + int i; + + max_bytes = MAX_DATA_BYTES_PER_SG; + sg_count = ((buf_len - 1) / max_bytes) + 1; + if (sg_count > AHCI_MAX_SG) { + printf("Error:Too much sg!\n"); + return -1; + } + + for (i = 0; i < sg_count; i++) { + ahci_sg->addr = + cpu_to_le32((u32)buf + i * max_bytes); + ahci_sg->addr_hi = 0; + ahci_sg->flags_size = cpu_to_le32(0x3fffff & + (buf_len < max_bytes + ? (buf_len - 1) + : (max_bytes - 1))); + ahci_sg++; + buf_len -= max_bytes; + } + + return sg_count; +} + +static void ahci_fill_cmd_slot(struct ahci_ioports *pp, u32 cmd_slot, u32 opts) +{ + struct ahci_cmd_hdr *cmd_hdr = (struct ahci_cmd_hdr *)(pp->cmd_slot + + AHCI_CMD_SLOT_SZ * cmd_slot); + + memset(cmd_hdr, 0, AHCI_CMD_SLOT_SZ); + cmd_hdr->opts = cpu_to_le32(opts); + cmd_hdr->status = 0; + pp->cmd_slot->tbl_addr = cpu_to_le32((u32)pp->cmd_tbl & 0xffffffff); +#ifdef CONFIG_PHYS_64BIT + pp->cmd_slot->tbl_addr_hi = + cpu_to_le32((u32)(((pp->cmd_tbl) >> 16) >> 16)); +#endif +} + +#define AHCI_GET_CMD_SLOT(c) ((c) ? ffs(c) : 0) + +static int ahci_exec_ata_cmd(struct ahci_probe_ent *probe_ent, + u8 port, struct sata_fis_h2d *cfis, + u8 *buf, u32 buf_len, s32 is_write) +{ + struct ahci_ioports *pp = &(probe_ent->port[port]); + struct sata_port_regs *port_mmio = + (struct sata_port_regs *)pp->port_mmio; + u32 opts; + int sg_count = 0, cmd_slot = 0; + + cmd_slot = AHCI_GET_CMD_SLOT(readl(&(port_mmio->ci))); + if (32 == cmd_slot) { + printf("Can't find empty command slot!\n"); + return 0; + } + + /* Check xfer length */ + if (buf_len > MAX_BYTES_PER_TRANS) { + printf("Max transfer length is %dB\n\r", + MAX_BYTES_PER_TRANS); + return 0; + } + + memcpy((u8 *)(pp->cmd_tbl), cfis, sizeof(struct sata_fis_h2d)); + if (buf && buf_len) + sg_count = ahci_fill_sg(probe_ent, port, buf, buf_len); + opts = (sizeof(struct sata_fis_h2d) >> 2) | (sg_count << 16); + if (is_write) { + opts |= 0x40; + flush_cache((ulong)buf, buf_len); + } + ahci_fill_cmd_slot(pp, cmd_slot, opts); + + flush_cache((int)(pp->cmd_slot), AHCI_PORT_PRIV_DMA_SZ); + writel_with_flush(1 << cmd_slot, &(port_mmio->ci)); + + if (waiting_for_cmd_completed((u8 *)&(port_mmio->ci), + 10000, 0x1 << cmd_slot)) { + printf("timeout exit!\n"); + return -1; + } + invalidate_dcache_range((int)(pp->cmd_slot), + (int)(pp->cmd_slot)+AHCI_PORT_PRIV_DMA_SZ); + debug("ahci_exec_ata_cmd: %d byte transferred.\n", + pp->cmd_slot->status); + if (!is_write) + invalidate_dcache_range((ulong)buf, (ulong)buf+buf_len); + + return buf_len; +} + +static void ahci_set_feature(u8 dev, u8 port) +{ + struct ahci_probe_ent *probe_ent = + (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN); + struct sata_fis_h2d *cfis = &h2d; + + memset(cfis, 0, sizeof(struct sata_fis_h2d)); + cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; + cfis->pm_port_c = 1 << 7; + cfis->command = ATA_CMD_SET_FEATURES; + cfis->features = SETFEATURES_XFER; + cfis->sector_count = ffs(probe_ent->udma_mask + 1) + 0x3e; + + ahci_exec_ata_cmd(probe_ent, port, cfis, NULL, 0, READ_CMD); +} + +static int ahci_port_start(struct ahci_probe_ent *probe_ent, + u8 port) +{ + struct ahci_ioports *pp = &(probe_ent->port[port]); + struct sata_port_regs *port_mmio = + (struct sata_port_regs *)pp->port_mmio; + u32 port_status; + u32 mem; + int timeout = 10000000; + + debug("Enter start port: %d\n", port); + port_status = readl(&(port_mmio->ssts)); + debug("Port %d status: %x\n", port, port_status); + if ((port_status & 0xf) != 0x03) { + printf("No Link on this port!\n"); + return -1; + } + + mem = (u32)malloc(AHCI_PORT_PRIV_DMA_SZ + 1024); + if (!mem) { + free(pp); + printf("No mem for table!\n"); + return -ENOMEM; + } + + mem = (mem + 0x400) & (~0x3ff); /* Aligned to 1024-bytes */ + memset((u8 *)mem, 0, AHCI_PORT_PRIV_DMA_SZ); + + /* + * First item in chunk of DMA memory: 32-slot command table, + * 32 bytes each in size + */ + pp->cmd_slot = (struct ahci_cmd_hdr *)mem; + debug("cmd_slot = 0x%x\n", (unsigned int) pp->cmd_slot); + mem += (AHCI_CMD_SLOT_SZ * DWC_AHSATA_MAX_CMD_SLOTS); + + /* + * Second item: Received-FIS area, 256-Byte aligned + */ + pp->rx_fis = mem; + mem += AHCI_RX_FIS_SZ; + + /* + * Third item: data area for storing a single command + * and its scatter-gather table + */ + pp->cmd_tbl = mem; + debug("cmd_tbl_dma = 0x%lx\n", pp->cmd_tbl); + + mem += AHCI_CMD_TBL_HDR; + + writel_with_flush(0x00004444, &(port_mmio->dmacr)); + pp->cmd_tbl_sg = (struct ahci_sg *)mem; + writel_with_flush((u32)pp->cmd_slot, &(port_mmio->clb)); + writel_with_flush(pp->rx_fis, &(port_mmio->fb)); + + /* Enable FRE */ + writel_with_flush((SATA_PORT_CMD_FRE | readl(&(port_mmio->cmd))), + &(port_mmio->cmd)); + + /* Wait device ready */ + while ((readl(&(port_mmio->tfd)) & (SATA_PORT_TFD_STS_ERR | + SATA_PORT_TFD_STS_DRQ | SATA_PORT_TFD_STS_BSY)) + && --timeout) + ; + if (timeout <= 0) { + debug("Device not ready for BSY, DRQ and" + "ERR in TFD!\n"); + return -1; + } + + writel_with_flush(PORT_CMD_ICC_ACTIVE | PORT_CMD_FIS_RX | + PORT_CMD_POWER_ON | PORT_CMD_SPIN_UP | + PORT_CMD_START, &(port_mmio->cmd)); + + debug("Exit start port %d\n", port); + + return 0; +} + +int init_sata(int dev) +{ + int i; + u32 linkmap; + struct ahci_probe_ent *probe_ent = NULL; + +#if defined(CONFIG_MX6) + if (!is_mx6dq() && !is_mx6dqp()) + return 1; +#endif + if (dev < 0 || dev > (CONFIG_SYS_SATA_MAX_DEVICE - 1)) { + printf("The sata index %d is out of ranges\n\r", dev); + return -1; + } + + ahci_init_one(dev); + + probe_ent = (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + linkmap = probe_ent->link_port_map; + + if (0 == linkmap) { + printf("No port device detected!\n"); + return 1; + } + + for (i = 0; i < probe_ent->n_ports; i++) { + if ((linkmap >> i) && ((linkmap >> i) & 0x01)) { + if (ahci_port_start(probe_ent, (u8)i)) { + printf("Can not start port %d\n", i); + return 1; + } + probe_ent->hard_port_no = i; + break; + } + } + + return 0; +} + +int reset_sata(int dev) +{ + struct ahci_probe_ent *probe_ent; + struct sata_host_regs *host_mmio; + + if (dev < 0 || dev > (CONFIG_SYS_SATA_MAX_DEVICE - 1)) { + printf("The sata index %d is out of ranges\n\r", dev); + return -1; + } + + probe_ent = (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + if (NULL == probe_ent) + /* not initialized, so nothing to reset */ + return 0; + + host_mmio = (struct sata_host_regs *)probe_ent->mmio_base; + setbits_le32(&host_mmio->ghc, SATA_HOST_GHC_HR); + while (readl(&host_mmio->ghc) & SATA_HOST_GHC_HR) + udelay(100); + + return 0; +} + +static void dwc_ahsata_print_info(int dev) +{ + struct blk_desc *pdev = &(sata_dev_desc[dev]); + + printf("SATA Device Info:\n\r"); +#ifdef CONFIG_SYS_64BIT_LBA + printf("S/N: %s\n\rProduct model number: %s\n\r" + "Firmware version: %s\n\rCapacity: %lld sectors\n\r", + pdev->product, pdev->vendor, pdev->revision, pdev->lba); +#else + printf("S/N: %s\n\rProduct model number: %s\n\r" + "Firmware version: %s\n\rCapacity: %ld sectors\n\r", + pdev->product, pdev->vendor, pdev->revision, pdev->lba); +#endif +} + +static void dwc_ahsata_identify(int dev, u16 *id) +{ + struct ahci_probe_ent *probe_ent = + (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN); + struct sata_fis_h2d *cfis = &h2d; + u8 port = probe_ent->hard_port_no; + + memset(cfis, 0, sizeof(struct sata_fis_h2d)); + + cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; + cfis->pm_port_c = 0x80; /* is command */ + cfis->command = ATA_CMD_ID_ATA; + + ahci_exec_ata_cmd(probe_ent, port, cfis, + (u8 *)id, ATA_ID_WORDS * 2, READ_CMD); + ata_swap_buf_le16(id, ATA_ID_WORDS); +} + +static void dwc_ahsata_xfer_mode(int dev, u16 *id) +{ + struct ahci_probe_ent *probe_ent = + (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + + probe_ent->pio_mask = id[ATA_ID_PIO_MODES]; + probe_ent->udma_mask = id[ATA_ID_UDMA_MODES]; + debug("pio %04x, udma %04x\n\r", + probe_ent->pio_mask, probe_ent->udma_mask); +} + +static u32 dwc_ahsata_rw_cmd(int dev, u32 start, u32 blkcnt, + u8 *buffer, int is_write) +{ + struct ahci_probe_ent *probe_ent = + (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN); + struct sata_fis_h2d *cfis = &h2d; + u8 port = probe_ent->hard_port_no; + u32 block; + + block = start; + + memset(cfis, 0, sizeof(struct sata_fis_h2d)); + + cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; + cfis->pm_port_c = 0x80; /* is command */ + cfis->command = (is_write) ? ATA_CMD_WRITE : ATA_CMD_READ; + cfis->device = ATA_LBA; + + cfis->device |= (block >> 24) & 0xf; + cfis->lba_high = (block >> 16) & 0xff; + cfis->lba_mid = (block >> 8) & 0xff; + cfis->lba_low = block & 0xff; + cfis->sector_count = (u8)(blkcnt & 0xff); + + if (ahci_exec_ata_cmd(probe_ent, port, cfis, + buffer, ATA_SECT_SIZE * blkcnt, is_write) > 0) + return blkcnt; + else + return 0; +} + +void dwc_ahsata_flush_cache(int dev) +{ + struct ahci_probe_ent *probe_ent = + (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN); + struct sata_fis_h2d *cfis = &h2d; + u8 port = probe_ent->hard_port_no; + + memset(cfis, 0, sizeof(struct sata_fis_h2d)); + + cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; + cfis->pm_port_c = 0x80; /* is command */ + cfis->command = ATA_CMD_FLUSH; + + ahci_exec_ata_cmd(probe_ent, port, cfis, NULL, 0, 0); +} + +static u32 dwc_ahsata_rw_cmd_ext(int dev, u32 start, lbaint_t blkcnt, + u8 *buffer, int is_write) +{ + struct ahci_probe_ent *probe_ent = + (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN); + struct sata_fis_h2d *cfis = &h2d; + u8 port = probe_ent->hard_port_no; + u64 block; + + block = (u64)start; + + memset(cfis, 0, sizeof(struct sata_fis_h2d)); + + cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; + cfis->pm_port_c = 0x80; /* is command */ + + cfis->command = (is_write) ? ATA_CMD_WRITE_EXT + : ATA_CMD_READ_EXT; + + cfis->lba_high_exp = (block >> 40) & 0xff; + cfis->lba_mid_exp = (block >> 32) & 0xff; + cfis->lba_low_exp = (block >> 24) & 0xff; + cfis->lba_high = (block >> 16) & 0xff; + cfis->lba_mid = (block >> 8) & 0xff; + cfis->lba_low = block & 0xff; + cfis->device = ATA_LBA; + cfis->sector_count_exp = (blkcnt >> 8) & 0xff; + cfis->sector_count = blkcnt & 0xff; + + if (ahci_exec_ata_cmd(probe_ent, port, cfis, buffer, + ATA_SECT_SIZE * blkcnt, is_write) > 0) + return blkcnt; + else + return 0; +} + +u32 dwc_ahsata_rw_ncq_cmd(int dev, u32 start, lbaint_t blkcnt, + u8 *buffer, int is_write) +{ + struct ahci_probe_ent *probe_ent = + (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN); + struct sata_fis_h2d *cfis = &h2d; + u8 port = probe_ent->hard_port_no; + u64 block; + + if (sata_dev_desc[dev].lba48 != 1) { + printf("execute FPDMA command on non-LBA48 hard disk\n\r"); + return -1; + } + + block = (u64)start; + + memset(cfis, 0, sizeof(struct sata_fis_h2d)); + + cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; + cfis->pm_port_c = 0x80; /* is command */ + + cfis->command = (is_write) ? ATA_CMD_FPDMA_WRITE + : ATA_CMD_FPDMA_READ; + + cfis->lba_high_exp = (block >> 40) & 0xff; + cfis->lba_mid_exp = (block >> 32) & 0xff; + cfis->lba_low_exp = (block >> 24) & 0xff; + cfis->lba_high = (block >> 16) & 0xff; + cfis->lba_mid = (block >> 8) & 0xff; + cfis->lba_low = block & 0xff; + + cfis->device = ATA_LBA; + cfis->features_exp = (blkcnt >> 8) & 0xff; + cfis->features = blkcnt & 0xff; + + /* Use the latest queue */ + ahci_exec_ata_cmd(probe_ent, port, cfis, + buffer, ATA_SECT_SIZE * blkcnt, is_write); + + return blkcnt; +} + +void dwc_ahsata_flush_cache_ext(int dev) +{ + struct ahci_probe_ent *probe_ent = + (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN); + struct sata_fis_h2d *cfis = &h2d; + u8 port = probe_ent->hard_port_no; + + memset(cfis, 0, sizeof(struct sata_fis_h2d)); + + cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; + cfis->pm_port_c = 0x80; /* is command */ + cfis->command = ATA_CMD_FLUSH_EXT; + + ahci_exec_ata_cmd(probe_ent, port, cfis, NULL, 0, 0); +} + +static void dwc_ahsata_init_wcache(int dev, u16 *id) +{ + struct ahci_probe_ent *probe_ent = + (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + + if (ata_id_has_wcache(id) && ata_id_wcache_enabled(id)) + probe_ent->flags |= SATA_FLAG_WCACHE; + if (ata_id_has_flush(id)) + probe_ent->flags |= SATA_FLAG_FLUSH; + if (ata_id_has_flush_ext(id)) + probe_ent->flags |= SATA_FLAG_FLUSH_EXT; +} + +u32 ata_low_level_rw_lba48(int dev, u32 blknr, lbaint_t blkcnt, + const void *buffer, int is_write) +{ + u32 start, blks; + u8 *addr; + int max_blks; + + start = blknr; + blks = blkcnt; + addr = (u8 *)buffer; + + max_blks = ATA_MAX_SECTORS_LBA48; + + do { + if (blks > max_blks) { + if (max_blks != dwc_ahsata_rw_cmd_ext(dev, start, + max_blks, addr, is_write)) + return 0; + start += max_blks; + blks -= max_blks; + addr += ATA_SECT_SIZE * max_blks; + } else { + if (blks != dwc_ahsata_rw_cmd_ext(dev, start, + blks, addr, is_write)) + return 0; + start += blks; + blks = 0; + addr += ATA_SECT_SIZE * blks; + } + } while (blks != 0); + + return blkcnt; +} + +u32 ata_low_level_rw_lba28(int dev, u32 blknr, lbaint_t blkcnt, + const void *buffer, int is_write) +{ + u32 start, blks; + u8 *addr; + int max_blks; + + start = blknr; + blks = blkcnt; + addr = (u8 *)buffer; + + max_blks = ATA_MAX_SECTORS; + do { + if (blks > max_blks) { + if (max_blks != dwc_ahsata_rw_cmd(dev, start, + max_blks, addr, is_write)) + return 0; + start += max_blks; + blks -= max_blks; + addr += ATA_SECT_SIZE * max_blks; + } else { + if (blks != dwc_ahsata_rw_cmd(dev, start, + blks, addr, is_write)) + return 0; + start += blks; + blks = 0; + addr += ATA_SECT_SIZE * blks; + } + } while (blks != 0); + + return blkcnt; +} + +int sata_port_status(int dev, int port) +{ + struct sata_port_regs *port_mmio; + struct ahci_probe_ent *probe_ent = NULL; + + if (dev < 0 || dev > (CONFIG_SYS_SATA_MAX_DEVICE - 1)) + return -EINVAL; + + if (sata_dev_desc[dev].priv == NULL) + return -ENODEV; + + probe_ent = (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + port_mmio = (struct sata_port_regs *)probe_ent->port[port].port_mmio; + + return readl(&(port_mmio->ssts)) & SATA_PORT_SSTS_DET_MASK; +} + +/* + * SATA interface between low level driver and command layer + */ +ulong sata_read(int dev, ulong blknr, lbaint_t blkcnt, void *buffer) +{ + u32 rc; + + if (sata_dev_desc[dev].lba48) + rc = ata_low_level_rw_lba48(dev, blknr, blkcnt, + buffer, READ_CMD); + else + rc = ata_low_level_rw_lba28(dev, blknr, blkcnt, + buffer, READ_CMD); + return rc; +} + +ulong sata_write(int dev, ulong blknr, lbaint_t blkcnt, const void *buffer) +{ + u32 rc; + struct ahci_probe_ent *probe_ent = + (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + u32 flags = probe_ent->flags; + + if (sata_dev_desc[dev].lba48) { + rc = ata_low_level_rw_lba48(dev, blknr, blkcnt, + buffer, WRITE_CMD); + if ((flags & SATA_FLAG_WCACHE) && + (flags & SATA_FLAG_FLUSH_EXT)) + dwc_ahsata_flush_cache_ext(dev); + } else { + rc = ata_low_level_rw_lba28(dev, blknr, blkcnt, + buffer, WRITE_CMD); + if ((flags & SATA_FLAG_WCACHE) && + (flags & SATA_FLAG_FLUSH)) + dwc_ahsata_flush_cache(dev); + } + return rc; +} + +int scan_sata(int dev) +{ + u8 serial[ATA_ID_SERNO_LEN + 1] = { 0 }; + u8 firmware[ATA_ID_FW_REV_LEN + 1] = { 0 }; + u8 product[ATA_ID_PROD_LEN + 1] = { 0 }; + u16 *id; + u64 n_sectors; + struct ahci_probe_ent *probe_ent = + (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + u8 port = probe_ent->hard_port_no; + struct blk_desc *pdev = &(sata_dev_desc[dev]); + + id = (u16 *)memalign(ARCH_DMA_MINALIGN, + roundup(ARCH_DMA_MINALIGN, + (ATA_ID_WORDS * 2))); + if (!id) { + printf("id malloc failed\n\r"); + return -1; + } + + /* Identify device to get information */ + dwc_ahsata_identify(dev, id); + + /* Serial number */ + ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial)); + memcpy(pdev->product, serial, sizeof(serial)); + + /* Firmware version */ + ata_id_c_string(id, firmware, ATA_ID_FW_REV, sizeof(firmware)); + memcpy(pdev->revision, firmware, sizeof(firmware)); + + /* Product model */ + ata_id_c_string(id, product, ATA_ID_PROD, sizeof(product)); + memcpy(pdev->vendor, product, sizeof(product)); + + /* Totoal sectors */ + n_sectors = ata_id_n_sectors(id); + pdev->lba = (u32)n_sectors; + + pdev->type = DEV_TYPE_HARDDISK; + pdev->blksz = ATA_SECT_SIZE; + pdev->lun = 0 ; + + /* Check if support LBA48 */ + if (ata_id_has_lba48(id)) { + pdev->lba48 = 1; + debug("Device support LBA48\n\r"); + } + + /* Get the NCQ queue depth from device */ + probe_ent->flags &= (~SATA_FLAG_Q_DEP_MASK); + probe_ent->flags |= ata_id_queue_depth(id); + + /* Get the xfer mode from device */ + dwc_ahsata_xfer_mode(dev, id); + + /* Get the write cache status from device */ + dwc_ahsata_init_wcache(dev, id); + + /* Set the xfer mode to highest speed */ + ahci_set_feature(dev, port); + + free((void *)id); + + dwc_ahsata_print_info(dev); + + is_ready = 1; + + return 0; +} diff --git a/drivers/ata/dwc_ahsata.h b/drivers/ata/dwc_ahsata.h new file mode 100644 index 0000000..caa2e50 --- /dev/null +++ b/drivers/ata/dwc_ahsata.h @@ -0,0 +1,320 @@ +/* + * Copyright (C) 2010 Freescale Semiconductor, Inc. + * Terry Lv + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __FSL_SATA_H__ +#define __FSL_SATA_H__ + +#define DWC_AHSATA_MAX_CMD_SLOTS 32 + +/* Max host controller numbers */ +#define SATA_HC_MAX_NUM 4 +/* Max command queue depth per host controller */ +#define DWC_AHSATA_HC_MAX_CMD 32 +/* Max port number per host controller */ +#define SATA_HC_MAX_PORT 16 + +/* Generic Host Register */ + +/* HBA Capabilities Register */ +#define SATA_HOST_CAP_S64A 0x80000000 +#define SATA_HOST_CAP_SNCQ 0x40000000 +#define SATA_HOST_CAP_SSNTF 0x20000000 +#define SATA_HOST_CAP_SMPS 0x10000000 +#define SATA_HOST_CAP_SSS 0x08000000 +#define SATA_HOST_CAP_SALP 0x04000000 +#define SATA_HOST_CAP_SAL 0x02000000 +#define SATA_HOST_CAP_SCLO 0x01000000 +#define SATA_HOST_CAP_ISS_MASK 0x00f00000 +#define SATA_HOST_CAP_ISS_OFFSET 20 +#define SATA_HOST_CAP_SNZO 0x00080000 +#define SATA_HOST_CAP_SAM 0x00040000 +#define SATA_HOST_CAP_SPM 0x00020000 +#define SATA_HOST_CAP_PMD 0x00008000 +#define SATA_HOST_CAP_SSC 0x00004000 +#define SATA_HOST_CAP_PSC 0x00002000 +#define SATA_HOST_CAP_NCS 0x00001f00 +#define SATA_HOST_CAP_CCCS 0x00000080 +#define SATA_HOST_CAP_EMS 0x00000040 +#define SATA_HOST_CAP_SXS 0x00000020 +#define SATA_HOST_CAP_NP_MASK 0x0000001f + +/* Global HBA Control Register */ +#define SATA_HOST_GHC_AE 0x80000000 +#define SATA_HOST_GHC_IE 0x00000002 +#define SATA_HOST_GHC_HR 0x00000001 + +/* Interrupt Status Register */ + +/* Ports Implemented Register */ + +/* AHCI Version Register */ +#define SATA_HOST_VS_MJR_MASK 0xffff0000 +#define SATA_HOST_VS_MJR_OFFSET 16 +#define SATA_HOST_VS_MJR_MNR 0x0000ffff + +/* Command Completion Coalescing Control */ +#define SATA_HOST_CCC_CTL_TV_MASK 0xffff0000 +#define SATA_HOST_CCC_CTL_TV_OFFSET 16 +#define SATA_HOST_CCC_CTL_CC_MASK 0x0000ff00 +#define SATA_HOST_CCC_CTL_CC_OFFSET 8 +#define SATA_HOST_CCC_CTL_INT_MASK 0x000000f8 +#define SATA_HOST_CCC_CTL_INT_OFFSET 3 +#define SATA_HOST_CCC_CTL_EN 0x00000001 + +/* Command Completion Coalescing Ports */ + +/* HBA Capabilities Extended Register */ +#define SATA_HOST_CAP2_APST 0x00000004 + +/* BIST Activate FIS Register */ +#define SATA_HOST_BISTAFR_NCP_MASK 0x0000ff00 +#define SATA_HOST_BISTAFR_NCP_OFFSET 8 +#define SATA_HOST_BISTAFR_PD_MASK 0x000000ff +#define SATA_HOST_BISTAFR_PD_OFFSET 0 + +/* BIST Control Register */ +#define SATA_HOST_BISTCR_FERLB 0x00100000 +#define SATA_HOST_BISTCR_TXO 0x00040000 +#define SATA_HOST_BISTCR_CNTCLR 0x00020000 +#define SATA_HOST_BISTCR_NEALB 0x00010000 +#define SATA_HOST_BISTCR_LLC_MASK 0x00000700 +#define SATA_HOST_BISTCR_LLC_OFFSET 8 +#define SATA_HOST_BISTCR_ERREN 0x00000040 +#define SATA_HOST_BISTCR_FLIP 0x00000020 +#define SATA_HOST_BISTCR_PV 0x00000010 +#define SATA_HOST_BISTCR_PATTERN_MASK 0x0000000f +#define SATA_HOST_BISTCR_PATTERN_OFFSET 0 + +/* BIST FIS Count Register */ + +/* BIST Status Register */ +#define SATA_HOST_BISTSR_FRAMERR_MASK 0x0000ffff +#define SATA_HOST_BISTSR_FRAMERR_OFFSET 0 +#define SATA_HOST_BISTSR_BRSTERR_MASK 0x00ff0000 +#define SATA_HOST_BISTSR_BRSTERR_OFFSET 16 + +/* BIST DWORD Error Count Register */ + +/* OOB Register*/ +#define SATA_HOST_OOBR_WE 0x80000000 +#define SATA_HOST_OOBR_cwMin_MASK 0x7f000000 +#define SATA_HOST_OOBR_cwMAX_MASK 0x00ff0000 +#define SATA_HOST_OOBR_ciMin_MASK 0x0000ff00 +#define SATA_HOST_OOBR_ciMax_MASK 0x000000ff + +/* Timer 1-ms Register */ + +/* Global Parameter 1 Register */ +#define SATA_HOST_GPARAM1R_ALIGN_M 0x80000000 +#define SATA_HOST_GPARAM1R_RX_BUFFER 0x40000000 +#define SATA_HOST_GPARAM1R_PHY_DATA_MASK 0x30000000 +#define SATA_HOST_GPARAM1R_PHY_RST 0x08000000 +#define SATA_HOST_GPARAM1R_PHY_CTRL_MASK 0x07e00000 +#define SATA_HOST_GPARAM1R_PHY_STAT_MASK 0x001f8000 +#define SATA_HOST_GPARAM1R_LATCH_M 0x00004000 +#define SATA_HOST_GPARAM1R_BIST_M 0x00002000 +#define SATA_HOST_GPARAM1R_PHY_TYPE 0x00001000 +#define SATA_HOST_GPARAM1R_RETURN_ERR 0x00000400 +#define SATA_HOST_GPARAM1R_AHB_ENDIAN_MASK 0x00000300 +#define SATA_HOST_GPARAM1R_S_HADDR 0X00000080 +#define SATA_HOST_GPARAM1R_M_HADDR 0X00000040 + +/* Global Parameter 2 Register */ +#define SATA_HOST_GPARAM2R_DEV_CP 0x00004000 +#define SATA_HOST_GPARAM2R_DEV_MP 0x00002000 +#define SATA_HOST_GPARAM2R_DEV_ENCODE_M 0x00001000 +#define SATA_HOST_GPARAM2R_RXOOB_CLK_M 0x00000800 +#define SATA_HOST_GPARAM2R_RXOOB_M 0x00000400 +#define SATA_HOST_GPARAM2R_TX_OOB_M 0x00000200 +#define SATA_HOST_GPARAM2R_RXOOB_CLK_MASK 0x000001ff + +/* Port Parameter Register */ +#define SATA_HOST_PPARAMR_TX_MEM_M 0x00000200 +#define SATA_HOST_PPARAMR_TX_MEM_S 0x00000100 +#define SATA_HOST_PPARAMR_RX_MEM_M 0x00000080 +#define SATA_HOST_PPARAMR_RX_MEM_S 0x00000040 +#define SATA_HOST_PPARAMR_TXFIFO_DEPTH_MASK 0x00000038 +#define SATA_HOST_PPARAMR_RXFIFO_DEPTH_MASK 0x00000007 + +/* Test Register */ +#define SATA_HOST_TESTR_PSEL_MASK 0x00070000 +#define SATA_HOST_TESTR_TEST_IF 0x00000001 + +/* Port Register Descriptions */ +/* Port# Command List Base Address Register */ +#define SATA_PORT_CLB_CLB_MASK 0xfffffc00 + +/* Port# Command List Base Address Upper 32-Bits Register */ + +/* Port# FIS Base Address Register */ +#define SATA_PORT_FB_FB_MASK 0xfffffff0 + +/* Port# FIS Base Address Upper 32-Bits Register */ + +/* Port# Interrupt Status Register */ +#define SATA_PORT_IS_CPDS 0x80000000 +#define SATA_PORT_IS_TFES 0x40000000 +#define SATA_PORT_IS_HBFS 0x20000000 +#define SATA_PORT_IS_HBDS 0x10000000 +#define SATA_PORT_IS_IFS 0x08000000 +#define SATA_PORT_IS_INFS 0x04000000 +#define SATA_PORT_IS_OFS 0x01000000 +#define SATA_PORT_IS_IPMS 0x00800000 +#define SATA_PORT_IS_PRCS 0x00400000 +#define SATA_PORT_IS_DMPS 0x00000080 +#define SATA_PORT_IS_PCS 0x00000040 +#define SATA_PORT_IS_DPS 0x00000020 +#define SATA_PORT_IS_UFS 0x00000010 +#define SATA_PORT_IS_SDBS 0x00000008 +#define SATA_PORT_IS_DSS 0x00000004 +#define SATA_PORT_IS_PSS 0x00000002 +#define SATA_PORT_IS_DHRS 0x00000001 + +/* Port# Interrupt Enable Register */ +#define SATA_PORT_IE_CPDE 0x80000000 +#define SATA_PORT_IE_TFEE 0x40000000 +#define SATA_PORT_IE_HBFE 0x20000000 +#define SATA_PORT_IE_HBDE 0x10000000 +#define SATA_PORT_IE_IFE 0x08000000 +#define SATA_PORT_IE_INFE 0x04000000 +#define SATA_PORT_IE_OFE 0x01000000 +#define SATA_PORT_IE_IPME 0x00800000 +#define SATA_PORT_IE_PRCE 0x00400000 +#define SATA_PORT_IE_DMPE 0x00000080 +#define SATA_PORT_IE_PCE 0x00000040 +#define SATA_PORT_IE_DPE 0x00000020 +#define SATA_PORT_IE_UFE 0x00000010 +#define SATA_PORT_IE_SDBE 0x00000008 +#define SATA_PORT_IE_DSE 0x00000004 +#define SATA_PORT_IE_PSE 0x00000002 +#define SATA_PORT_IE_DHRE 0x00000001 + +/* Port# Command Register */ +#define SATA_PORT_CMD_ICC_MASK 0xf0000000 +#define SATA_PORT_CMD_ASP 0x08000000 +#define SATA_PORT_CMD_ALPE 0x04000000 +#define SATA_PORT_CMD_DLAE 0x02000000 +#define SATA_PORT_CMD_ATAPI 0x01000000 +#define SATA_PORT_CMD_APSTE 0x00800000 +#define SATA_PORT_CMD_ESP 0x00200000 +#define SATA_PORT_CMD_CPD 0x00100000 +#define SATA_PORT_CMD_MPSP 0x00080000 +#define SATA_PORT_CMD_HPCP 0x00040000 +#define SATA_PORT_CMD_PMA 0x00020000 +#define SATA_PORT_CMD_CPS 0x00010000 +#define SATA_PORT_CMD_CR 0x00008000 +#define SATA_PORT_CMD_FR 0x00004000 +#define SATA_PORT_CMD_MPSS 0x00002000 +#define SATA_PORT_CMD_CCS_MASK 0x00001f00 +#define SATA_PORT_CMD_FRE 0x00000010 +#define SATA_PORT_CMD_CLO 0x00000008 +#define SATA_PORT_CMD_POD 0x00000004 +#define SATA_PORT_CMD_SUD 0x00000002 +#define SATA_PORT_CMD_ST 0x00000001 + +/* Port# Task File Data Register */ +#define SATA_PORT_TFD_ERR_MASK 0x0000ff00 +#define SATA_PORT_TFD_STS_MASK 0x000000ff +#define SATA_PORT_TFD_STS_ERR 0x00000001 +#define SATA_PORT_TFD_STS_DRQ 0x00000008 +#define SATA_PORT_TFD_STS_BSY 0x00000080 + +/* Port# Signature Register */ + +/* Port# Serial ATA Status {SStatus} Register */ +#define SATA_PORT_SSTS_IPM_MASK 0x00000f00 +#define SATA_PORT_SSTS_SPD_MASK 0x000000f0 +#define SATA_PORT_SSTS_DET_MASK 0x0000000f + +/* Port# Serial ATA Control {SControl} Register */ +#define SATA_PORT_SCTL_IPM_MASK 0x00000f00 +#define SATA_PORT_SCTL_SPD_MASK 0x000000f0 +#define SATA_PORT_SCTL_DET_MASK 0x0000000f + +/* Port# Serial ATA Error {SError} Register */ +#define SATA_PORT_SERR_DIAG_X 0x04000000 +#define SATA_PORT_SERR_DIAG_F 0x02000000 +#define SATA_PORT_SERR_DIAG_T 0x01000000 +#define SATA_PORT_SERR_DIAG_S 0x00800000 +#define SATA_PORT_SERR_DIAG_H 0x00400000 +#define SATA_PORT_SERR_DIAG_C 0x00200000 +#define SATA_PORT_SERR_DIAG_D 0x00100000 +#define SATA_PORT_SERR_DIAG_B 0x00080000 +#define SATA_PORT_SERR_DIAG_W 0x00040000 +#define SATA_PORT_SERR_DIAG_I 0x00020000 +#define SATA_PORT_SERR_DIAG_N 0x00010000 +#define SATA_PORT_SERR_ERR_E 0x00000800 +#define SATA_PORT_SERR_ERR_P 0x00000400 +#define SATA_PORT_SERR_ERR_C 0x00000200 +#define SATA_PORT_SERR_ERR_T 0x00000100 +#define SATA_PORT_SERR_ERR_M 0x00000002 +#define SATA_PORT_SERR_ERR_I 0x00000001 + +/* Port# Serial ATA Active {SActive} Register */ + +/* Port# Command Issue Register */ + +/* Port# Serial ATA Notification Register */ + +/* Port# DMA Control Register */ +#define SATA_PORT_DMACR_RXABL_MASK 0x0000f000 +#define SATA_PORT_DMACR_TXABL_MASK 0x00000f00 +#define SATA_PORT_DMACR_RXTS_MASK 0x000000f0 +#define SATA_PORT_DMACR_TXTS_MASK 0x0000000f + +/* Port# PHY Control Register */ + +/* Port# PHY Status Register */ + +#define SATA_HC_CMD_HDR_ENTRY_SIZE sizeof(struct cmd_hdr_entry) + +/* DW0 +*/ +#define CMD_HDR_DI_CFL_MASK 0x0000001f +#define CMD_HDR_DI_CFL_OFFSET 0 +#define CMD_HDR_DI_A 0x00000020 +#define CMD_HDR_DI_W 0x00000040 +#define CMD_HDR_DI_P 0x00000080 +#define CMD_HDR_DI_R 0x00000100 +#define CMD_HDR_DI_B 0x00000200 +#define CMD_HDR_DI_C 0x00000400 +#define CMD_HDR_DI_PMP_MASK 0x0000f000 +#define CMD_HDR_DI_PMP_OFFSET 12 +#define CMD_HDR_DI_PRDTL 0xffff0000 +#define CMD_HDR_DI_PRDTL_OFFSET 16 + +/* prde_fis_len +*/ +#define CMD_HDR_PRD_ENTRY_SHIFT 16 +#define CMD_HDR_PRD_ENTRY_MASK 0x003f0000 +#define CMD_HDR_FIS_LEN_SHIFT 2 + +/* attribute +*/ +#define CMD_HDR_ATTR_RES 0x00000800 /* Reserved bit, should be 1 */ +#define CMD_HDR_ATTR_VBIST 0x00000400 /* Vendor BIST */ +/* Snoop enable for all descriptor */ +#define CMD_HDR_ATTR_SNOOP 0x00000200 +#define CMD_HDR_ATTR_FPDMA 0x00000100 /* FPDMA queued command */ +#define CMD_HDR_ATTR_RESET 0x00000080 /* Reset - a SRST or device reset */ +/* BIST - require the host to enter BIST mode */ +#define CMD_HDR_ATTR_BIST 0x00000040 +#define CMD_HDR_ATTR_ATAPI 0x00000020 /* ATAPI command */ +#define CMD_HDR_ATTR_TAG 0x0000001f /* TAG mask */ + +#define FLAGS_DMA 0x00000000 +#define FLAGS_FPDMA 0x00000001 + +#define SATA_FLAG_Q_DEP_MASK 0x0000000f +#define SATA_FLAG_WCACHE 0x00000100 +#define SATA_FLAG_FLUSH 0x00000200 +#define SATA_FLAG_FLUSH_EXT 0x00000400 + +#define READ_CMD 0 +#define WRITE_CMD 1 + +#endif /* __FSL_SATA_H__ */ diff --git a/drivers/ata/fsl_sata.c b/drivers/ata/fsl_sata.c new file mode 100644 index 0000000..31f7fab --- /dev/null +++ b/drivers/ata/fsl_sata.c @@ -0,0 +1,854 @@ +/* + * Copyright (C) 2008,2010 Freescale Semiconductor, Inc. + * Dave Liu + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "fsl_sata.h" + +#ifndef CONFIG_SYS_SATA1_FLAGS + #define CONFIG_SYS_SATA1_FLAGS FLAGS_DMA +#endif +#ifndef CONFIG_SYS_SATA2_FLAGS + #define CONFIG_SYS_SATA2_FLAGS FLAGS_DMA +#endif + +static struct fsl_sata_info fsl_sata_info[] = { +#ifdef CONFIG_SATA1 + {CONFIG_SYS_SATA1, CONFIG_SYS_SATA1_FLAGS}, +#else + {0, 0}, +#endif +#ifdef CONFIG_SATA2 + {CONFIG_SYS_SATA2, CONFIG_SYS_SATA2_FLAGS}, +#else + {0, 0}, +#endif +}; + +static inline void sdelay(unsigned long sec) +{ + unsigned long i; + for (i = 0; i < sec; i++) + mdelay(1000); +} + +static void fsl_sata_dump_sfis(struct sata_fis_d2h *s) +{ + printf("Status FIS dump:\n\r"); + printf("fis_type: %02x\n\r", s->fis_type); + printf("pm_port_i: %02x\n\r", s->pm_port_i); + printf("status: %02x\n\r", s->status); + printf("error: %02x\n\r", s->error); + printf("lba_low: %02x\n\r", s->lba_low); + printf("lba_mid: %02x\n\r", s->lba_mid); + printf("lba_high: %02x\n\r", s->lba_high); + printf("device: %02x\n\r", s->device); + printf("lba_low_exp: %02x\n\r", s->lba_low_exp); + printf("lba_mid_exp: %02x\n\r", s->lba_mid_exp); + printf("lba_high_exp: %02x\n\r", s->lba_high_exp); + printf("res1: %02x\n\r", s->res1); + printf("sector_count: %02x\n\r", s->sector_count); + printf("sector_count_exp: %02x\n\r", s->sector_count_exp); +} + +static int ata_wait_register(unsigned __iomem *addr, u32 mask, + u32 val, u32 timeout_msec) +{ + int i; + u32 temp; + + for (i = 0; (((temp = in_le32(addr)) & mask) != val) + && i < timeout_msec; i++) + mdelay(1); + return (i < timeout_msec) ? 0 : -1; +} + +int init_sata(int dev) +{ + u32 length, align; + cmd_hdr_tbl_t *cmd_hdr; + u32 cda; + u32 val32; + fsl_sata_reg_t __iomem *reg; + u32 sig; + int i; + fsl_sata_t *sata; + + if (dev < 0 || dev > (CONFIG_SYS_SATA_MAX_DEVICE - 1)) { + printf("the sata index %d is out of ranges\n\r", dev); + return -1; + } + +#ifdef CONFIG_MPC85xx + if ((dev == 0) && (!is_serdes_configured(SATA1))) { + printf("SATA%d [dev = %d] is not enabled\n", dev+1, dev); + return -1; + } + if ((dev == 1) && (!is_serdes_configured(SATA2))) { + printf("SATA%d [dev = %d] is not enabled\n", dev+1, dev); + return -1; + } +#endif + + /* Allocate SATA device driver struct */ + sata = (fsl_sata_t *)malloc(sizeof(fsl_sata_t)); + if (!sata) { + printf("alloc the sata device struct failed\n\r"); + return -1; + } + /* Zero all of the device driver struct */ + memset((void *)sata, 0, sizeof(fsl_sata_t)); + + /* Save the private struct to block device struct */ + sata_dev_desc[dev].priv = (void *)sata; + + snprintf(sata->name, 12, "SATA%d", dev); + + /* Set the controller register base address to device struct */ + reg = (fsl_sata_reg_t *)(fsl_sata_info[dev].sata_reg_base); + sata->reg_base = reg; + + /* Allocate the command header table, 4 bytes aligned */ + length = sizeof(struct cmd_hdr_tbl); + align = SATA_HC_CMD_HDR_TBL_ALIGN; + sata->cmd_hdr_tbl_offset = (void *)malloc(length + align); + if (!sata->cmd_hdr_tbl_offset) { + printf("alloc the command header failed\n\r"); + return -1; + } + + cmd_hdr = (cmd_hdr_tbl_t *)(((u32)sata->cmd_hdr_tbl_offset + align) + & ~(align - 1)); + sata->cmd_hdr = cmd_hdr; + + /* Zero all of the command header table */ + memset((void *)sata->cmd_hdr_tbl_offset, 0, length + align); + + /* Allocate command descriptor for all command */ + length = sizeof(struct cmd_desc) * SATA_HC_MAX_CMD; + align = SATA_HC_CMD_DESC_ALIGN; + sata->cmd_desc_offset = (void *)malloc(length + align); + if (!sata->cmd_desc_offset) { + printf("alloc the command descriptor failed\n\r"); + return -1; + } + sata->cmd_desc = (cmd_desc_t *)(((u32)sata->cmd_desc_offset + align) + & ~(align - 1)); + /* Zero all of command descriptor */ + memset((void *)sata->cmd_desc_offset, 0, length + align); + + /* Link the command descriptor to command header */ + for (i = 0; i < SATA_HC_MAX_CMD; i++) { + cda = ((u32)sata->cmd_desc + SATA_HC_CMD_DESC_SIZE * i) + & ~(CMD_HDR_CDA_ALIGN - 1); + cmd_hdr->cmd_slot[i].cda = cpu_to_le32(cda); + } + + /* To have safe state, force the controller offline */ + val32 = in_le32(®->hcontrol); + val32 &= ~HCONTROL_ONOFF; + val32 |= HCONTROL_FORCE_OFFLINE; + out_le32(®->hcontrol, val32); + + /* Wait the controller offline */ + ata_wait_register(®->hstatus, HSTATUS_ONOFF, 0, 1000); + + /* Set the command header base address to CHBA register to tell DMA */ + out_le32(®->chba, (u32)cmd_hdr & ~0x3); + + /* Snoop for the command header */ + val32 = in_le32(®->hcontrol); + val32 |= HCONTROL_HDR_SNOOP; + out_le32(®->hcontrol, val32); + + /* Disable all of interrupts */ + val32 = in_le32(®->hcontrol); + val32 &= ~HCONTROL_INT_EN_ALL; + out_le32(®->hcontrol, val32); + + /* Clear all of interrupts */ + val32 = in_le32(®->hstatus); + out_le32(®->hstatus, val32); + + /* Set the ICC, no interrupt coalescing */ + out_le32(®->icc, 0x01000000); + + /* No PM attatched, the SATA device direct connect */ + out_le32(®->cqpmp, 0); + + /* Clear SError register */ + val32 = in_le32(®->serror); + out_le32(®->serror, val32); + + /* Clear CER register */ + val32 = in_le32(®->cer); + out_le32(®->cer, val32); + + /* Clear DER register */ + val32 = in_le32(®->der); + out_le32(®->der, val32); + + /* No device detection or initialization action requested */ + out_le32(®->scontrol, 0x00000300); + + /* Configure the transport layer, default value */ + out_le32(®->transcfg, 0x08000016); + + /* Configure the link layer, default value */ + out_le32(®->linkcfg, 0x0000ff34); + + /* Bring the controller online */ + val32 = in_le32(®->hcontrol); + val32 |= HCONTROL_ONOFF; + out_le32(®->hcontrol, val32); + + mdelay(100); + + /* print sata device name */ + if (!dev) + printf("%s ", sata->name); + else + printf(" %s ", sata->name); + + /* Wait PHY RDY signal changed for 500ms */ + ata_wait_register(®->hstatus, HSTATUS_PHY_RDY, + HSTATUS_PHY_RDY, 500); + + /* Check PHYRDY */ + val32 = in_le32(®->hstatus); + if (val32 & HSTATUS_PHY_RDY) { + sata->link = 1; + } else { + sata->link = 0; + printf("(No RDY)\n\r"); + return -1; + } + + /* Wait for signature updated, which is 1st D2H */ + ata_wait_register(®->hstatus, HSTATUS_SIGNATURE, + HSTATUS_SIGNATURE, 10000); + + if (val32 & HSTATUS_SIGNATURE) { + sig = in_le32(®->sig); + debug("Signature updated, the sig =%08x\n\r", sig); + sata->ata_device_type = ata_dev_classify(sig); + } + + /* Check the speed */ + val32 = in_le32(®->sstatus); + if ((val32 & SSTATUS_SPD_MASK) == SSTATUS_SPD_GEN1) + printf("(1.5 Gbps)\n\r"); + else if ((val32 & SSTATUS_SPD_MASK) == SSTATUS_SPD_GEN2) + printf("(3 Gbps)\n\r"); + + return 0; +} + +int reset_sata(int dev) +{ + return 0; +} + +static void fsl_sata_dump_regs(fsl_sata_reg_t __iomem *reg) +{ + printf("\n\rSATA: %08x\n\r", (u32)reg); + printf("CQR: %08x\n\r", in_le32(®->cqr)); + printf("CAR: %08x\n\r", in_le32(®->car)); + printf("CCR: %08x\n\r", in_le32(®->ccr)); + printf("CER: %08x\n\r", in_le32(®->cer)); + printf("CQR: %08x\n\r", in_le32(®->cqr)); + printf("DER: %08x\n\r", in_le32(®->der)); + printf("CHBA: %08x\n\r", in_le32(®->chba)); + printf("HStatus: %08x\n\r", in_le32(®->hstatus)); + printf("HControl: %08x\n\r", in_le32(®->hcontrol)); + printf("CQPMP: %08x\n\r", in_le32(®->cqpmp)); + printf("SIG: %08x\n\r", in_le32(®->sig)); + printf("ICC: %08x\n\r", in_le32(®->icc)); + printf("SStatus: %08x\n\r", in_le32(®->sstatus)); + printf("SError: %08x\n\r", in_le32(®->serror)); + printf("SControl: %08x\n\r", in_le32(®->scontrol)); + printf("SNotification: %08x\n\r", in_le32(®->snotification)); + printf("TransCfg: %08x\n\r", in_le32(®->transcfg)); + printf("TransStatus: %08x\n\r", in_le32(®->transstatus)); + printf("LinkCfg: %08x\n\r", in_le32(®->linkcfg)); + printf("LinkCfg1: %08x\n\r", in_le32(®->linkcfg1)); + printf("LinkCfg2: %08x\n\r", in_le32(®->linkcfg2)); + printf("LinkStatus: %08x\n\r", in_le32(®->linkstatus)); + printf("LinkStatus1: %08x\n\r", in_le32(®->linkstatus1)); + printf("PhyCtrlCfg: %08x\n\r", in_le32(®->phyctrlcfg)); + printf("SYSPR: %08x\n\r", in_be32(®->syspr)); +} + +static int fsl_ata_exec_ata_cmd(struct fsl_sata *sata, struct sata_fis_h2d *cfis, + int is_ncq, int tag, u8 *buffer, u32 len) +{ + cmd_hdr_entry_t *cmd_hdr; + cmd_desc_t *cmd_desc; + sata_fis_h2d_t *h2d; + prd_entry_t *prde; + u32 ext_c_ddc; + u32 prde_count; + u32 val32; + u32 ttl; + fsl_sata_reg_t __iomem *reg = sata->reg_base; + int i; + + /* Check xfer length */ + if (len > SATA_HC_MAX_XFER_LEN) { + printf("max transfer length is 64MB\n\r"); + return 0; + } + + /* Setup the command descriptor */ + cmd_desc = sata->cmd_desc + tag; + + /* Get the pointer cfis of command descriptor */ + h2d = (sata_fis_h2d_t *)cmd_desc->cfis; + + /* Zero the cfis of command descriptor */ + memset((void *)h2d, 0, SATA_HC_CMD_DESC_CFIS_SIZE); + + /* Copy the cfis from user to command descriptor */ + h2d->fis_type = cfis->fis_type; + h2d->pm_port_c = cfis->pm_port_c; + h2d->command = cfis->command; + + h2d->features = cfis->features; + h2d->features_exp = cfis->features_exp; + + h2d->lba_low = cfis->lba_low; + h2d->lba_mid = cfis->lba_mid; + h2d->lba_high = cfis->lba_high; + h2d->lba_low_exp = cfis->lba_low_exp; + h2d->lba_mid_exp = cfis->lba_mid_exp; + h2d->lba_high_exp = cfis->lba_high_exp; + + if (!is_ncq) { + h2d->sector_count = cfis->sector_count; + h2d->sector_count_exp = cfis->sector_count_exp; + } else { /* NCQ */ + h2d->sector_count = (u8)(tag << 3); + } + + h2d->device = cfis->device; + h2d->control = cfis->control; + + /* Setup the PRD table */ + prde = (prd_entry_t *)cmd_desc->prdt; + memset((void *)prde, 0, sizeof(struct prdt)); + + prde_count = 0; + ttl = len; + for (i = 0; i < SATA_HC_MAX_PRD_DIRECT; i++) { + if (!len) + break; + prde->dba = cpu_to_le32((u32)buffer & ~0x3); + debug("dba = %08x\n\r", (u32)buffer); + + if (len < PRD_ENTRY_MAX_XFER_SZ) { + ext_c_ddc = PRD_ENTRY_DATA_SNOOP | len; + debug("ext_c_ddc1 = %08x, len = %08x\n\r", ext_c_ddc, len); + prde->ext_c_ddc = cpu_to_le32(ext_c_ddc); + prde_count++; + prde++; + break; + } else { + ext_c_ddc = PRD_ENTRY_DATA_SNOOP; /* 4M bytes */ + debug("ext_c_ddc2 = %08x, len = %08x\n\r", ext_c_ddc, len); + prde->ext_c_ddc = cpu_to_le32(ext_c_ddc); + buffer += PRD_ENTRY_MAX_XFER_SZ; + len -= PRD_ENTRY_MAX_XFER_SZ; + prde_count++; + prde++; + } + } + + /* Setup the command slot of cmd hdr */ + cmd_hdr = (cmd_hdr_entry_t *)&sata->cmd_hdr->cmd_slot[tag]; + + cmd_hdr->cda = cpu_to_le32((u32)cmd_desc & ~0x3); + + val32 = prde_count << CMD_HDR_PRD_ENTRY_SHIFT; + val32 |= sizeof(sata_fis_h2d_t); + cmd_hdr->prde_fis_len = cpu_to_le32(val32); + + cmd_hdr->ttl = cpu_to_le32(ttl); + + if (!is_ncq) { + val32 = CMD_HDR_ATTR_RES | CMD_HDR_ATTR_SNOOP; + } else { + val32 = CMD_HDR_ATTR_RES | CMD_HDR_ATTR_SNOOP | CMD_HDR_ATTR_FPDMA; + } + + tag &= CMD_HDR_ATTR_TAG; + val32 |= tag; + + debug("attribute = %08x\n\r", val32); + cmd_hdr->attribute = cpu_to_le32(val32); + + /* Make sure cmd desc and cmd slot valid before command issue */ + sync(); + + /* PMP*/ + val32 = (u32)(h2d->pm_port_c & 0x0f); + out_le32(®->cqpmp, val32); + + /* Wait no active */ + if (ata_wait_register(®->car, (1 << tag), 0, 10000)) + printf("Wait no active time out\n\r"); + + /* Issue command */ + if (!(in_le32(®->cqr) & (1 << tag))) { + val32 = 1 << tag; + out_le32(®->cqr, val32); + } + + /* Wait command completed for 10s */ + if (ata_wait_register(®->ccr, (1 << tag), (1 << tag), 10000)) { + if (!is_ncq) + printf("Non-NCQ command time out\n\r"); + else + printf("NCQ command time out\n\r"); + } + + val32 = in_le32(®->cer); + + if (val32) { + u32 der; + fsl_sata_dump_sfis((struct sata_fis_d2h *)cmd_desc->sfis); + printf("CE at device\n\r"); + fsl_sata_dump_regs(reg); + der = in_le32(®->der); + out_le32(®->cer, val32); + out_le32(®->der, der); + } + + /* Clear complete flags */ + val32 = in_le32(®->ccr); + out_le32(®->ccr, val32); + + return len; +} + +static int fsl_ata_exec_reset_cmd(struct fsl_sata *sata, struct sata_fis_h2d *cfis, + int tag, u8 *buffer, u32 len) +{ + return 0; +} + +static int fsl_sata_exec_cmd(struct fsl_sata *sata, struct sata_fis_h2d *cfis, + enum cmd_type command_type, int tag, u8 *buffer, u32 len) +{ + int rc; + + if (tag > SATA_HC_MAX_CMD || tag < 0) { + printf("tag is out of range, tag=%d\n\r", tag); + return -1; + } + + switch (command_type) { + case CMD_ATA: + rc = fsl_ata_exec_ata_cmd(sata, cfis, 0, tag, buffer, len); + return rc; + case CMD_RESET: + rc = fsl_ata_exec_reset_cmd(sata, cfis, tag, buffer, len); + return rc; + case CMD_NCQ: + rc = fsl_ata_exec_ata_cmd(sata, cfis, 1, tag, buffer, len); + return rc; + case CMD_ATAPI: + case CMD_VENDOR_BIST: + case CMD_BIST: + printf("not support now\n\r"); + return -1; + default: + break; + } + + return -1; +} + +static void fsl_sata_identify(int dev, u16 *id) +{ + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + struct sata_fis_h2d h2d, *cfis = &h2d; + + memset(cfis, 0, sizeof(struct sata_fis_h2d)); + + cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; + cfis->pm_port_c = 0x80; /* is command */ + cfis->command = ATA_CMD_ID_ATA; + + fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, (u8 *)id, ATA_ID_WORDS * 2); + ata_swap_buf_le16(id, ATA_ID_WORDS); +} + +static void fsl_sata_xfer_mode(int dev, u16 *id) +{ + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + + sata->pio = id[ATA_ID_PIO_MODES]; + sata->mwdma = id[ATA_ID_MWDMA_MODES]; + sata->udma = id[ATA_ID_UDMA_MODES]; + debug("pio %04x, mwdma %04x, udma %04x\n\r", sata->pio, sata->mwdma, sata->udma); +} + +static void fsl_sata_set_features(int dev) +{ + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + struct sata_fis_h2d h2d, *cfis = &h2d; + u8 udma_cap; + + memset(cfis, 0, sizeof(struct sata_fis_h2d)); + + cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; + cfis->pm_port_c = 0x80; /* is command */ + cfis->command = ATA_CMD_SET_FEATURES; + cfis->features = SETFEATURES_XFER; + + /* First check the device capablity */ + udma_cap = (u8)(sata->udma & 0xff); + debug("udma_cap %02x\n\r", udma_cap); + + if (udma_cap == ATA_UDMA6) + cfis->sector_count = XFER_UDMA_6; + if (udma_cap == ATA_UDMA5) + cfis->sector_count = XFER_UDMA_5; + if (udma_cap == ATA_UDMA4) + cfis->sector_count = XFER_UDMA_4; + if (udma_cap == ATA_UDMA3) + cfis->sector_count = XFER_UDMA_3; + + fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, NULL, 0); +} + +static u32 fsl_sata_rw_cmd(int dev, u32 start, u32 blkcnt, u8 *buffer, int is_write) +{ + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + struct sata_fis_h2d h2d, *cfis = &h2d; + u32 block; + + block = start; + + memset(cfis, 0, sizeof(struct sata_fis_h2d)); + + cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; + cfis->pm_port_c = 0x80; /* is command */ + cfis->command = (is_write) ? ATA_CMD_WRITE : ATA_CMD_READ; + cfis->device = ATA_LBA; + + cfis->device |= (block >> 24) & 0xf; + cfis->lba_high = (block >> 16) & 0xff; + cfis->lba_mid = (block >> 8) & 0xff; + cfis->lba_low = block & 0xff; + cfis->sector_count = (u8)(blkcnt & 0xff); + + fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, buffer, ATA_SECT_SIZE * blkcnt); + return blkcnt; +} + +static void fsl_sata_flush_cache(int dev) +{ + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + struct sata_fis_h2d h2d, *cfis = &h2d; + + memset(cfis, 0, sizeof(struct sata_fis_h2d)); + + cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; + cfis->pm_port_c = 0x80; /* is command */ + cfis->command = ATA_CMD_FLUSH; + + fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, NULL, 0); +} + +static u32 fsl_sata_rw_cmd_ext(int dev, u32 start, u32 blkcnt, u8 *buffer, int is_write) +{ + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + struct sata_fis_h2d h2d, *cfis = &h2d; + u64 block; + + block = (u64)start; + + memset(cfis, 0, sizeof(struct sata_fis_h2d)); + + cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; + cfis->pm_port_c = 0x80; /* is command */ + + cfis->command = (is_write) ? ATA_CMD_WRITE_EXT + : ATA_CMD_READ_EXT; + + cfis->lba_high_exp = (block >> 40) & 0xff; + cfis->lba_mid_exp = (block >> 32) & 0xff; + cfis->lba_low_exp = (block >> 24) & 0xff; + cfis->lba_high = (block >> 16) & 0xff; + cfis->lba_mid = (block >> 8) & 0xff; + cfis->lba_low = block & 0xff; + cfis->device = ATA_LBA; + cfis->sector_count_exp = (blkcnt >> 8) & 0xff; + cfis->sector_count = blkcnt & 0xff; + + fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, buffer, ATA_SECT_SIZE * blkcnt); + return blkcnt; +} + +static u32 fsl_sata_rw_ncq_cmd(int dev, u32 start, u32 blkcnt, u8 *buffer, + int is_write) +{ + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + struct sata_fis_h2d h2d, *cfis = &h2d; + int ncq_channel; + u64 block; + + if (sata->lba48 != 1) { + printf("execute FPDMA command on non-LBA48 hard disk\n\r"); + return -1; + } + + block = (u64)start; + + memset(cfis, 0, sizeof(struct sata_fis_h2d)); + + cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; + cfis->pm_port_c = 0x80; /* is command */ + + cfis->command = (is_write) ? ATA_CMD_FPDMA_WRITE + : ATA_CMD_FPDMA_READ; + + cfis->lba_high_exp = (block >> 40) & 0xff; + cfis->lba_mid_exp = (block >> 32) & 0xff; + cfis->lba_low_exp = (block >> 24) & 0xff; + cfis->lba_high = (block >> 16) & 0xff; + cfis->lba_mid = (block >> 8) & 0xff; + cfis->lba_low = block & 0xff; + + cfis->device = ATA_LBA; + cfis->features_exp = (blkcnt >> 8) & 0xff; + cfis->features = blkcnt & 0xff; + + if (sata->queue_depth >= SATA_HC_MAX_CMD) + ncq_channel = SATA_HC_MAX_CMD - 1; + else + ncq_channel = sata->queue_depth - 1; + + /* Use the latest queue */ + fsl_sata_exec_cmd(sata, cfis, CMD_NCQ, ncq_channel, buffer, ATA_SECT_SIZE * blkcnt); + return blkcnt; +} + +static void fsl_sata_flush_cache_ext(int dev) +{ + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + struct sata_fis_h2d h2d, *cfis = &h2d; + + memset(cfis, 0, sizeof(struct sata_fis_h2d)); + + cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; + cfis->pm_port_c = 0x80; /* is command */ + cfis->command = ATA_CMD_FLUSH_EXT; + + fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, NULL, 0); +} + +static void fsl_sata_init_wcache(int dev, u16 *id) +{ + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + + if (ata_id_has_wcache(id) && ata_id_wcache_enabled(id)) + sata->wcache = 1; + if (ata_id_has_flush(id)) + sata->flush = 1; + if (ata_id_has_flush_ext(id)) + sata->flush_ext = 1; +} + +static int fsl_sata_get_wcache(int dev) +{ + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + return sata->wcache; +} + +static int fsl_sata_get_flush(int dev) +{ + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + return sata->flush; +} + +static int fsl_sata_get_flush_ext(int dev) +{ + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + return sata->flush_ext; +} + +static u32 ata_low_level_rw_lba48(int dev, u32 blknr, lbaint_t blkcnt, + const void *buffer, int is_write) +{ + u32 start, blks; + u8 *addr; + int max_blks; + + start = blknr; + blks = blkcnt; + addr = (u8 *)buffer; + + max_blks = ATA_MAX_SECTORS_LBA48; + do { + if (blks > max_blks) { + if (fsl_sata_info[dev].flags != FLAGS_FPDMA) + fsl_sata_rw_cmd_ext(dev, start, max_blks, addr, is_write); + else + fsl_sata_rw_ncq_cmd(dev, start, max_blks, addr, is_write); + start += max_blks; + blks -= max_blks; + addr += ATA_SECT_SIZE * max_blks; + } else { + if (fsl_sata_info[dev].flags != FLAGS_FPDMA) + fsl_sata_rw_cmd_ext(dev, start, blks, addr, is_write); + else + fsl_sata_rw_ncq_cmd(dev, start, blks, addr, is_write); + start += blks; + blks = 0; + addr += ATA_SECT_SIZE * blks; + } + } while (blks != 0); + + return blkcnt; +} + +static u32 ata_low_level_rw_lba28(int dev, u32 blknr, u32 blkcnt, + const void *buffer, int is_write) +{ + u32 start, blks; + u8 *addr; + int max_blks; + + start = blknr; + blks = blkcnt; + addr = (u8 *)buffer; + + max_blks = ATA_MAX_SECTORS; + do { + if (blks > max_blks) { + fsl_sata_rw_cmd(dev, start, max_blks, addr, is_write); + start += max_blks; + blks -= max_blks; + addr += ATA_SECT_SIZE * max_blks; + } else { + fsl_sata_rw_cmd(dev, start, blks, addr, is_write); + start += blks; + blks = 0; + addr += ATA_SECT_SIZE * blks; + } + } while (blks != 0); + + return blkcnt; +} + +/* + * SATA interface between low level driver and command layer + */ +ulong sata_read(int dev, ulong blknr, lbaint_t blkcnt, void *buffer) +{ + u32 rc; + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + + if (sata->lba48) + rc = ata_low_level_rw_lba48(dev, blknr, blkcnt, buffer, READ_CMD); + else + rc = ata_low_level_rw_lba28(dev, blknr, blkcnt, buffer, READ_CMD); + return rc; +} + +ulong sata_write(int dev, ulong blknr, lbaint_t blkcnt, const void *buffer) +{ + u32 rc; + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + + if (sata->lba48) { + rc = ata_low_level_rw_lba48(dev, blknr, blkcnt, buffer, WRITE_CMD); + if (fsl_sata_get_wcache(dev) && fsl_sata_get_flush_ext(dev)) + fsl_sata_flush_cache_ext(dev); + } else { + rc = ata_low_level_rw_lba28(dev, blknr, blkcnt, buffer, WRITE_CMD); + if (fsl_sata_get_wcache(dev) && fsl_sata_get_flush(dev)) + fsl_sata_flush_cache(dev); + } + return rc; +} + +int scan_sata(int dev) +{ + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + unsigned char serial[ATA_ID_SERNO_LEN + 1]; + unsigned char firmware[ATA_ID_FW_REV_LEN + 1]; + unsigned char product[ATA_ID_PROD_LEN + 1]; + u16 *id; + u64 n_sectors; + + /* if no detected link */ + if (!sata->link) + return -1; + + id = (u16 *)malloc(ATA_ID_WORDS * 2); + if (!id) { + printf("id malloc failed\n\r"); + return -1; + } + + /* Identify device to get information */ + fsl_sata_identify(dev, id); + + /* Serial number */ + ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial)); + memcpy(sata_dev_desc[dev].product, serial, sizeof(serial)); + + /* Firmware version */ + ata_id_c_string(id, firmware, ATA_ID_FW_REV, sizeof(firmware)); + memcpy(sata_dev_desc[dev].revision, firmware, sizeof(firmware)); + + /* Product model */ + ata_id_c_string(id, product, ATA_ID_PROD, sizeof(product)); + memcpy(sata_dev_desc[dev].vendor, product, sizeof(product)); + + /* Totoal sectors */ + n_sectors = ata_id_n_sectors(id); + sata_dev_desc[dev].lba = (u32)n_sectors; + +#ifdef CONFIG_LBA48 + /* Check if support LBA48 */ + if (ata_id_has_lba48(id)) { + sata->lba48 = 1; + debug("Device support LBA48\n\r"); + } else + debug("Device supports LBA28\n\r"); +#endif + + /* Get the NCQ queue depth from device */ + sata->queue_depth = ata_id_queue_depth(id); + + /* Get the xfer mode from device */ + fsl_sata_xfer_mode(dev, id); + + /* Get the write cache status from device */ + fsl_sata_init_wcache(dev, id); + + /* Set the xfer mode to highest speed */ + fsl_sata_set_features(dev); +#ifdef DEBUG + fsl_sata_identify(dev, id); + ata_dump_id(id); +#endif + free((void *)id); + return 0; +} diff --git a/drivers/ata/fsl_sata.h b/drivers/ata/fsl_sata.h new file mode 100644 index 0000000..18d679e --- /dev/null +++ b/drivers/ata/fsl_sata.h @@ -0,0 +1,321 @@ +/* + * Copyright (C) 2007-2008 Freescale Semiconductor, Inc. + * Dave Liu + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __FSL_SATA_H__ +#define __FSL_SATA_H__ + +#define SATA_HC_MAX_NUM 4 /* Max host controller numbers */ +#define SATA_HC_MAX_CMD 16 /* Max command queue depth per host controller */ +#define SATA_HC_MAX_PORT 16 /* Max port number per host controller */ + +/* +* SATA Host Controller Registers +*/ +typedef struct fsl_sata_reg { + /* SATA command registers */ + u32 cqr; /* Command queue register */ + u8 res1[0x4]; + u32 car; /* Command active register */ + u8 res2[0x4]; + u32 ccr; /* Command completed register */ + u8 res3[0x4]; + u32 cer; /* Command error register */ + u8 res4[0x4]; + u32 der; /* Device error register */ + u32 chba; /* Command header base address */ + u32 hstatus; /* Host status register */ + u32 hcontrol; /* Host control register */ + u32 cqpmp; /* Port number queue register */ + u32 sig; /* Signature register */ + u32 icc; /* Interrupt coalescing control register */ + u8 res5[0xc4]; + + /* SATA supperset registers */ + u32 sstatus; /* SATA interface status register */ + u32 serror; /* SATA interface error register */ + u32 scontrol; /* SATA interface control register */ + u32 snotification; /* SATA interface notification register */ + u8 res6[0x30]; + + /* SATA control status registers */ + u32 transcfg; /* Transport layer configuration */ + u32 transstatus; /* Transport layer status */ + u32 linkcfg; /* Link layer configuration */ + u32 linkcfg1; /* Link layer configuration1 */ + u32 linkcfg2; /* Link layer configuration2 */ + u32 linkstatus; /* Link layer status */ + u32 linkstatus1; /* Link layer status1 */ + u32 phyctrlcfg; /* PHY control configuration */ + u8 res7[0x2b0]; + + /* SATA system control registers */ + u32 syspr; /* System priority register - big endian */ + u8 res8[0xbec]; +} __attribute__ ((packed)) fsl_sata_reg_t; + +/* HStatus register +*/ +#define HSTATUS_ONOFF 0x80000000 /* Online/offline status */ +#define HSTATUS_FORCE_OFFLINE 0x40000000 /* In process going offline */ +#define HSTATUS_BIST_ERR 0x20000000 + +/* Fatal error */ +#define HSTATUS_MASTER_ERR 0x00004000 +#define HSTATUS_DATA_UNDERRUN 0x00002000 +#define HSTATUS_DATA_OVERRUN 0x00001000 +#define HSTATUS_CRC_ERR_TX 0x00000800 +#define HSTATUS_CRC_ERR_RX 0x00000400 +#define HSTATUS_FIFO_OVERFLOW_TX 0x00000200 +#define HSTATUS_FIFO_OVERFLOW_RX 0x00000100 +#define HSTATUS_FATAL_ERR_ALL (HSTATUS_MASTER_ERR | \ + HSTATUS_DATA_UNDERRUN | \ + HSTATUS_DATA_OVERRUN | \ + HSTATUS_CRC_ERR_TX | \ + HSTATUS_CRC_ERR_RX | \ + HSTATUS_FIFO_OVERFLOW_TX | \ + HSTATUS_FIFO_OVERFLOW_RX) +/* Interrupt status */ +#define HSTATUS_FATAL_ERR 0x00000020 +#define HSTATUS_PHY_RDY 0x00000010 +#define HSTATUS_SIGNATURE 0x00000008 +#define HSTATUS_SNOTIFY 0x00000004 +#define HSTATUS_DEVICE_ERR 0x00000002 +#define HSTATUS_CMD_COMPLETE 0x00000001 + +/* HControl register +*/ +#define HCONTROL_ONOFF 0x80000000 /* Online or offline request */ +#define HCONTROL_FORCE_OFFLINE 0x40000000 /* Force offline request */ +#define HCONTROL_ENTERPRISE_EN 0x10000000 /* Enterprise mode enabled */ +#define HCONTROL_HDR_SNOOP 0x00000400 /* Command header snoop */ +#define HCONTROL_PMP_ATTACHED 0x00000200 /* Port multiplier attached */ + +/* Interrupt enable */ +#define HCONTROL_FATAL_ERR 0x00000020 +#define HCONTROL_PHY_RDY 0x00000010 +#define HCONTROL_SIGNATURE 0x00000008 +#define HCONTROL_SNOTIFY 0x00000004 +#define HCONTROL_DEVICE_ERR 0x00000002 +#define HCONTROL_CMD_COMPLETE 0x00000001 + +#define HCONTROL_INT_EN_ALL (HCONTROL_FATAL_ERR | \ + HCONTROL_PHY_RDY | \ + HCONTROL_SIGNATURE | \ + HCONTROL_SNOTIFY | \ + HCONTROL_DEVICE_ERR | \ + HCONTROL_CMD_COMPLETE) + +/* SStatus register +*/ +#define SSTATUS_IPM_MASK 0x00000780 +#define SSTATUS_IPM_NOPRESENT 0x00000000 +#define SSTATUS_IPM_ACTIVE 0x00000080 +#define SSTATUS_IPM_PATIAL 0x00000100 +#define SSTATUS_IPM_SLUMBER 0x00000300 + +#define SSTATUS_SPD_MASK 0x000000f0 +#define SSTATUS_SPD_GEN1 0x00000010 +#define SSTATUS_SPD_GEN2 0x00000020 + +#define SSTATUS_DET_MASK 0x0000000f +#define SSTATUS_DET_NODEVICE 0x00000000 +#define SSTATUS_DET_DISCONNECT 0x00000001 +#define SSTATUS_DET_CONNECT 0x00000003 +#define SSTATUS_DET_PHY_OFFLINE 0x00000004 + +/* SControl register +*/ +#define SCONTROL_SPM_MASK 0x0000f000 +#define SCONTROL_SPM_GO_PARTIAL 0x00001000 +#define SCONTROL_SPM_GO_SLUMBER 0x00002000 +#define SCONTROL_SPM_GO_ACTIVE 0x00004000 + +#define SCONTROL_IPM_MASK 0x00000f00 +#define SCONTROL_IPM_NO_RESTRICT 0x00000000 +#define SCONTROL_IPM_PARTIAL 0x00000100 +#define SCONTROL_IPM_SLUMBER 0x00000200 +#define SCONTROL_IPM_PART_SLUM 0x00000300 + +#define SCONTROL_SPD_MASK 0x000000f0 +#define SCONTROL_SPD_NO_RESTRICT 0x00000000 +#define SCONTROL_SPD_GEN1 0x00000010 +#define SCONTROL_SPD_GEN2 0x00000020 + +#define SCONTROL_DET_MASK 0x0000000f +#define SCONTROL_DET_HRESET 0x00000001 +#define SCONTROL_DET_DISABLE 0x00000004 + +/* TransCfg register +*/ +#define TRANSCFG_DFIS_SIZE_SHIFT 16 +#define TRANSCFG_RX_WATER_MARK_MASK 0x0000001f + +/* PhyCtrlCfg register +*/ +#define PHYCTRLCFG_FPRFTI_MASK 0x00000018 +#define PHYCTRLCFG_LOOPBACK_MASK 0x0000000e + +/* +* Command Header Entry +*/ +typedef struct cmd_hdr_entry { + __le32 cda; /* Command Descriptor Address, + 4 bytes aligned */ + __le32 prde_fis_len; /* Number of PRD entries and FIS length */ + __le32 ttl; /* Total transfer length */ + __le32 attribute; /* the attribute of command */ +} __attribute__ ((packed)) cmd_hdr_entry_t; + +#define SATA_HC_CMD_HDR_ENTRY_SIZE sizeof(struct cmd_hdr_entry) + +/* cda +*/ +#define CMD_HDR_CDA_ALIGN 4 + +/* prde_fis_len +*/ +#define CMD_HDR_PRD_ENTRY_SHIFT 16 +#define CMD_HDR_PRD_ENTRY_MASK 0x003f0000 +#define CMD_HDR_FIS_LEN_SHIFT 2 + +/* attribute +*/ +#define CMD_HDR_ATTR_RES 0x00000800 /* Reserved bit, should be 1 */ +#define CMD_HDR_ATTR_VBIST 0x00000400 /* Vendor BIST */ +#define CMD_HDR_ATTR_SNOOP 0x00000200 /* Snoop enable for all descriptor */ +#define CMD_HDR_ATTR_FPDMA 0x00000100 /* FPDMA queued command */ +#define CMD_HDR_ATTR_RESET 0x00000080 /* Reset - a SRST or device reset */ +#define CMD_HDR_ATTR_BIST 0x00000040 /* BIST - require the host to enter BIST mode */ +#define CMD_HDR_ATTR_ATAPI 0x00000020 /* ATAPI command */ +#define CMD_HDR_ATTR_TAG 0x0000001f /* TAG mask */ + +/* command type +*/ +enum cmd_type { + CMD_VENDOR_BIST, + CMD_BIST, + CMD_RESET, /* SRST or device reset */ + CMD_ATAPI, + CMD_NCQ, + CMD_ATA, /* None of all above */ +}; + +/* +* Command Header Table +*/ +typedef struct cmd_hdr_tbl { + cmd_hdr_entry_t cmd_slot[SATA_HC_MAX_CMD]; +} __attribute__ ((packed)) cmd_hdr_tbl_t; + +#define SATA_HC_CMD_HDR_TBL_SIZE sizeof(struct cmd_hdr_tbl) +#define SATA_HC_CMD_HDR_TBL_ALIGN 4 + +/* +* PRD entry - Physical Region Descriptor entry +*/ +typedef struct prd_entry { + __le32 dba; /* Data base address, 4 bytes aligned */ + u32 res1; + u32 res2; + __le32 ext_c_ddc; /* Indirect PRD flags, snoop and data word count */ +} __attribute__ ((packed)) prd_entry_t; + +#define SATA_HC_CMD_DESC_PRD_SIZE sizeof(struct prd_entry) + +/* dba +*/ +#define PRD_ENTRY_DBA_ALIGN 4 + +/* ext_c_ddc +*/ +#define PRD_ENTRY_EXT 0x80000000 /* extension flag */ +#ifdef CONFIG_FSL_SATA_V2 +#define PRD_ENTRY_DATA_SNOOP 0x10000000 /* Data snoop enable */ +#else +#define PRD_ENTRY_DATA_SNOOP 0x00400000 /* Data snoop enable */ +#endif +#define PRD_ENTRY_LEN_MASK 0x003fffff /* Data word count */ + +#define PRD_ENTRY_MAX_XFER_SZ (PRD_ENTRY_LEN_MASK + 1) + +/* + * This SATA host controller supports a max of 16 direct PRD entries, but if use + * chained indirect PRD entries, then the contollers supports upto a max of 63 + * entries including direct and indirect PRD entries. + * The PRDT is an array of 63 PRD entries contigiously, but the PRD entries#15 + * will be setup as an indirect descriptor, pointing to it's next (contigious) + * PRD entries#16. + */ +#define SATA_HC_MAX_PRD 63 /* Max PRD entry numbers per command */ +#define SATA_HC_MAX_PRD_DIRECT 16 /* Direct PRDT entries */ +#define SATA_HC_MAX_PRD_USABLE (SATA_HC_MAX_PRD - 1) +#define SATA_HC_MAX_XFER_LEN 0x4000000 + +/* +* PRDT - Physical Region Descriptor Table +*/ +typedef struct prdt { + prd_entry_t prdt[SATA_HC_MAX_PRD]; +} __attribute__ ((packed)) prdt_t; + +/* +* Command Descriptor +*/ +#define SATA_HC_CMD_DESC_CFIS_SIZE 32 /* bytes */ +#define SATA_HC_CMD_DESC_SFIS_SIZE 32 /* bytes */ +#define SATA_HC_CMD_DESC_ACMD_SIZE 16 /* bytes */ +#define SATA_HC_CMD_DESC_RES 16 /* bytes */ + +typedef struct cmd_desc { + u8 cfis[SATA_HC_CMD_DESC_CFIS_SIZE]; + u8 sfis[SATA_HC_CMD_DESC_SFIS_SIZE]; + u8 acmd[SATA_HC_CMD_DESC_ACMD_SIZE]; + u8 res[SATA_HC_CMD_DESC_RES]; + prd_entry_t prdt[SATA_HC_MAX_PRD]; +} __attribute__ ((packed)) cmd_desc_t; + +#define SATA_HC_CMD_DESC_SIZE sizeof(struct cmd_desc) +#define SATA_HC_CMD_DESC_ALIGN 4 + +/* + * SATA device driver info + */ +typedef struct fsl_sata_info { + u32 sata_reg_base; + u32 flags; +} fsl_sata_info_t; + +#define FLAGS_DMA 0x00000000 +#define FLAGS_FPDMA 0x00000001 + +/* + * SATA device driver struct + */ +typedef struct fsl_sata { + char name[12]; + fsl_sata_reg_t *reg_base; /* the base address of controller register */ + void *cmd_hdr_tbl_offset; /* alloc address of command header table */ + cmd_hdr_tbl_t *cmd_hdr; /* aligned address of command header table */ + void *cmd_desc_offset; /* alloc address of command descriptor */ + cmd_desc_t *cmd_desc; /* aligned address of command descriptor */ + int link; /* PHY link status */ + /* device attribute */ + int ata_device_type; /* device type */ + int lba48; + int queue_depth; /* Max NCQ queue depth */ + u16 pio; + u16 mwdma; + u16 udma; + int wcache; + int flush; + int flush_ext; +} fsl_sata_t; + +#define READ_CMD 0 +#define WRITE_CMD 1 + +#endif /* __FSL_SATA_H__ */ diff --git a/drivers/ata/libata.c b/drivers/ata/libata.c new file mode 100644 index 0000000..d684270 --- /dev/null +++ b/drivers/ata/libata.c @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2008 Freescale Semiconductor, Inc. + * Dave Liu + * port from the libata of linux kernel + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include + +u64 ata_id_n_sectors(u16 *id) +{ + if (ata_id_has_lba(id)) { + if (ata_id_has_lba48(id)) + return ata_id_u64(id, ATA_ID_LBA48_SECTORS); + else + return ata_id_u32(id, ATA_ID_LBA_SECTORS); + } else { + return 0; + } +} + +u32 ata_dev_classify(u32 sig) +{ + u8 lbam, lbah; + + lbam = (sig >> 16) & 0xff; + lbah = (sig >> 24) & 0xff; + + if (((lbam == 0) && (lbah == 0)) || + ((lbam == 0x3c) && (lbah == 0xc3))) + return ATA_DEV_ATA; + + if ((lbam == 0x14) && (lbah == 0xeb)) + return ATA_DEV_ATAPI; + + if ((lbam == 0x69) && (lbah == 0x96)) + return ATA_DEV_PMP; + + return ATA_DEV_UNKNOWN; +} + +static void ata_id_string(const u16 *id, unsigned char *s, + unsigned int ofs, unsigned int len) +{ + unsigned int c; + + while (len > 0) { + c = id[ofs] >> 8; + *s = c; + s++; + + c = id[ofs] & 0xff; + *s = c; + s++; + + ofs++; + len -= 2; + } +} + +void ata_id_c_string(const u16 *id, unsigned char *s, + unsigned int ofs, unsigned int len) +{ + unsigned char *p; + + ata_id_string(id, s, ofs, len - 1); + + p = s + strnlen((char *)s, len - 1); + while (p > s && p[-1] == ' ') + p--; + *p = '\0'; +} + +void ata_dump_id(u16 *id) +{ + unsigned char serial[ATA_ID_SERNO_LEN + 1]; + unsigned char firmware[ATA_ID_FW_REV_LEN + 1]; + unsigned char product[ATA_ID_PROD_LEN + 1]; + u64 n_sectors; + + /* Serial number */ + ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial)); + printf("S/N: %s\n\r", serial); + + /* Firmware version */ + ata_id_c_string(id, firmware, ATA_ID_FW_REV, sizeof(firmware)); + printf("Firmware version: %s\n\r", firmware); + + /* Product model */ + ata_id_c_string(id, product, ATA_ID_PROD, sizeof(product)); + printf("Product model number: %s\n\r", product); + + /* Total sectors of device */ + n_sectors = ata_id_n_sectors(id); + printf("Capablity: %lld sectors\n\r", n_sectors); + + printf ("id[49]: capabilities = 0x%04x\n" + "id[53]: field valid = 0x%04x\n" + "id[63]: mwdma = 0x%04x\n" + "id[64]: pio = 0x%04x\n" + "id[75]: queue depth = 0x%04x\n", + id[49], + id[53], + id[63], + id[64], + id[75]); + + printf ("id[76]: sata capablity = 0x%04x\n" + "id[78]: sata features supported = 0x%04x\n" + "id[79]: sata features enable = 0x%04x\n", + id[76], + id[78], + id[79]); + + printf ("id[80]: major version = 0x%04x\n" + "id[81]: minor version = 0x%04x\n" + "id[82]: command set supported 1 = 0x%04x\n" + "id[83]: command set supported 2 = 0x%04x\n" + "id[84]: command set extension = 0x%04x\n", + id[80], + id[81], + id[82], + id[83], + id[84]); + printf ("id[85]: command set enable 1 = 0x%04x\n" + "id[86]: command set enable 2 = 0x%04x\n" + "id[87]: command set default = 0x%04x\n" + "id[88]: udma = 0x%04x\n" + "id[93]: hardware reset result = 0x%04x\n", + id[85], + id[86], + id[87], + id[88], + id[93]); +} + +void ata_swap_buf_le16(u16 *buf, unsigned int buf_words) +{ + unsigned int i; + + for (i = 0; i < buf_words; i++) + buf[i] = le16_to_cpu(buf[i]); +} diff --git a/drivers/ata/mvsata_ide.c b/drivers/ata/mvsata_ide.c new file mode 100644 index 0000000..7b6a155 --- /dev/null +++ b/drivers/ata/mvsata_ide.c @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2010 Albert ARIBAUD + * + * Written-by: Albert ARIBAUD + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include + +#if defined(CONFIG_ORION5X) +#include +#elif defined(CONFIG_KIRKWOOD) +#include +#elif defined(CONFIG_ARCH_MVEBU) +#include +#endif + +/* SATA port registers */ +struct mvsata_port_registers { + u32 reserved0[10]; + u32 edma_cmd; + u32 reserved1[181]; + /* offset 0x300 : ATA Interface registers */ + u32 sstatus; + u32 serror; + u32 scontrol; + u32 ltmode; + u32 phymode3; + u32 phymode4; + u32 reserved2[5]; + u32 phymode1; + u32 phymode2; + u32 bist_cr; + u32 bist_dw1; + u32 bist_dw2; + u32 serrorintrmask; +}; + +/* + * Sanity checks: + * - to compile at all, we need CONFIG_SYS_ATA_BASE_ADDR. + * - for ide_preinit to make sense, we need at least one of + * CONFIG_SYS_ATA_IDE0_OFFSET or CONFIG_SYS_ATA_IDE1_OFFSET; + * - for ide_preinit to be called, we need CONFIG_IDE_PREINIT. + * Fail with an explanation message if these conditions are not met. + * This is particularly important for CONFIG_IDE_PREINIT, because + * its lack would not cause a build error. + */ + +#if !defined(CONFIG_SYS_ATA_BASE_ADDR) +#error CONFIG_SYS_ATA_BASE_ADDR must be defined +#elif !defined(CONFIG_SYS_ATA_IDE0_OFFSET) \ + && !defined(CONFIG_SYS_ATA_IDE1_OFFSET) +#error CONFIG_SYS_ATA_IDE0_OFFSET or CONFIG_SYS_ATA_IDE1_OFFSET \ + must be defined +#elif !defined(CONFIG_IDE_PREINIT) +#error CONFIG_IDE_PREINIT must be defined +#endif + +/* + * Masks and values for SControl DETection and Interface Power Management, + * and for SStatus DETection. + */ + +#define MVSATA_EDMA_CMD_ATA_RST 0x00000004 +#define MVSATA_SCONTROL_DET_MASK 0x0000000F +#define MVSATA_SCONTROL_DET_NONE 0x00000000 +#define MVSATA_SCONTROL_DET_INIT 0x00000001 +#define MVSATA_SCONTROL_IPM_MASK 0x00000F00 +#define MVSATA_SCONTROL_IPM_NO_LP_ALLOWED 0x00000300 +#define MVSATA_SCONTROL_MASK \ + (MVSATA_SCONTROL_DET_MASK|MVSATA_SCONTROL_IPM_MASK) +#define MVSATA_PORT_INIT \ + (MVSATA_SCONTROL_DET_INIT|MVSATA_SCONTROL_IPM_NO_LP_ALLOWED) +#define MVSATA_PORT_USE \ + (MVSATA_SCONTROL_DET_NONE|MVSATA_SCONTROL_IPM_NO_LP_ALLOWED) +#define MVSATA_SSTATUS_DET_MASK 0x0000000F +#define MVSATA_SSTATUS_DET_DEVCOMM 0x00000003 + +/* + * Status codes to return to client callers. Currently, callers ignore + * exact value and only care for zero or nonzero, so no need to make this + * public, it is only #define'd for clarity. + * If/when standard negative codes are implemented in U-Boot, then these + * #defines should be moved to, or replaced by ones from, the common list + * of status codes. + */ + +#define MVSATA_STATUS_OK 0 +#define MVSATA_STATUS_TIMEOUT -1 + +/* + * Registers for SATA MBUS memory windows + */ + +#define MVSATA_WIN_CONTROL(w) (MVEBU_AXP_SATA_BASE + 0x30 + ((w) << 4)) +#define MVSATA_WIN_BASE(w) (MVEBU_AXP_SATA_BASE + 0x34 + ((w) << 4)) + +/* + * Initialize SATA memory windows for Armada XP + */ + +#ifdef CONFIG_ARCH_MVEBU +static void mvsata_ide_conf_mbus_windows(void) +{ + const struct mbus_dram_target_info *dram; + int i; + + dram = mvebu_mbus_dram_info(); + + /* Disable windows, Set Size/Base to 0 */ + for (i = 0; i < 4; i++) { + writel(0, MVSATA_WIN_CONTROL(i)); + writel(0, MVSATA_WIN_BASE(i)); + } + + for (i = 0; i < dram->num_cs; i++) { + const struct mbus_dram_window *cs = dram->cs + i; + writel(((cs->size - 1) & 0xffff0000) | (cs->mbus_attr << 8) | + (dram->mbus_dram_target_id << 4) | 1, + MVSATA_WIN_CONTROL(i)); + writel(cs->base & 0xffff0000, MVSATA_WIN_BASE(i)); + } +} +#endif + +/* + * Initialize one MVSATAHC port: set SControl's IPM to "always active" + * and DET to "reset", then wait for SStatus's DET to become "device and + * comm ok" (or time out after 50 us if no device), then set SControl's + * DET back to "no action". + */ + +static int mvsata_ide_initialize_port(struct mvsata_port_registers *port) +{ + u32 control; + u32 status; + u32 timeleft = 10000; /* wait at most 10 ms for SATA reset to complete */ + + /* Hard reset */ + writel(MVSATA_EDMA_CMD_ATA_RST, &port->edma_cmd); + udelay(25); /* taken from original marvell port */ + writel(0, &port->edma_cmd); + + /* Set control IPM to 3 (no low power) and DET to 1 (initialize) */ + control = readl(&port->scontrol); + control = (control & ~MVSATA_SCONTROL_MASK) | MVSATA_PORT_INIT; + writel(control, &port->scontrol); + /* Toggle control DET back to 0 (normal operation) */ + control = (control & ~MVSATA_SCONTROL_MASK) | MVSATA_PORT_USE; + writel(control, &port->scontrol); + /* wait for status DET to become 3 (device and communication OK) */ + while (--timeleft) { + status = readl(&port->sstatus) & MVSATA_SSTATUS_DET_MASK; + if (status == MVSATA_SSTATUS_DET_DEVCOMM) + break; + udelay(1); + } + /* return success or time-out error depending on time left */ + if (!timeleft) + return MVSATA_STATUS_TIMEOUT; + return MVSATA_STATUS_OK; +} + +/* + * ide_preinit() will be called by ide_init in cmd_ide.c and will + * reset the MVSTATHC ports needed by the board. + */ + +int ide_preinit(void) +{ + int ret = MVSATA_STATUS_TIMEOUT; + int status; + +#ifdef CONFIG_ARCH_MVEBU + mvsata_ide_conf_mbus_windows(); +#endif + + /* Enable ATA port 0 (could be SATA port 0 or 1) if declared */ +#if defined(CONFIG_SYS_ATA_IDE0_OFFSET) + status = mvsata_ide_initialize_port( + (struct mvsata_port_registers *) + (CONFIG_SYS_ATA_BASE_ADDR + CONFIG_SYS_ATA_IDE0_OFFSET)); + if (status == MVSATA_STATUS_OK) + ret = MVSATA_STATUS_OK; +#endif + /* Enable ATA port 1 (could be SATA port 0 or 1) if declared */ +#if defined(CONFIG_SYS_ATA_IDE1_OFFSET) + status = mvsata_ide_initialize_port( + (struct mvsata_port_registers *) + (CONFIG_SYS_ATA_BASE_ADDR + CONFIG_SYS_ATA_IDE1_OFFSET)); + if (status == MVSATA_STATUS_OK) + ret = MVSATA_STATUS_OK; +#endif + /* Return success if at least one port initialization succeeded */ + return ret; +} diff --git a/drivers/ata/mxc_ata.c b/drivers/ata/mxc_ata.c new file mode 100644 index 0000000..44bb406 --- /dev/null +++ b/drivers/ata/mxc_ata.c @@ -0,0 +1,129 @@ +/* + * Freescale iMX51 ATA driver + * + * Copyright (C) 2010 Marek Vasut + * + * Based on code by: + * Mahesh Mahadevan + * + * Based on code from original FSL ATA driver, which is + * part of eCos, the Embedded Configurable Operating System. + * Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +/* MXC ATA register offsets */ +struct mxc_ata_config_regs { + u8 time_off; /* 0x00 */ + u8 time_on; + u8 time_1; + u8 time_2w; + u8 time_2r; + u8 time_ax; + u8 time_pio_rdx; + u8 time_4; + u8 time_9; + u8 time_m; + u8 time_jn; + u8 time_d; + u8 time_k; + u8 time_ack; + u8 time_env; + u8 time_udma_rdx; + u8 time_zah; /* 0x10 */ + u8 time_mlix; + u8 time_dvh; + u8 time_dzfs; + u8 time_dvs; + u8 time_cvh; + u8 time_ss; + u8 time_cyc; + u32 fifo_data_32; /* 0x18 */ + u32 fifo_data_16; + u32 fifo_fill; + u32 ata_control; + u32 interrupt_pending; + u32 interrupt_enable; + u32 interrupt_clear; + u32 fifo_alarm; +}; + +struct mxc_data_hdd_regs { + u32 drive_data; /* 0xa0 */ + u32 drive_features; + u32 drive_sector_count; + u32 drive_sector_num; + u32 drive_cyl_low; + u32 drive_cyl_high; + u32 drive_dev_head; + u32 command; + u32 status; + u32 alt_status; +}; + +/* PIO timing table */ +#define NR_PIO_SPECS 5 +static uint16_t pio_t1[NR_PIO_SPECS] = { 70, 50, 30, 30, 25 }; +static uint16_t pio_t2_8[NR_PIO_SPECS] = { 290, 290, 290, 80, 70 }; +static uint16_t pio_t4[NR_PIO_SPECS] = { 30, 20, 15, 10, 10 }; +static uint16_t pio_t9[NR_PIO_SPECS] = { 20, 15, 10, 10, 10 }; +static uint16_t pio_tA[NR_PIO_SPECS] = { 50, 50, 50, 50, 50 }; + +#define REG2OFF(reg) ((((uint32_t)reg) & 0x3) * 8) +static void set_ata_bus_timing(unsigned char mode) +{ + uint32_t T = 1000000000 / mxc_get_clock(MXC_IPG_CLK); + + struct mxc_ata_config_regs *ata_regs; + ata_regs = (struct mxc_ata_config_regs *)CONFIG_SYS_ATA_BASE_ADDR; + + if (mode >= NR_PIO_SPECS) + return; + + /* Write TIME_OFF/ON/1/2W */ + writeb(3, &ata_regs->time_off); + writeb(3, &ata_regs->time_on); + writeb((pio_t1[mode] + T) / T, &ata_regs->time_1); + writeb((pio_t2_8[mode] + T) / T, &ata_regs->time_2w); + + /* Write TIME_2R/AX/RDX/4 */ + writeb((pio_t2_8[mode] + T) / T, &ata_regs->time_2r); + writeb((pio_tA[mode] + T) / T + 2, &ata_regs->time_ax); + writeb(1, &ata_regs->time_pio_rdx); + writeb((pio_t4[mode] + T) / T, &ata_regs->time_4); + + /* Write TIME_9 ; the rest of timing registers is irrelevant for PIO */ + writeb((pio_t9[mode] + T) / T, &ata_regs->time_9); +} + +int ide_preinit(void) +{ + struct mxc_ata_config_regs *ata_regs; + ata_regs = (struct mxc_ata_config_regs *)CONFIG_SYS_ATA_BASE_ADDR; + + /* 46.3.3.4 @ FSL iMX51 manual */ + /* FIFO normal op., drive reset */ + writel(0x80, &ata_regs->ata_control); + /* FIFO normal op., drive not reset */ + writel(0xc0, &ata_regs->ata_control); + + /* Configure the PIO timing */ + set_ata_bus_timing(CONFIG_MXC_ATA_PIO_MODE); + + /* 46.3.3.4 @ FSL iMX51 manual */ + /* Drive not reset, IORDY handshake */ + writel(0x41, &ata_regs->ata_control); + + return 0; +} diff --git a/drivers/ata/sata.c b/drivers/ata/sata.c new file mode 100644 index 0000000..42ff5c7 --- /dev/null +++ b/drivers/ata/sata.c @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2000-2005, DENX Software Engineering + * Wolfgang Denk + * Copyright (C) Procsys. All rights reserved. + * Mushtaq Khan + * + * Copyright (C) 2008 Freescale Semiconductor, Inc. + * Dave Liu + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +struct blk_desc sata_dev_desc[CONFIG_SYS_SATA_MAX_DEVICE]; + +#ifdef CONFIG_PARTITIONS +struct blk_desc *sata_get_dev(int dev) +{ + return (dev < CONFIG_SYS_SATA_MAX_DEVICE) ? &sata_dev_desc[dev] : NULL; +} +#endif + +#ifdef CONFIG_BLK +static unsigned long sata_bread(struct udevice *dev, lbaint_t start, + lbaint_t blkcnt, void *dst) +{ + return -ENOSYS; +} + +static unsigned long sata_bwrite(struct udevice *dev, lbaint_t start, + lbaint_t blkcnt, const void *buffer) +{ + return -ENOSYS; +} +#else +static unsigned long sata_bread(struct blk_desc *block_dev, lbaint_t start, + lbaint_t blkcnt, void *dst) +{ + return sata_read(block_dev->devnum, start, blkcnt, dst); +} + +static unsigned long sata_bwrite(struct blk_desc *block_dev, lbaint_t start, + lbaint_t blkcnt, const void *buffer) +{ + return sata_write(block_dev->devnum, start, blkcnt, buffer); +} +#endif + +int __sata_initialize(void) +{ + int rc, ret = -1; + int i; + + for (i = 0; i < CONFIG_SYS_SATA_MAX_DEVICE; i++) { + memset(&sata_dev_desc[i], 0, sizeof(struct blk_desc)); + sata_dev_desc[i].if_type = IF_TYPE_SATA; + sata_dev_desc[i].devnum = i; + sata_dev_desc[i].part_type = PART_TYPE_UNKNOWN; + sata_dev_desc[i].type = DEV_TYPE_HARDDISK; + sata_dev_desc[i].lba = 0; + sata_dev_desc[i].blksz = 512; + sata_dev_desc[i].log2blksz = LOG2(sata_dev_desc[i].blksz); +#ifndef CONFIG_BLK + sata_dev_desc[i].block_read = sata_bread; + sata_dev_desc[i].block_write = sata_bwrite; +#endif + rc = init_sata(i); + if (!rc) { + rc = scan_sata(i); + if (!rc && sata_dev_desc[i].lba > 0 && + sata_dev_desc[i].blksz > 0) { + part_init(&sata_dev_desc[i]); + ret = i; + } + } + } + + return ret; +} +int sata_initialize(void) __attribute__((weak, alias("__sata_initialize"))); + +__weak int __sata_stop(void) +{ + int i, err = 0; + + for (i = 0; i < CONFIG_SYS_SATA_MAX_DEVICE; i++) + err |= reset_sata(i); + + if (err) + printf("Could not reset some SATA devices\n"); + + return err; +} +int sata_stop(void) __attribute__((weak, alias("__sata_stop"))); + +#ifdef CONFIG_BLK +static const struct blk_ops sata_blk_ops = { + .read = sata_bread, + .write = sata_bwrite, +}; + +U_BOOT_DRIVER(sata_blk) = { + .name = "sata_blk", + .id = UCLASS_BLK, + .ops = &sata_blk_ops, +}; +#else +U_BOOT_LEGACY_BLK(sata) = { + .if_typename = "sata", + .if_type = IF_TYPE_SATA, + .max_devs = CONFIG_SYS_SATA_MAX_DEVICE, + .desc = sata_dev_desc, +}; +#endif diff --git a/drivers/ata/sata_ceva.c b/drivers/ata/sata_ceva.c new file mode 100644 index 0000000..0c24fce --- /dev/null +++ b/drivers/ata/sata_ceva.c @@ -0,0 +1,149 @@ +/* + * (C) Copyright 2015 - 2016 Xilinx, Inc. + * Michal Simek + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#include +#include +#include +#include +#include + +#include + +/* Vendor Specific Register Offsets */ +#define AHCI_VEND_PCFG 0xA4 +#define AHCI_VEND_PPCFG 0xA8 +#define AHCI_VEND_PP2C 0xAC +#define AHCI_VEND_PP3C 0xB0 +#define AHCI_VEND_PP4C 0xB4 +#define AHCI_VEND_PP5C 0xB8 +#define AHCI_VEND_PAXIC 0xC0 +#define AHCI_VEND_PTC 0xC8 + +/* Vendor Specific Register bit definitions */ +#define PAXIC_ADBW_BW64 0x1 +#define PAXIC_MAWIDD (1 << 8) +#define PAXIC_MARIDD (1 << 16) +#define PAXIC_OTL (0x4 << 20) + +#define PCFG_TPSS_VAL (0x32 << 16) +#define PCFG_TPRS_VAL (0x2 << 12) +#define PCFG_PAD_VAL 0x2 + +#define PPCFG_TTA 0x1FFFE +#define PPCFG_PSSO_EN (1 << 28) +#define PPCFG_PSS_EN (1 << 29) +#define PPCFG_ESDF_EN (1 << 31) + +#define PP2C_CIBGMN 0x0F +#define PP2C_CIBGMX (0x25 << 8) +#define PP2C_CIBGN (0x18 << 16) +#define PP2C_CINMP (0x29 << 24) + +#define PP3C_CWBGMN 0x04 +#define PP3C_CWBGMX (0x0B << 8) +#define PP3C_CWBGN (0x08 << 16) +#define PP3C_CWNMP (0x0F << 24) + +#define PP4C_BMX 0x0a +#define PP4C_BNM (0x08 << 8) +#define PP4C_SFD (0x4a << 16) +#define PP4C_PTST (0x06 << 24) + +#define PP5C_RIT 0x60216 +#define PP5C_RCT (0x7f0 << 20) + +#define PTC_RX_WM_VAL 0x40 +#define PTC_RSVD (1 << 27) + +#define PORT0_BASE 0x100 +#define PORT1_BASE 0x180 + +/* Port Control Register Bit Definitions */ +#define PORT_SCTL_SPD_GEN3 (0x3 << 4) +#define PORT_SCTL_SPD_GEN2 (0x2 << 4) +#define PORT_SCTL_SPD_GEN1 (0x1 << 4) +#define PORT_SCTL_IPM (0x3 << 8) + +#define PORT_BASE 0x100 +#define PORT_OFFSET 0x80 +#define NR_PORTS 2 +#define DRV_NAME "ahci-ceva" +#define CEVA_FLAG_BROKEN_GEN2 1 + +static int ceva_init_sata(ulong mmio) +{ + ulong tmp; + int i; + + /* + * AXI Data bus width to 64 + * Set Mem Addr Read, Write ID for data transfers + * Transfer limit to 72 DWord + */ + tmp = PAXIC_ADBW_BW64 | PAXIC_MAWIDD | PAXIC_MARIDD | PAXIC_OTL; + writel(tmp, mmio + AHCI_VEND_PAXIC); + + /* Set AHCI Enable */ + tmp = readl(mmio + HOST_CTL); + tmp |= HOST_AHCI_EN; + writel(tmp, mmio + HOST_CTL); + + for (i = 0; i < NR_PORTS; i++) { + /* TPSS TPRS scalars, CISE and Port Addr */ + tmp = PCFG_TPSS_VAL | PCFG_TPRS_VAL | (PCFG_PAD_VAL + i); + writel(tmp, mmio + AHCI_VEND_PCFG); + + /* Port Phy Cfg register enables */ + tmp = PPCFG_TTA | PPCFG_PSS_EN | PPCFG_ESDF_EN; + writel(tmp, mmio + AHCI_VEND_PPCFG); + + /* Rx Watermark setting */ + tmp = PTC_RX_WM_VAL | PTC_RSVD; + writel(tmp, mmio + AHCI_VEND_PTC); + + /* Default to Gen 2 Speed and Gen 1 if Gen2 is broken */ + tmp = PORT_SCTL_SPD_GEN3 | PORT_SCTL_IPM; + writel(tmp, mmio + PORT_SCR_CTL + PORT_BASE + PORT_OFFSET * i); + } + return 0; +} + +static int sata_ceva_probe(struct udevice *dev) +{ + struct scsi_platdata *plat = dev_get_platdata(dev); + + ceva_init_sata(plat->base); + return 0; +} + +static const struct udevice_id sata_ceva_ids[] = { + { .compatible = "ceva,ahci-1v84" }, + { } +}; + +static int sata_ceva_ofdata_to_platdata(struct udevice *dev) +{ + struct scsi_platdata *plat = dev_get_platdata(dev); + + plat->base = devfdt_get_addr(dev); + if (plat->base == FDT_ADDR_T_NONE) + return -EINVAL; + + /* Hardcode number for ceva sata controller */ + plat->max_lun = 1; /* Actually two but untested */ + plat->max_id = 2; + + return 0; +} + +U_BOOT_DRIVER(ceva_host_blk) = { + .name = "ceva_sata", + .id = UCLASS_SCSI, + .of_match = sata_ceva_ids, + .probe = sata_ceva_probe, + .ofdata_to_platdata = sata_ceva_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct scsi_platdata), +}; diff --git a/drivers/ata/sata_dwc.c b/drivers/ata/sata_dwc.c new file mode 100644 index 0000000..a226ca2 --- /dev/null +++ b/drivers/ata/sata_dwc.c @@ -0,0 +1,2076 @@ +/* + * sata_dwc.c + * + * Synopsys DesignWare Cores (DWC) SATA host driver + * + * Author: Mark Miesfeld + * + * Ported from 2.6.19.2 to 2.6.25/26 by Stefan Roese + * Copyright 2008 DENX Software Engineering + * + * Based on versions provided by AMCC and Synopsys which are: + * Copyright 2006 Applied Micro Circuits Corporation + * COPYRIGHT (C) 2005 SYNOPSYS, INC. ALL RIGHTS RESERVED + * + * SPDX-License-Identifier: GPL-2.0+ + */ +/* + * SATA support based on the chip canyonlands. + * + * 04-17-2009 + * The local version of this driver for the canyonlands board + * does not use interrupts but polls the chip instead. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sata_dwc.h" + +#define DMA_NUM_CHANS 1 +#define DMA_NUM_CHAN_REGS 8 + +#define AHB_DMA_BRST_DFLT 16 + +struct dmareg { + u32 low; + u32 high; +}; + +struct dma_chan_regs { + struct dmareg sar; + struct dmareg dar; + struct dmareg llp; + struct dmareg ctl; + struct dmareg sstat; + struct dmareg dstat; + struct dmareg sstatar; + struct dmareg dstatar; + struct dmareg cfg; + struct dmareg sgr; + struct dmareg dsr; +}; + +struct dma_interrupt_regs { + struct dmareg tfr; + struct dmareg block; + struct dmareg srctran; + struct dmareg dsttran; + struct dmareg error; +}; + +struct ahb_dma_regs { + struct dma_chan_regs chan_regs[DMA_NUM_CHAN_REGS]; + struct dma_interrupt_regs interrupt_raw; + struct dma_interrupt_regs interrupt_status; + struct dma_interrupt_regs interrupt_mask; + struct dma_interrupt_regs interrupt_clear; + struct dmareg statusInt; + struct dmareg rq_srcreg; + struct dmareg rq_dstreg; + struct dmareg rq_sgl_srcreg; + struct dmareg rq_sgl_dstreg; + struct dmareg rq_lst_srcreg; + struct dmareg rq_lst_dstreg; + struct dmareg dma_cfg; + struct dmareg dma_chan_en; + struct dmareg dma_id; + struct dmareg dma_test; + struct dmareg res1; + struct dmareg res2; + /* DMA Comp Params + * Param 6 = dma_param[0], Param 5 = dma_param[1], + * Param 4 = dma_param[2] ... + */ + struct dmareg dma_params[6]; +}; + +#define DMA_EN 0x00000001 +#define DMA_DI 0x00000000 +#define DMA_CHANNEL(ch) (0x00000001 << (ch)) +#define DMA_ENABLE_CHAN(ch) ((0x00000001 << (ch)) | \ + ((0x000000001 << (ch)) << 8)) +#define DMA_DISABLE_CHAN(ch) (0x00000000 | \ + ((0x000000001 << (ch)) << 8)) + +#define SATA_DWC_MAX_PORTS 1 +#define SATA_DWC_SCR_OFFSET 0x24 +#define SATA_DWC_REG_OFFSET 0x64 + +struct sata_dwc_regs { + u32 fptagr; + u32 fpbor; + u32 fptcr; + u32 dmacr; + u32 dbtsr; + u32 intpr; + u32 intmr; + u32 errmr; + u32 llcr; + u32 phycr; + u32 physr; + u32 rxbistpd; + u32 rxbistpd1; + u32 rxbistpd2; + u32 txbistpd; + u32 txbistpd1; + u32 txbistpd2; + u32 bistcr; + u32 bistfctr; + u32 bistsr; + u32 bistdecr; + u32 res[15]; + u32 testr; + u32 versionr; + u32 idr; + u32 unimpl[192]; + u32 dmadr[256]; +}; + +#define SATA_DWC_TXFIFO_DEPTH 0x01FF +#define SATA_DWC_RXFIFO_DEPTH 0x01FF + +#define SATA_DWC_DBTSR_MWR(size) ((size / 4) & SATA_DWC_TXFIFO_DEPTH) +#define SATA_DWC_DBTSR_MRD(size) (((size / 4) & \ + SATA_DWC_RXFIFO_DEPTH) << 16) +#define SATA_DWC_INTPR_DMAT 0x00000001 +#define SATA_DWC_INTPR_NEWFP 0x00000002 +#define SATA_DWC_INTPR_PMABRT 0x00000004 +#define SATA_DWC_INTPR_ERR 0x00000008 +#define SATA_DWC_INTPR_NEWBIST 0x00000010 +#define SATA_DWC_INTPR_IPF 0x10000000 +#define SATA_DWC_INTMR_DMATM 0x00000001 +#define SATA_DWC_INTMR_NEWFPM 0x00000002 +#define SATA_DWC_INTMR_PMABRTM 0x00000004 +#define SATA_DWC_INTMR_ERRM 0x00000008 +#define SATA_DWC_INTMR_NEWBISTM 0x00000010 + +#define SATA_DWC_DMACR_TMOD_TXCHEN 0x00000004 +#define SATA_DWC_DMACR_TXRXCH_CLEAR SATA_DWC_DMACR_TMOD_TXCHEN + +#define SATA_DWC_QCMD_MAX 32 + +#define SATA_DWC_SERROR_ERR_BITS 0x0FFF0F03 + +#define HSDEVP_FROM_AP(ap) (struct sata_dwc_device_port*) \ + (ap)->private_data + +struct sata_dwc_device { + struct device *dev; + struct ata_probe_ent *pe; + struct ata_host *host; + u8 *reg_base; + struct sata_dwc_regs *sata_dwc_regs; + int irq_dma; +}; + +struct sata_dwc_device_port { + struct sata_dwc_device *hsdev; + int cmd_issued[SATA_DWC_QCMD_MAX]; + u32 dma_chan[SATA_DWC_QCMD_MAX]; + int dma_pending[SATA_DWC_QCMD_MAX]; +}; + +enum { + SATA_DWC_CMD_ISSUED_NOT = 0, + SATA_DWC_CMD_ISSUED_PEND = 1, + SATA_DWC_CMD_ISSUED_EXEC = 2, + SATA_DWC_CMD_ISSUED_NODATA = 3, + + SATA_DWC_DMA_PENDING_NONE = 0, + SATA_DWC_DMA_PENDING_TX = 1, + SATA_DWC_DMA_PENDING_RX = 2, +}; + +#define msleep(a) udelay(a * 1000) +#define ssleep(a) msleep(a * 1000) + +static int ata_probe_timeout = (ATA_TMOUT_INTERNAL / 100); + +enum sata_dev_state { + SATA_INIT = 0, + SATA_READY = 1, + SATA_NODEVICE = 2, + SATA_ERROR = 3, +}; +enum sata_dev_state dev_state = SATA_INIT; + +static struct ahb_dma_regs *sata_dma_regs = 0; +static struct ata_host *phost; +static struct ata_port ap; +static struct ata_port *pap = ≈ +static struct ata_device ata_device; +static struct sata_dwc_device_port dwc_devp; + +static void *scr_addr_sstatus; +static u32 temp_n_block = 0; + +static unsigned ata_exec_internal(struct ata_device *dev, + struct ata_taskfile *tf, const u8 *cdb, + int dma_dir, unsigned int buflen, + unsigned long timeout); +static unsigned int ata_dev_set_feature(struct ata_device *dev, + u8 enable,u8 feature); +static unsigned int ata_dev_init_params(struct ata_device *dev, + u16 heads, u16 sectors); +static u8 ata_irq_on(struct ata_port *ap); +static struct ata_queued_cmd *__ata_qc_from_tag(struct ata_port *ap, + unsigned int tag); +static int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, + u8 status, int in_wq); +static void ata_tf_to_host(struct ata_port *ap, + const struct ata_taskfile *tf); +static void ata_exec_command(struct ata_port *ap, + const struct ata_taskfile *tf); +static unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc); +static u8 ata_check_altstatus(struct ata_port *ap); +static u8 ata_check_status(struct ata_port *ap); +static void ata_dev_select(struct ata_port *ap, unsigned int device, + unsigned int wait, unsigned int can_sleep); +static void ata_qc_issue(struct ata_queued_cmd *qc); +static void ata_tf_load(struct ata_port *ap, + const struct ata_taskfile *tf); +static int ata_dev_read_sectors(unsigned char* pdata, + unsigned long datalen, u32 block, u32 n_block); +static int ata_dev_write_sectors(unsigned char* pdata, + unsigned long datalen , u32 block, u32 n_block); +static void ata_std_dev_select(struct ata_port *ap, unsigned int device); +static void ata_qc_complete(struct ata_queued_cmd *qc); +static void __ata_qc_complete(struct ata_queued_cmd *qc); +static void fill_result_tf(struct ata_queued_cmd *qc); +static void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf); +static void ata_mmio_data_xfer(struct ata_device *dev, + unsigned char *buf, + unsigned int buflen,int do_write); +static void ata_pio_task(struct ata_port *arg_ap); +static void __ata_port_freeze(struct ata_port *ap); +static int ata_port_freeze(struct ata_port *ap); +static void ata_qc_free(struct ata_queued_cmd *qc); +static void ata_pio_sectors(struct ata_queued_cmd *qc); +static void ata_pio_sector(struct ata_queued_cmd *qc); +static void ata_pio_queue_task(struct ata_port *ap, + void *data,unsigned long delay); +static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq); +static int sata_dwc_softreset(struct ata_port *ap); +static int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, + unsigned int flags, u16 *id); +static int check_sata_dev_state(void); + +static const struct ata_port_info sata_dwc_port_info[] = { + { + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING | + ATA_FLAG_SRST | ATA_FLAG_NCQ, + .pio_mask = 0x1f, + .mwdma_mask = 0x07, + .udma_mask = 0x7f, + }, +}; + +int init_sata(int dev) +{ + struct sata_dwc_device hsdev; + struct ata_host host; + struct ata_port_info pi = sata_dwc_port_info[0]; + struct ata_link *link; + struct sata_dwc_device_port hsdevp = dwc_devp; + u8 *base = 0; + u8 *sata_dma_regs_addr = 0; + u8 status; + unsigned long base_addr = 0; + int chan = 0; + int rc; + int i; + + phost = &host; + + base = (u8*)SATA_BASE_ADDR; + + hsdev.sata_dwc_regs = (void *__iomem)(base + SATA_DWC_REG_OFFSET); + + host.n_ports = SATA_DWC_MAX_PORTS; + + for (i = 0; i < SATA_DWC_MAX_PORTS; i++) { + ap.pflags |= ATA_PFLAG_INITIALIZING; + ap.flags = ATA_FLAG_DISABLED; + ap.print_id = -1; + ap.ctl = ATA_DEVCTL_OBS; + ap.host = &host; + ap.last_ctl = 0xFF; + + link = &ap.link; + link->ap = ≈ + link->pmp = 0; + link->active_tag = ATA_TAG_POISON; + link->hw_sata_spd_limit = 0; + + ap.port_no = i; + host.ports[i] = ≈ + } + + ap.pio_mask = pi.pio_mask; + ap.mwdma_mask = pi.mwdma_mask; + ap.udma_mask = pi.udma_mask; + ap.flags |= pi.flags; + ap.link.flags |= pi.link_flags; + + host.ports[0]->ioaddr.cmd_addr = base; + host.ports[0]->ioaddr.scr_addr = base + SATA_DWC_SCR_OFFSET; + scr_addr_sstatus = base + SATA_DWC_SCR_OFFSET; + + base_addr = (unsigned long)base; + + host.ports[0]->ioaddr.cmd_addr = (void *)base_addr + 0x00; + host.ports[0]->ioaddr.data_addr = (void *)base_addr + 0x00; + + host.ports[0]->ioaddr.error_addr = (void *)base_addr + 0x04; + host.ports[0]->ioaddr.feature_addr = (void *)base_addr + 0x04; + + host.ports[0]->ioaddr.nsect_addr = (void *)base_addr + 0x08; + + host.ports[0]->ioaddr.lbal_addr = (void *)base_addr + 0x0c; + host.ports[0]->ioaddr.lbam_addr = (void *)base_addr + 0x10; + host.ports[0]->ioaddr.lbah_addr = (void *)base_addr + 0x14; + + host.ports[0]->ioaddr.device_addr = (void *)base_addr + 0x18; + host.ports[0]->ioaddr.command_addr = (void *)base_addr + 0x1c; + host.ports[0]->ioaddr.status_addr = (void *)base_addr + 0x1c; + + host.ports[0]->ioaddr.altstatus_addr = (void *)base_addr + 0x20; + host.ports[0]->ioaddr.ctl_addr = (void *)base_addr + 0x20; + + sata_dma_regs_addr = (u8*)SATA_DMA_REG_ADDR; + sata_dma_regs = (void *__iomem)sata_dma_regs_addr; + + status = ata_check_altstatus(&ap); + + if (status == 0x7f) { + printf("Hard Disk not found.\n"); + dev_state = SATA_NODEVICE; + rc = false; + return rc; + } + + printf("Waiting for device..."); + i = 0; + while (1) { + udelay(10000); + + status = ata_check_altstatus(&ap); + + if ((status & ATA_BUSY) == 0) { + printf("\n"); + break; + } + + i++; + if (i > (ATA_RESET_TIME * 100)) { + printf("** TimeOUT **\n"); + + dev_state = SATA_NODEVICE; + rc = false; + return rc; + } + if ((i >= 100) && ((i % 100) == 0)) + printf("."); + } + + rc = sata_dwc_softreset(&ap); + + if (rc) { + printf("sata_dwc : error. soft reset failed\n"); + return rc; + } + + for (chan = 0; chan < DMA_NUM_CHANS; chan++) { + out_le32(&(sata_dma_regs->interrupt_mask.error.low), + DMA_DISABLE_CHAN(chan)); + + out_le32(&(sata_dma_regs->interrupt_mask.tfr.low), + DMA_DISABLE_CHAN(chan)); + } + + out_le32(&(sata_dma_regs->dma_cfg.low), DMA_DI); + + out_le32(&hsdev.sata_dwc_regs->intmr, + SATA_DWC_INTMR_ERRM | + SATA_DWC_INTMR_PMABRTM); + + /* Unmask the error bits that should trigger + * an error interrupt by setting the error mask register. + */ + out_le32(&hsdev.sata_dwc_regs->errmr, SATA_DWC_SERROR_ERR_BITS); + + hsdev.host = ap.host; + memset(&hsdevp, 0, sizeof(hsdevp)); + hsdevp.hsdev = &hsdev; + + for (i = 0; i < SATA_DWC_QCMD_MAX; i++) + hsdevp.cmd_issued[i] = SATA_DWC_CMD_ISSUED_NOT; + + out_le32((void __iomem *)scr_addr_sstatus + 4, + in_le32((void __iomem *)scr_addr_sstatus + 4)); + + rc = 0; + return rc; +} + +int reset_sata(int dev) +{ + return 0; +} + +static u8 ata_check_altstatus(struct ata_port *ap) +{ + u8 val = 0; + val = readb(ap->ioaddr.altstatus_addr); + return val; +} + +static int sata_dwc_softreset(struct ata_port *ap) +{ + u8 nsect,lbal = 0; + u8 tmp = 0; + struct ata_ioports *ioaddr = &ap->ioaddr; + + in_le32((void *)ap->ioaddr.scr_addr + (SCR_ERROR * 4)); + + writeb(0x55, ioaddr->nsect_addr); + writeb(0xaa, ioaddr->lbal_addr); + writeb(0xaa, ioaddr->nsect_addr); + writeb(0x55, ioaddr->lbal_addr); + writeb(0x55, ioaddr->nsect_addr); + writeb(0xaa, ioaddr->lbal_addr); + + nsect = readb(ioaddr->nsect_addr); + lbal = readb(ioaddr->lbal_addr); + + if ((nsect == 0x55) && (lbal == 0xaa)) { + printf("Device found\n"); + } else { + printf("No device found\n"); + dev_state = SATA_NODEVICE; + return false; + } + + tmp = ATA_DEVICE_OBS; + writeb(tmp, ioaddr->device_addr); + writeb(ap->ctl, ioaddr->ctl_addr); + + udelay(200); + + writeb(ap->ctl | ATA_SRST, ioaddr->ctl_addr); + + udelay(200); + writeb(ap->ctl, ioaddr->ctl_addr); + + msleep(150); + ata_check_status(ap); + + msleep(50); + ata_check_status(ap); + + while (1) { + u8 status = ata_check_status(ap); + + if (!(status & ATA_BUSY)) + break; + + printf("Hard Disk status is BUSY.\n"); + msleep(50); + } + + tmp = ATA_DEVICE_OBS; + writeb(tmp, ioaddr->device_addr); + + nsect = readb(ioaddr->nsect_addr); + lbal = readb(ioaddr->lbal_addr); + + return 0; +} + +static u8 ata_check_status(struct ata_port *ap) +{ + u8 val = 0; + val = readb(ap->ioaddr.status_addr); + return val; +} + +static int ata_id_has_hipm(const u16 *id) +{ + u16 val = id[76]; + + if (val == 0 || val == 0xffff) + return -1; + + return val & (1 << 9); +} + +static int ata_id_has_dipm(const u16 *id) +{ + u16 val = id[78]; + + if (val == 0 || val == 0xffff) + return -1; + + return val & (1 << 3); +} + +int scan_sata(int dev) +{ + int i; + int rc; + u8 status; + const u16 *id; + struct ata_device *ata_dev = &ata_device; + unsigned long pio_mask, mwdma_mask; + char revbuf[7]; + u16 iobuf[ATA_SECTOR_WORDS]; + + memset(iobuf, 0, sizeof(iobuf)); + + if (dev_state == SATA_NODEVICE) + return 1; + + printf("Waiting for device..."); + i = 0; + while (1) { + udelay(10000); + + status = ata_check_altstatus(&ap); + + if ((status & ATA_BUSY) == 0) { + printf("\n"); + break; + } + + i++; + if (i > (ATA_RESET_TIME * 100)) { + printf("** TimeOUT **\n"); + + dev_state = SATA_NODEVICE; + return 1; + } + if ((i >= 100) && ((i % 100) == 0)) + printf("."); + } + + udelay(1000); + + rc = ata_dev_read_id(ata_dev, &ata_dev->class, + ATA_READID_POSTRESET,ata_dev->id); + if (rc) { + printf("sata_dwc : error. failed sata scan\n"); + return 1; + } + + /* SATA drives indicate we have a bridge. We don't know which + * end of the link the bridge is which is a problem + */ + if (ata_id_is_sata(ata_dev->id)) + ap.cbl = ATA_CBL_SATA; + + id = ata_dev->id; + + ata_dev->flags &= ~ATA_DFLAG_CFG_MASK; + ata_dev->max_sectors = 0; + ata_dev->cdb_len = 0; + ata_dev->n_sectors = 0; + ata_dev->cylinders = 0; + ata_dev->heads = 0; + ata_dev->sectors = 0; + + if (id[ATA_ID_FIELD_VALID] & (1 << 1)) { + pio_mask = id[ATA_ID_PIO_MODES] & 0x03; + pio_mask <<= 3; + pio_mask |= 0x7; + } else { + /* If word 64 isn't valid then Word 51 high byte holds + * the PIO timing number for the maximum. Turn it into + * a mask. + */ + u8 mode = (id[ATA_ID_OLD_PIO_MODES] >> 8) & 0xFF; + if (mode < 5) { + pio_mask = (2 << mode) - 1; + } else { + pio_mask = 1; + } + } + + mwdma_mask = id[ATA_ID_MWDMA_MODES] & 0x07; + + if (ata_id_is_cfa(id)) { + int pio = id[163] & 0x7; + int dma = (id[163] >> 3) & 7; + + if (pio) + pio_mask |= (1 << 5); + if (pio > 1) + pio_mask |= (1 << 6); + if (dma) + mwdma_mask |= (1 << 3); + if (dma > 1) + mwdma_mask |= (1 << 4); + } + + if (ata_dev->class == ATA_DEV_ATA) { + if (ata_id_is_cfa(id)) { + if (id[162] & 1) + printf("supports DRM functions and may " + "not be fully accessable.\n"); + strcpy(revbuf, "CFA"); + } else { + if (ata_id_has_tpm(id)) + printf("supports DRM functions and may " + "not be fully accessable.\n"); + } + + ata_dev->n_sectors = ata_id_n_sectors((u16*)id); + + if (ata_dev->id[59] & 0x100) + ata_dev->multi_count = ata_dev->id[59] & 0xff; + + if (ata_id_has_lba(id)) { + char ncq_desc[20]; + + ata_dev->flags |= ATA_DFLAG_LBA; + if (ata_id_has_lba48(id)) { + ata_dev->flags |= ATA_DFLAG_LBA48; + + if (ata_dev->n_sectors >= (1UL << 28) && + ata_id_has_flush_ext(id)) + ata_dev->flags |= ATA_DFLAG_FLUSH_EXT; + } + if (!ata_id_has_ncq(ata_dev->id)) + ncq_desc[0] = '\0'; + + if (ata_dev->horkage & ATA_HORKAGE_NONCQ) + strcpy(ncq_desc, "NCQ (not used)"); + + if (ap.flags & ATA_FLAG_NCQ) + ata_dev->flags |= ATA_DFLAG_NCQ; + } + ata_dev->cdb_len = 16; + } + ata_dev->max_sectors = ATA_MAX_SECTORS; + if (ata_dev->flags & ATA_DFLAG_LBA48) + ata_dev->max_sectors = ATA_MAX_SECTORS_LBA48; + + if (!(ata_dev->horkage & ATA_HORKAGE_IPM)) { + if (ata_id_has_hipm(ata_dev->id)) + ata_dev->flags |= ATA_DFLAG_HIPM; + if (ata_id_has_dipm(ata_dev->id)) + ata_dev->flags |= ATA_DFLAG_DIPM; + } + + if ((ap.cbl == ATA_CBL_SATA) && (!ata_id_is_sata(ata_dev->id))) { + ata_dev->udma_mask &= ATA_UDMA5; + ata_dev->max_sectors = ATA_MAX_SECTORS; + } + + if (ata_dev->horkage & ATA_HORKAGE_DIAGNOSTIC) { + printf("Drive reports diagnostics failure." + "This may indicate a drive\n"); + printf("fault or invalid emulation." + "Contact drive vendor for information.\n"); + } + + rc = check_sata_dev_state(); + + ata_id_c_string(ata_dev->id, + (unsigned char *)sata_dev_desc[dev].revision, + ATA_ID_FW_REV, sizeof(sata_dev_desc[dev].revision)); + ata_id_c_string(ata_dev->id, + (unsigned char *)sata_dev_desc[dev].vendor, + ATA_ID_PROD, sizeof(sata_dev_desc[dev].vendor)); + ata_id_c_string(ata_dev->id, + (unsigned char *)sata_dev_desc[dev].product, + ATA_ID_SERNO, sizeof(sata_dev_desc[dev].product)); + + sata_dev_desc[dev].lba = (u32) ata_dev->n_sectors; + +#ifdef CONFIG_LBA48 + if (ata_dev->id[83] & (1 << 10)) { + sata_dev_desc[dev].lba48 = 1; + } else { + sata_dev_desc[dev].lba48 = 0; + } +#endif + + return 0; +} + +static u8 ata_busy_wait(struct ata_port *ap, + unsigned int bits,unsigned int max) +{ + u8 status; + + do { + udelay(10); + status = ata_check_status(ap); + max--; + } while (status != 0xff && (status & bits) && (max > 0)); + + return status; +} + +static int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, + unsigned int flags, u16 *id) +{ + struct ata_port *ap = pap; + unsigned int class = *p_class; + struct ata_taskfile tf; + unsigned int err_mask = 0; + const char *reason; + int may_fallback = 1, tried_spinup = 0; + u8 status; + int rc; + + status = ata_busy_wait(ap, ATA_BUSY, 30000); + if (status & ATA_BUSY) { + printf("BSY = 0 check. timeout.\n"); + rc = false; + return rc; + } + + ata_dev_select(ap, dev->devno, 1, 1); + +retry: + memset(&tf, 0, sizeof(tf)); + ap->print_id = 1; + ap->flags &= ~ATA_FLAG_DISABLED; + tf.ctl = ap->ctl; + tf.device = ATA_DEVICE_OBS; + tf.command = ATA_CMD_ID_ATA; + tf.protocol = ATA_PROT_PIO; + + /* Some devices choke if TF registers contain garbage. Make + * sure those are properly initialized. + */ + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + + /* Device presence detection is unreliable on some + * controllers. Always poll IDENTIFY if available. + */ + tf.flags |= ATA_TFLAG_POLLING; + + temp_n_block = 1; + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, + sizeof(id[0]) * ATA_ID_WORDS, 0); + + if (err_mask) { + if (err_mask & AC_ERR_NODEV_HINT) { + printf("NODEV after polling detection\n"); + return -ENOENT; + } + + if ((err_mask == AC_ERR_DEV) && (tf.feature & ATA_ABORTED)) { + /* Device or controller might have reported + * the wrong device class. Give a shot at the + * other IDENTIFY if the current one is + * aborted by the device. + */ + if (may_fallback) { + may_fallback = 0; + + if (class == ATA_DEV_ATA) { + class = ATA_DEV_ATAPI; + } else { + class = ATA_DEV_ATA; + } + goto retry; + } + /* Control reaches here iff the device aborted + * both flavors of IDENTIFYs which happens + * sometimes with phantom devices. + */ + printf("both IDENTIFYs aborted, assuming NODEV\n"); + return -ENOENT; + } + rc = -EIO; + reason = "I/O error"; + goto err_out; + } + + /* Falling back doesn't make sense if ID data was read + * successfully at least once. + */ + may_fallback = 0; + + unsigned int id_cnt; + + for (id_cnt = 0; id_cnt < ATA_ID_WORDS; id_cnt++) + id[id_cnt] = le16_to_cpu(id[id_cnt]); + + + rc = -EINVAL; + reason = "device reports invalid type"; + + if (class == ATA_DEV_ATA) { + if (!ata_id_is_ata(id) && !ata_id_is_cfa(id)) + goto err_out; + } else { + if (ata_id_is_ata(id)) + goto err_out; + } + if (!tried_spinup && (id[2] == 0x37c8 || id[2] == 0x738c)) { + tried_spinup = 1; + /* + * Drive powered-up in standby mode, and requires a specific + * SET_FEATURES spin-up subcommand before it will accept + * anything other than the original IDENTIFY command. + */ + err_mask = ata_dev_set_feature(dev, SETFEATURES_SPINUP, 0); + if (err_mask && id[2] != 0x738c) { + rc = -EIO; + reason = "SPINUP failed"; + goto err_out; + } + /* + * If the drive initially returned incomplete IDENTIFY info, + * we now must reissue the IDENTIFY command. + */ + if (id[2] == 0x37c8) + goto retry; + } + + if ((flags & ATA_READID_POSTRESET) && class == ATA_DEV_ATA) { + /* + * The exact sequence expected by certain pre-ATA4 drives is: + * SRST RESET + * IDENTIFY (optional in early ATA) + * INITIALIZE DEVICE PARAMETERS (later IDE and ATA) + * anything else.. + * Some drives were very specific about that exact sequence. + * + * Note that ATA4 says lba is mandatory so the second check + * shoud never trigger. + */ + if (ata_id_major_version(id) < 4 || !ata_id_has_lba(id)) { + err_mask = ata_dev_init_params(dev, id[3], id[6]); + if (err_mask) { + rc = -EIO; + reason = "INIT_DEV_PARAMS failed"; + goto err_out; + } + + /* current CHS translation info (id[53-58]) might be + * changed. reread the identify device info. + */ + flags &= ~ATA_READID_POSTRESET; + goto retry; + } + } + + *p_class = class; + return 0; + +err_out: + printf("failed to READ ID (%s, err_mask=0x%x)\n", reason, err_mask); + return rc; +} + +static u8 ata_wait_idle(struct ata_port *ap) +{ + u8 status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); + return status; +} + +static void ata_dev_select(struct ata_port *ap, unsigned int device, + unsigned int wait, unsigned int can_sleep) +{ + if (wait) + ata_wait_idle(ap); + + ata_std_dev_select(ap, device); + + if (wait) + ata_wait_idle(ap); +} + +static void ata_std_dev_select(struct ata_port *ap, unsigned int device) +{ + u8 tmp; + + if (device == 0) { + tmp = ATA_DEVICE_OBS; + } else { + tmp = ATA_DEVICE_OBS | ATA_DEV1; + } + + writeb(tmp, ap->ioaddr.device_addr); + + readb(ap->ioaddr.altstatus_addr); + + udelay(1); +} + +static int waiting_for_reg_state(volatile u8 *offset, + int timeout_msec, + u32 sign) +{ + int i; + u32 status; + + for (i = 0; i < timeout_msec; i++) { + status = readl(offset); + if ((status & sign) != 0) + break; + msleep(1); + } + + return (i < timeout_msec) ? 0 : -1; +} + +static void ata_qc_reinit(struct ata_queued_cmd *qc) +{ + qc->dma_dir = DMA_NONE; + qc->flags = 0; + qc->nbytes = qc->extrabytes = qc->curbytes = 0; + qc->n_elem = 0; + qc->err_mask = 0; + qc->sect_size = ATA_SECT_SIZE; + qc->nbytes = ATA_SECT_SIZE * temp_n_block; + + memset(&qc->tf, 0, sizeof(qc->tf)); + qc->tf.ctl = 0; + qc->tf.device = ATA_DEVICE_OBS; + + qc->result_tf.command = ATA_DRDY; + qc->result_tf.feature = 0; +} + +struct ata_queued_cmd *__ata_qc_from_tag(struct ata_port *ap, + unsigned int tag) +{ + if (tag < ATA_MAX_QUEUE) + return &ap->qcmd[tag]; + return NULL; +} + +static void __ata_port_freeze(struct ata_port *ap) +{ + printf("set port freeze.\n"); + ap->pflags |= ATA_PFLAG_FROZEN; +} + +static int ata_port_freeze(struct ata_port *ap) +{ + __ata_port_freeze(ap); + return 0; +} + +unsigned ata_exec_internal(struct ata_device *dev, + struct ata_taskfile *tf, const u8 *cdb, + int dma_dir, unsigned int buflen, + unsigned long timeout) +{ + struct ata_link *link = dev->link; + struct ata_port *ap = pap; + struct ata_queued_cmd *qc; + unsigned int tag, preempted_tag; + u32 preempted_sactive, preempted_qc_active; + int preempted_nr_active_links; + unsigned int err_mask; + int rc = 0; + u8 status; + + status = ata_busy_wait(ap, ATA_BUSY, 300000); + if (status & ATA_BUSY) { + printf("BSY = 0 check. timeout.\n"); + rc = false; + return rc; + } + + if (ap->pflags & ATA_PFLAG_FROZEN) + return AC_ERR_SYSTEM; + + tag = ATA_TAG_INTERNAL; + + if (test_and_set_bit(tag, &ap->qc_allocated)) { + rc = false; + return rc; + } + + qc = __ata_qc_from_tag(ap, tag); + qc->tag = tag; + qc->ap = ap; + qc->dev = dev; + + ata_qc_reinit(qc); + + preempted_tag = link->active_tag; + preempted_sactive = link->sactive; + preempted_qc_active = ap->qc_active; + preempted_nr_active_links = ap->nr_active_links; + link->active_tag = ATA_TAG_POISON; + link->sactive = 0; + ap->qc_active = 0; + ap->nr_active_links = 0; + + qc->tf = *tf; + if (cdb) + memcpy(qc->cdb, cdb, ATAPI_CDB_LEN); + qc->flags |= ATA_QCFLAG_RESULT_TF; + qc->dma_dir = dma_dir; + qc->private_data = 0; + + ata_qc_issue(qc); + + if (!timeout) + timeout = ata_probe_timeout * 1000 / HZ; + + status = ata_busy_wait(ap, ATA_BUSY, 30000); + if (status & ATA_BUSY) { + printf("BSY = 0 check. timeout.\n"); + printf("altstatus = 0x%x.\n", status); + qc->err_mask |= AC_ERR_OTHER; + return qc->err_mask; + } + + if (waiting_for_reg_state(ap->ioaddr.altstatus_addr, 1000, 0x8)) { + u8 status = 0; + u8 errorStatus = 0; + + status = readb(ap->ioaddr.altstatus_addr); + if ((status & 0x01) != 0) { + errorStatus = readb(ap->ioaddr.feature_addr); + if (errorStatus == 0x04 && + qc->tf.command == ATA_CMD_PIO_READ_EXT){ + printf("Hard Disk doesn't support LBA48\n"); + dev_state = SATA_ERROR; + qc->err_mask |= AC_ERR_OTHER; + return qc->err_mask; + } + } + qc->err_mask |= AC_ERR_OTHER; + return qc->err_mask; + } + + status = ata_busy_wait(ap, ATA_BUSY, 10); + if (status & ATA_BUSY) { + printf("BSY = 0 check. timeout.\n"); + qc->err_mask |= AC_ERR_OTHER; + return qc->err_mask; + } + + ata_pio_task(ap); + + if (!rc) { + if (qc->flags & ATA_QCFLAG_ACTIVE) { + qc->err_mask |= AC_ERR_TIMEOUT; + ata_port_freeze(ap); + } + } + + if (qc->flags & ATA_QCFLAG_FAILED) { + if (qc->result_tf.command & (ATA_ERR | ATA_DF)) + qc->err_mask |= AC_ERR_DEV; + + if (!qc->err_mask) + qc->err_mask |= AC_ERR_OTHER; + + if (qc->err_mask & ~AC_ERR_OTHER) + qc->err_mask &= ~AC_ERR_OTHER; + } + + *tf = qc->result_tf; + err_mask = qc->err_mask; + ata_qc_free(qc); + link->active_tag = preempted_tag; + link->sactive = preempted_sactive; + ap->qc_active = preempted_qc_active; + ap->nr_active_links = preempted_nr_active_links; + + if (ap->flags & ATA_FLAG_DISABLED) { + err_mask |= AC_ERR_SYSTEM; + ap->flags &= ~ATA_FLAG_DISABLED; + } + + return err_mask; +} + +static void ata_qc_issue(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct ata_link *link = qc->dev->link; + u8 prot = qc->tf.protocol; + + if (ata_is_ncq(prot)) { + if (!link->sactive) + ap->nr_active_links++; + link->sactive |= 1 << qc->tag; + } else { + ap->nr_active_links++; + link->active_tag = qc->tag; + } + + qc->flags |= ATA_QCFLAG_ACTIVE; + ap->qc_active |= 1 << qc->tag; + + if (qc->dev->flags & ATA_DFLAG_SLEEPING) { + msleep(1); + return; + } + + qc->err_mask |= ata_qc_issue_prot(qc); + if (qc->err_mask) + goto err; + + return; +err: + ata_qc_complete(qc); +} + +static unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + + if (ap->flags & ATA_FLAG_PIO_POLLING) { + switch (qc->tf.protocol) { + case ATA_PROT_PIO: + case ATA_PROT_NODATA: + case ATAPI_PROT_PIO: + case ATAPI_PROT_NODATA: + qc->tf.flags |= ATA_TFLAG_POLLING; + break; + default: + break; + } + } + + ata_dev_select(ap, qc->dev->devno, 1, 0); + + switch (qc->tf.protocol) { + case ATA_PROT_PIO: + if (qc->tf.flags & ATA_TFLAG_POLLING) + qc->tf.ctl |= ATA_NIEN; + + ata_tf_to_host(ap, &qc->tf); + + ap->hsm_task_state = HSM_ST; + + if (qc->tf.flags & ATA_TFLAG_POLLING) + ata_pio_queue_task(ap, qc, 0); + + break; + + default: + return AC_ERR_SYSTEM; + } + + return 0; +} + +static void ata_tf_to_host(struct ata_port *ap, + const struct ata_taskfile *tf) +{ + ata_tf_load(ap, tf); + ata_exec_command(ap, tf); +} + +static void ata_tf_load(struct ata_port *ap, + const struct ata_taskfile *tf) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; + + if (tf->ctl != ap->last_ctl) { + if (ioaddr->ctl_addr) + writeb(tf->ctl, ioaddr->ctl_addr); + ap->last_ctl = tf->ctl; + ata_wait_idle(ap); + } + + if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { + writeb(tf->hob_feature, ioaddr->feature_addr); + writeb(tf->hob_nsect, ioaddr->nsect_addr); + writeb(tf->hob_lbal, ioaddr->lbal_addr); + writeb(tf->hob_lbam, ioaddr->lbam_addr); + writeb(tf->hob_lbah, ioaddr->lbah_addr); + } + + if (is_addr) { + writeb(tf->feature, ioaddr->feature_addr); + writeb(tf->nsect, ioaddr->nsect_addr); + writeb(tf->lbal, ioaddr->lbal_addr); + writeb(tf->lbam, ioaddr->lbam_addr); + writeb(tf->lbah, ioaddr->lbah_addr); + } + + if (tf->flags & ATA_TFLAG_DEVICE) + writeb(tf->device, ioaddr->device_addr); + + ata_wait_idle(ap); +} + +static void ata_exec_command(struct ata_port *ap, + const struct ata_taskfile *tf) +{ + writeb(tf->command, ap->ioaddr.command_addr); + + readb(ap->ioaddr.altstatus_addr); + + udelay(1); +} + +static void ata_pio_queue_task(struct ata_port *ap, + void *data,unsigned long delay) +{ + ap->port_task_data = data; +} + +static unsigned int ac_err_mask(u8 status) +{ + if (status & (ATA_BUSY | ATA_DRQ)) + return AC_ERR_HSM; + if (status & (ATA_ERR | ATA_DF)) + return AC_ERR_DEV; + return 0; +} + +static unsigned int __ac_err_mask(u8 status) +{ + unsigned int mask = ac_err_mask(status); + if (mask == 0) + return AC_ERR_OTHER; + return mask; +} + +static void ata_pio_task(struct ata_port *arg_ap) +{ + struct ata_port *ap = arg_ap; + struct ata_queued_cmd *qc = ap->port_task_data; + u8 status; + int poll_next; + +fsm_start: + /* + * This is purely heuristic. This is a fast path. + * Sometimes when we enter, BSY will be cleared in + * a chk-status or two. If not, the drive is probably seeking + * or something. Snooze for a couple msecs, then + * chk-status again. If still busy, queue delayed work. + */ + status = ata_busy_wait(ap, ATA_BUSY, 5); + if (status & ATA_BUSY) { + msleep(2); + status = ata_busy_wait(ap, ATA_BUSY, 10); + if (status & ATA_BUSY) { + ata_pio_queue_task(ap, qc, ATA_SHORT_PAUSE); + return; + } + } + + poll_next = ata_hsm_move(ap, qc, status, 1); + + /* another command or interrupt handler + * may be running at this point. + */ + if (poll_next) + goto fsm_start; +} + +static int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, + u8 status, int in_wq) +{ + int poll_next; + +fsm_start: + switch (ap->hsm_task_state) { + case HSM_ST_FIRST: + poll_next = (qc->tf.flags & ATA_TFLAG_POLLING); + + if ((status & ATA_DRQ) == 0) { + if (status & (ATA_ERR | ATA_DF)) { + qc->err_mask |= AC_ERR_DEV; + } else { + qc->err_mask |= AC_ERR_HSM; + } + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + + /* Device should not ask for data transfer (DRQ=1) + * when it finds something wrong. + * We ignore DRQ here and stop the HSM by + * changing hsm_task_state to HSM_ST_ERR and + * let the EH abort the command or reset the device. + */ + if (status & (ATA_ERR | ATA_DF)) { + if (!(qc->dev->horkage & ATA_HORKAGE_STUCK_ERR)) { + printf("DRQ=1 with device error, " + "dev_stat 0x%X\n", status); + qc->err_mask |= AC_ERR_HSM; + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + } + + if (qc->tf.protocol == ATA_PROT_PIO) { + /* PIO data out protocol. + * send first data block. + */ + /* ata_pio_sectors() might change the state + * to HSM_ST_LAST. so, the state is changed here + * before ata_pio_sectors(). + */ + ap->hsm_task_state = HSM_ST; + ata_pio_sectors(qc); + } else { + printf("protocol is not ATA_PROT_PIO \n"); + } + break; + + case HSM_ST: + if ((status & ATA_DRQ) == 0) { + if (status & (ATA_ERR | ATA_DF)) { + qc->err_mask |= AC_ERR_DEV; + } else { + /* HSM violation. Let EH handle this. + * Phantom devices also trigger this + * condition. Mark hint. + */ + qc->err_mask |= AC_ERR_HSM | AC_ERR_NODEV_HINT; + } + + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + /* For PIO reads, some devices may ask for + * data transfer (DRQ=1) alone with ERR=1. + * We respect DRQ here and transfer one + * block of junk data before changing the + * hsm_task_state to HSM_ST_ERR. + * + * For PIO writes, ERR=1 DRQ=1 doesn't make + * sense since the data block has been + * transferred to the device. + */ + if (status & (ATA_ERR | ATA_DF)) { + qc->err_mask |= AC_ERR_DEV; + + if (!(qc->tf.flags & ATA_TFLAG_WRITE)) { + ata_pio_sectors(qc); + status = ata_wait_idle(ap); + } + + if (status & (ATA_BUSY | ATA_DRQ)) + qc->err_mask |= AC_ERR_HSM; + + /* ata_pio_sectors() might change the + * state to HSM_ST_LAST. so, the state + * is changed after ata_pio_sectors(). + */ + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + + ata_pio_sectors(qc); + if (ap->hsm_task_state == HSM_ST_LAST && + (!(qc->tf.flags & ATA_TFLAG_WRITE))) { + status = ata_wait_idle(ap); + goto fsm_start; + } + + poll_next = 1; + break; + + case HSM_ST_LAST: + if (!ata_ok(status)) { + qc->err_mask |= __ac_err_mask(status); + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + + ap->hsm_task_state = HSM_ST_IDLE; + + ata_hsm_qc_complete(qc, in_wq); + + poll_next = 0; + break; + + case HSM_ST_ERR: + /* make sure qc->err_mask is available to + * know what's wrong and recover + */ + ap->hsm_task_state = HSM_ST_IDLE; + + ata_hsm_qc_complete(qc, in_wq); + + poll_next = 0; + break; + default: + poll_next = 0; + } + + return poll_next; +} + +static void ata_pio_sectors(struct ata_queued_cmd *qc) +{ + struct ata_port *ap; + ap = pap; + qc->pdata = ap->pdata; + + ata_pio_sector(qc); + + readb(qc->ap->ioaddr.altstatus_addr); + udelay(1); +} + +static void ata_pio_sector(struct ata_queued_cmd *qc) +{ + int do_write = (qc->tf.flags & ATA_TFLAG_WRITE); + struct ata_port *ap = qc->ap; + unsigned int offset; + unsigned char *buf; + char temp_data_buf[512]; + + if (qc->curbytes == qc->nbytes - qc->sect_size) + ap->hsm_task_state = HSM_ST_LAST; + + offset = qc->curbytes; + + switch (qc->tf.command) { + case ATA_CMD_ID_ATA: + buf = (unsigned char *)&ata_device.id[0]; + break; + case ATA_CMD_PIO_READ_EXT: + case ATA_CMD_PIO_READ: + case ATA_CMD_PIO_WRITE_EXT: + case ATA_CMD_PIO_WRITE: + buf = qc->pdata + offset; + break; + default: + buf = (unsigned char *)&temp_data_buf[0]; + } + + ata_mmio_data_xfer(qc->dev, buf, qc->sect_size, do_write); + + qc->curbytes += qc->sect_size; + +} + +static void ata_mmio_data_xfer(struct ata_device *dev, unsigned char *buf, + unsigned int buflen, int do_write) +{ + struct ata_port *ap = pap; + void __iomem *data_addr = ap->ioaddr.data_addr; + unsigned int words = buflen >> 1; + u16 *buf16 = (u16 *)buf; + unsigned int i = 0; + + udelay(100); + if (do_write) { + for (i = 0; i < words; i++) + writew(le16_to_cpu(buf16[i]), data_addr); + } else { + for (i = 0; i < words; i++) + buf16[i] = cpu_to_le16(readw(data_addr)); + } + + if (buflen & 0x01) { + __le16 align_buf[1] = { 0 }; + unsigned char *trailing_buf = buf + buflen - 1; + + if (do_write) { + memcpy(align_buf, trailing_buf, 1); + writew(le16_to_cpu(align_buf[0]), data_addr); + } else { + align_buf[0] = cpu_to_le16(readw(data_addr)); + memcpy(trailing_buf, align_buf, 1); + } + } +} + +static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq) +{ + struct ata_port *ap = qc->ap; + + if (in_wq) { + /* EH might have kicked in while host lock is + * released. + */ + qc = &ap->qcmd[qc->tag]; + if (qc) { + if (!(qc->err_mask & AC_ERR_HSM)) { + ata_irq_on(ap); + ata_qc_complete(qc); + } else { + ata_port_freeze(ap); + } + } + } else { + if (!(qc->err_mask & AC_ERR_HSM)) { + ata_qc_complete(qc); + } else { + ata_port_freeze(ap); + } + } +} + +static u8 ata_irq_on(struct ata_port *ap) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + u8 tmp; + + ap->ctl &= ~ATA_NIEN; + ap->last_ctl = ap->ctl; + + if (ioaddr->ctl_addr) + writeb(ap->ctl, ioaddr->ctl_addr); + + tmp = ata_wait_idle(ap); + + return tmp; +} + +static unsigned int ata_tag_internal(unsigned int tag) +{ + return tag == ATA_MAX_QUEUE - 1; +} + +static void ata_qc_complete(struct ata_queued_cmd *qc) +{ + struct ata_device *dev = qc->dev; + if (qc->err_mask) + qc->flags |= ATA_QCFLAG_FAILED; + + if (qc->flags & ATA_QCFLAG_FAILED) { + if (!ata_tag_internal(qc->tag)) { + fill_result_tf(qc); + return; + } + } + if (qc->flags & ATA_QCFLAG_RESULT_TF) + fill_result_tf(qc); + + /* Some commands need post-processing after successful + * completion. + */ + switch (qc->tf.command) { + case ATA_CMD_SET_FEATURES: + if (qc->tf.feature != SETFEATURES_WC_ON && + qc->tf.feature != SETFEATURES_WC_OFF) + break; + case ATA_CMD_INIT_DEV_PARAMS: + case ATA_CMD_SET_MULTI: + break; + + case ATA_CMD_SLEEP: + dev->flags |= ATA_DFLAG_SLEEPING; + break; + } + + __ata_qc_complete(qc); +} + +static void fill_result_tf(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + + qc->result_tf.flags = qc->tf.flags; + ata_tf_read(ap, &qc->result_tf); +} + +static void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + + tf->command = ata_check_status(ap); + tf->feature = readb(ioaddr->error_addr); + tf->nsect = readb(ioaddr->nsect_addr); + tf->lbal = readb(ioaddr->lbal_addr); + tf->lbam = readb(ioaddr->lbam_addr); + tf->lbah = readb(ioaddr->lbah_addr); + tf->device = readb(ioaddr->device_addr); + + if (tf->flags & ATA_TFLAG_LBA48) { + if (ioaddr->ctl_addr) { + writeb(tf->ctl | ATA_HOB, ioaddr->ctl_addr); + + tf->hob_feature = readb(ioaddr->error_addr); + tf->hob_nsect = readb(ioaddr->nsect_addr); + tf->hob_lbal = readb(ioaddr->lbal_addr); + tf->hob_lbam = readb(ioaddr->lbam_addr); + tf->hob_lbah = readb(ioaddr->lbah_addr); + + writeb(tf->ctl, ioaddr->ctl_addr); + ap->last_ctl = tf->ctl; + } else { + printf("sata_dwc warnning register read.\n"); + } + } +} + +static void __ata_qc_complete(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct ata_link *link = qc->dev->link; + + link->active_tag = ATA_TAG_POISON; + ap->nr_active_links--; + + if (qc->flags & ATA_QCFLAG_CLEAR_EXCL && ap->excl_link == link) + ap->excl_link = NULL; + + qc->flags &= ~ATA_QCFLAG_ACTIVE; + ap->qc_active &= ~(1 << qc->tag); +} + +static void ata_qc_free(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + unsigned int tag; + qc->flags = 0; + tag = qc->tag; + if (tag < ATA_MAX_QUEUE) { + qc->tag = ATA_TAG_POISON; + clear_bit(tag, &ap->qc_allocated); + } +} + +static int check_sata_dev_state(void) +{ + unsigned long datalen; + unsigned char *pdata; + int ret = 0; + int i = 0; + char temp_data_buf[512]; + + while (1) { + udelay(10000); + + pdata = (unsigned char*)&temp_data_buf[0]; + datalen = 512; + + ret = ata_dev_read_sectors(pdata, datalen, 0, 1); + + if (ret == true) + break; + + i++; + if (i > (ATA_RESET_TIME * 100)) { + printf("** TimeOUT **\n"); + dev_state = SATA_NODEVICE; + return false; + } + + if ((i >= 100) && ((i % 100) == 0)) + printf("."); + } + + dev_state = SATA_READY; + + return true; +} + +static unsigned int ata_dev_set_feature(struct ata_device *dev, + u8 enable, u8 feature) +{ + struct ata_taskfile tf; + struct ata_port *ap; + ap = pap; + unsigned int err_mask; + + memset(&tf, 0, sizeof(tf)); + tf.ctl = ap->ctl; + + tf.device = ATA_DEVICE_OBS; + tf.command = ATA_CMD_SET_FEATURES; + tf.feature = enable; + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.protocol = ATA_PROT_NODATA; + tf.nsect = feature; + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, 0, 0); + + return err_mask; +} + +static unsigned int ata_dev_init_params(struct ata_device *dev, + u16 heads, u16 sectors) +{ + struct ata_taskfile tf; + struct ata_port *ap; + ap = pap; + unsigned int err_mask; + + if (sectors < 1 || sectors > 255 || heads < 1 || heads > 16) + return AC_ERR_INVALID; + + memset(&tf, 0, sizeof(tf)); + tf.ctl = ap->ctl; + tf.device = ATA_DEVICE_OBS; + tf.command = ATA_CMD_INIT_DEV_PARAMS; + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.protocol = ATA_PROT_NODATA; + tf.nsect = sectors; + tf.device |= (heads - 1) & 0x0f; + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, 0, 0); + + if (err_mask == AC_ERR_DEV && (tf.feature & ATA_ABORTED)) + err_mask = 0; + + return err_mask; +} + +#if defined(CONFIG_SATA_DWC) && !defined(CONFIG_LBA48) +#define SATA_MAX_READ_BLK 0xFF +#else +#define SATA_MAX_READ_BLK 0xFFFF +#endif + +ulong sata_read(int device, ulong blknr, lbaint_t blkcnt, void *buffer) +{ + ulong start,blks, buf_addr; + unsigned short smallblks; + unsigned long datalen; + unsigned char *pdata; + device &= 0xff; + + u32 block = 0; + u32 n_block = 0; + + if (dev_state != SATA_READY) + return 0; + + buf_addr = (unsigned long)buffer; + start = blknr; + blks = blkcnt; + do { + pdata = (unsigned char *)buf_addr; + if (blks > SATA_MAX_READ_BLK) { + datalen = sata_dev_desc[device].blksz * SATA_MAX_READ_BLK; + smallblks = SATA_MAX_READ_BLK; + + block = (u32)start; + n_block = (u32)smallblks; + + start += SATA_MAX_READ_BLK; + blks -= SATA_MAX_READ_BLK; + } else { + datalen = sata_dev_desc[device].blksz * SATA_MAX_READ_BLK; + datalen = sata_dev_desc[device].blksz * blks; + smallblks = (unsigned short)blks; + + block = (u32)start; + n_block = (u32)smallblks; + + start += blks; + blks = 0; + } + + if (ata_dev_read_sectors(pdata, datalen, block, n_block) != true) { + printf("sata_dwc : Hard disk read error.\n"); + blkcnt -= blks; + break; + } + buf_addr += datalen; + } while (blks != 0); + + return (blkcnt); +} + +static int ata_dev_read_sectors(unsigned char *pdata, unsigned long datalen, + u32 block, u32 n_block) +{ + struct ata_port *ap = pap; + struct ata_device *dev = &ata_device; + struct ata_taskfile tf; + unsigned int class = ATA_DEV_ATA; + unsigned int err_mask = 0; + const char *reason; + int may_fallback = 1; + + if (dev_state == SATA_ERROR) + return false; + + ata_dev_select(ap, dev->devno, 1, 1); + +retry: + memset(&tf, 0, sizeof(tf)); + tf.ctl = ap->ctl; + ap->print_id = 1; + ap->flags &= ~ATA_FLAG_DISABLED; + + ap->pdata = pdata; + + tf.device = ATA_DEVICE_OBS; + + temp_n_block = n_block; + +#ifdef CONFIG_LBA48 + tf.command = ATA_CMD_PIO_READ_EXT; + tf.flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48; + + tf.hob_feature = 31; + tf.feature = 31; + tf.hob_nsect = (n_block >> 8) & 0xff; + tf.nsect = n_block & 0xff; + + tf.hob_lbah = 0x0; + tf.hob_lbam = 0x0; + tf.hob_lbal = (block >> 24) & 0xff; + tf.lbah = (block >> 16) & 0xff; + tf.lbam = (block >> 8) & 0xff; + tf.lbal = block & 0xff; + + tf.device = 1 << 6; + if (tf.flags & ATA_TFLAG_FUA) + tf.device |= 1 << 7; +#else + tf.command = ATA_CMD_PIO_READ; + tf.flags |= ATA_TFLAG_LBA ; + + tf.feature = 31; + tf.nsect = n_block & 0xff; + + tf.lbah = (block >> 16) & 0xff; + tf.lbam = (block >> 8) & 0xff; + tf.lbal = block & 0xff; + + tf.device = (block >> 24) & 0xf; + + tf.device |= 1 << 6; + if (tf.flags & ATA_TFLAG_FUA) + tf.device |= 1 << 7; + +#endif + + tf.protocol = ATA_PROT_PIO; + + /* Some devices choke if TF registers contain garbage. Make + * sure those are properly initialized. + */ + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.flags |= ATA_TFLAG_POLLING; + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, 0, 0); + + if (err_mask) { + if (err_mask & AC_ERR_NODEV_HINT) { + printf("READ_SECTORS NODEV after polling detection\n"); + return -ENOENT; + } + + if ((err_mask == AC_ERR_DEV) && (tf.feature & ATA_ABORTED)) { + /* Device or controller might have reported + * the wrong device class. Give a shot at the + * other IDENTIFY if the current one is + * aborted by the device. + */ + if (may_fallback) { + may_fallback = 0; + + if (class == ATA_DEV_ATA) { + class = ATA_DEV_ATAPI; + } else { + class = ATA_DEV_ATA; + } + goto retry; + } + /* Control reaches here iff the device aborted + * both flavors of IDENTIFYs which happens + * sometimes with phantom devices. + */ + printf("both IDENTIFYs aborted, assuming NODEV\n"); + return -ENOENT; + } + + reason = "I/O error"; + goto err_out; + } + + return true; + +err_out: + printf("failed to READ SECTORS (%s, err_mask=0x%x)\n", reason, err_mask); + return false; +} + +#if defined(CONFIG_SATA_DWC) && !defined(CONFIG_LBA48) +#define SATA_MAX_WRITE_BLK 0xFF +#else +#define SATA_MAX_WRITE_BLK 0xFFFF +#endif + +ulong sata_write(int device, ulong blknr, lbaint_t blkcnt, const void *buffer) +{ + ulong start,blks, buf_addr; + unsigned short smallblks; + unsigned long datalen; + unsigned char *pdata; + device &= 0xff; + + + u32 block = 0; + u32 n_block = 0; + + if (dev_state != SATA_READY) + return 0; + + buf_addr = (unsigned long)buffer; + start = blknr; + blks = blkcnt; + do { + pdata = (unsigned char *)buf_addr; + if (blks > SATA_MAX_WRITE_BLK) { + datalen = sata_dev_desc[device].blksz * SATA_MAX_WRITE_BLK; + smallblks = SATA_MAX_WRITE_BLK; + + block = (u32)start; + n_block = (u32)smallblks; + + start += SATA_MAX_WRITE_BLK; + blks -= SATA_MAX_WRITE_BLK; + } else { + datalen = sata_dev_desc[device].blksz * blks; + smallblks = (unsigned short)blks; + + block = (u32)start; + n_block = (u32)smallblks; + + start += blks; + blks = 0; + } + + if (ata_dev_write_sectors(pdata, datalen, block, n_block) != true) { + printf("sata_dwc : Hard disk read error.\n"); + blkcnt -= blks; + break; + } + buf_addr += datalen; + } while (blks != 0); + + return (blkcnt); +} + +static int ata_dev_write_sectors(unsigned char* pdata, unsigned long datalen, + u32 block, u32 n_block) +{ + struct ata_port *ap = pap; + struct ata_device *dev = &ata_device; + struct ata_taskfile tf; + unsigned int class = ATA_DEV_ATA; + unsigned int err_mask = 0; + const char *reason; + int may_fallback = 1; + + if (dev_state == SATA_ERROR) + return false; + + ata_dev_select(ap, dev->devno, 1, 1); + +retry: + memset(&tf, 0, sizeof(tf)); + tf.ctl = ap->ctl; + ap->print_id = 1; + ap->flags &= ~ATA_FLAG_DISABLED; + + ap->pdata = pdata; + + tf.device = ATA_DEVICE_OBS; + + temp_n_block = n_block; + + +#ifdef CONFIG_LBA48 + tf.command = ATA_CMD_PIO_WRITE_EXT; + tf.flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48 | ATA_TFLAG_WRITE; + + tf.hob_feature = 31; + tf.feature = 31; + tf.hob_nsect = (n_block >> 8) & 0xff; + tf.nsect = n_block & 0xff; + + tf.hob_lbah = 0x0; + tf.hob_lbam = 0x0; + tf.hob_lbal = (block >> 24) & 0xff; + tf.lbah = (block >> 16) & 0xff; + tf.lbam = (block >> 8) & 0xff; + tf.lbal = block & 0xff; + + tf.device = 1 << 6; + if (tf.flags & ATA_TFLAG_FUA) + tf.device |= 1 << 7; +#else + tf.command = ATA_CMD_PIO_WRITE; + tf.flags |= ATA_TFLAG_LBA | ATA_TFLAG_WRITE; + + tf.feature = 31; + tf.nsect = n_block & 0xff; + + tf.lbah = (block >> 16) & 0xff; + tf.lbam = (block >> 8) & 0xff; + tf.lbal = block & 0xff; + + tf.device = (block >> 24) & 0xf; + + tf.device |= 1 << 6; + if (tf.flags & ATA_TFLAG_FUA) + tf.device |= 1 << 7; + +#endif + + tf.protocol = ATA_PROT_PIO; + + /* Some devices choke if TF registers contain garbage. Make + * sure those are properly initialized. + */ + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.flags |= ATA_TFLAG_POLLING; + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, 0, 0); + + if (err_mask) { + if (err_mask & AC_ERR_NODEV_HINT) { + printf("READ_SECTORS NODEV after polling detection\n"); + return -ENOENT; + } + + if ((err_mask == AC_ERR_DEV) && (tf.feature & ATA_ABORTED)) { + /* Device or controller might have reported + * the wrong device class. Give a shot at the + * other IDENTIFY if the current one is + * aborted by the device. + */ + if (may_fallback) { + may_fallback = 0; + + if (class == ATA_DEV_ATA) { + class = ATA_DEV_ATAPI; + } else { + class = ATA_DEV_ATA; + } + goto retry; + } + /* Control reaches here iff the device aborted + * both flavors of IDENTIFYs which happens + * sometimes with phantom devices. + */ + printf("both IDENTIFYs aborted, assuming NODEV\n"); + return -ENOENT; + } + + reason = "I/O error"; + goto err_out; + } + + return true; + +err_out: + printf("failed to WRITE SECTORS (%s, err_mask=0x%x)\n", reason, err_mask); + return false; +} diff --git a/drivers/ata/sata_dwc.h b/drivers/ata/sata_dwc.h new file mode 100644 index 0000000..e2d9e0c --- /dev/null +++ b/drivers/ata/sata_dwc.h @@ -0,0 +1,465 @@ +/* + * sata_dwc.h + * + * Synopsys DesignWare Cores (DWC) SATA host driver + * + * Author: Mark Miesfeld + * + * Ported from 2.6.19.2 to 2.6.25/26 by Stefan Roese + * Copyright 2008 DENX Software Engineering + * + * Based on versions provided by AMCC and Synopsys which are: + * Copyright 2006 Applied Micro Circuits Corporation + * COPYRIGHT (C) 2005 SYNOPSYS, INC. ALL RIGHTS RESERVED + * + * SPDX-License-Identifier: GPL-2.0+ + */ +/* + * SATA support based on the chip canyonlands. + * + * 04-17-2009 + * The local version of this driver for the canyonlands board + * does not use interrupts but polls the chip instead. + */ + + +#ifndef _SATA_DWC_H_ +#define _SATA_DWC_H_ + +#define __U_BOOT__ + +#define HZ 100 +#define READ 0 +#define WRITE 1 + +enum { + ATA_READID_POSTRESET = (1 << 0), + + ATA_DNXFER_PIO = 0, + ATA_DNXFER_DMA = 1, + ATA_DNXFER_40C = 2, + ATA_DNXFER_FORCE_PIO = 3, + ATA_DNXFER_FORCE_PIO0 = 4, + + ATA_DNXFER_QUIET = (1 << 31), +}; + +enum hsm_task_states { + HSM_ST_IDLE, + HSM_ST_FIRST, + HSM_ST, + HSM_ST_LAST, + HSM_ST_ERR, +}; + +#define ATA_SHORT_PAUSE ((HZ >> 6) + 1) + +struct ata_queued_cmd { + struct ata_port *ap; + struct ata_device *dev; + + struct ata_taskfile tf; + u8 cdb[ATAPI_CDB_LEN]; + unsigned long flags; + unsigned int tag; + unsigned int n_elem; + + int dma_dir; + unsigned int sect_size; + + unsigned int nbytes; + unsigned int extrabytes; + unsigned int curbytes; + + unsigned int err_mask; + struct ata_taskfile result_tf; + + void *private_data; +#ifndef __U_BOOT__ + void *lldd_task; +#endif + unsigned char *pdata; +}; + +typedef void (*ata_qc_cb_t) (struct ata_queued_cmd *qc); + +#define ATA_TAG_POISON 0xfafbfcfdU + +enum { + LIBATA_MAX_PRD = ATA_MAX_PRD / 2, + LIBATA_DUMB_MAX_PRD = ATA_MAX_PRD / 4, + ATA_MAX_PORTS = 8, + ATA_DEF_QUEUE = 1, + ATA_MAX_QUEUE = 32, + ATA_TAG_INTERNAL = ATA_MAX_QUEUE - 1, + ATA_MAX_BUS = 2, + ATA_DEF_BUSY_WAIT = 10000, + + ATAPI_MAX_DRAIN = 16 << 10, + + ATA_SHT_EMULATED = 1, + ATA_SHT_CMD_PER_LUN = 1, + ATA_SHT_THIS_ID = -1, + ATA_SHT_USE_CLUSTERING = 1, + + ATA_DFLAG_LBA = (1 << 0), + ATA_DFLAG_LBA48 = (1 << 1), + ATA_DFLAG_CDB_INTR = (1 << 2), + ATA_DFLAG_NCQ = (1 << 3), + ATA_DFLAG_FLUSH_EXT = (1 << 4), + ATA_DFLAG_ACPI_PENDING = (1 << 5), + ATA_DFLAG_ACPI_FAILED = (1 << 6), + ATA_DFLAG_AN = (1 << 7), + ATA_DFLAG_HIPM = (1 << 8), + ATA_DFLAG_DIPM = (1 << 9), + ATA_DFLAG_DMADIR = (1 << 10), + ATA_DFLAG_CFG_MASK = (1 << 12) - 1, + + ATA_DFLAG_PIO = (1 << 12), + ATA_DFLAG_NCQ_OFF = (1 << 13), + ATA_DFLAG_SPUNDOWN = (1 << 14), + ATA_DFLAG_SLEEPING = (1 << 15), + ATA_DFLAG_DUBIOUS_XFER = (1 << 16), + ATA_DFLAG_INIT_MASK = (1 << 24) - 1, + + ATA_DFLAG_DETACH = (1 << 24), + ATA_DFLAG_DETACHED = (1 << 25), + + ATA_LFLAG_HRST_TO_RESUME = (1 << 0), + ATA_LFLAG_SKIP_D2H_BSY = (1 << 1), + ATA_LFLAG_NO_SRST = (1 << 2), + ATA_LFLAG_ASSUME_ATA = (1 << 3), + ATA_LFLAG_ASSUME_SEMB = (1 << 4), + ATA_LFLAG_ASSUME_CLASS = ATA_LFLAG_ASSUME_ATA | ATA_LFLAG_ASSUME_SEMB, + ATA_LFLAG_NO_RETRY = (1 << 5), + ATA_LFLAG_DISABLED = (1 << 6), + + ATA_FLAG_SLAVE_POSS = (1 << 0), + ATA_FLAG_SATA = (1 << 1), + ATA_FLAG_NO_LEGACY = (1 << 2), + ATA_FLAG_MMIO = (1 << 3), + ATA_FLAG_SRST = (1 << 4), + ATA_FLAG_SATA_RESET = (1 << 5), + ATA_FLAG_NO_ATAPI = (1 << 6), + ATA_FLAG_PIO_DMA = (1 << 7), + ATA_FLAG_PIO_LBA48 = (1 << 8), + ATA_FLAG_PIO_POLLING = (1 << 9), + ATA_FLAG_NCQ = (1 << 10), + ATA_FLAG_DEBUGMSG = (1 << 13), + ATA_FLAG_IGN_SIMPLEX = (1 << 15), + ATA_FLAG_NO_IORDY = (1 << 16), + ATA_FLAG_ACPI_SATA = (1 << 17), + ATA_FLAG_AN = (1 << 18), + ATA_FLAG_PMP = (1 << 19), + ATA_FLAG_IPM = (1 << 20), + + ATA_FLAG_DISABLED = (1 << 23), + + ATA_PFLAG_EH_PENDING = (1 << 0), + ATA_PFLAG_EH_IN_PROGRESS = (1 << 1), + ATA_PFLAG_FROZEN = (1 << 2), + ATA_PFLAG_RECOVERED = (1 << 3), + ATA_PFLAG_LOADING = (1 << 4), + ATA_PFLAG_UNLOADING = (1 << 5), + ATA_PFLAG_SCSI_HOTPLUG = (1 << 6), + ATA_PFLAG_INITIALIZING = (1 << 7), + ATA_PFLAG_RESETTING = (1 << 8), + ATA_PFLAG_SUSPENDED = (1 << 17), + ATA_PFLAG_PM_PENDING = (1 << 18), + + ATA_QCFLAG_ACTIVE = (1 << 0), + ATA_QCFLAG_DMAMAP = (1 << 1), + ATA_QCFLAG_IO = (1 << 3), + ATA_QCFLAG_RESULT_TF = (1 << 4), + ATA_QCFLAG_CLEAR_EXCL = (1 << 5), + ATA_QCFLAG_QUIET = (1 << 6), + + ATA_QCFLAG_FAILED = (1 << 16), + ATA_QCFLAG_SENSE_VALID = (1 << 17), + ATA_QCFLAG_EH_SCHEDULED = (1 << 18), + + ATA_HOST_SIMPLEX = (1 << 0), + ATA_HOST_STARTED = (1 << 1), + + ATA_TMOUT_BOOT = 30 * 100, + ATA_TMOUT_BOOT_QUICK = 7 * 100, + ATA_TMOUT_INTERNAL = 30 * 100, + ATA_TMOUT_INTERNAL_QUICK = 5 * 100, + + /* FIXME: GoVault needs 2s but we can't afford that without + * parallel probing. 800ms is enough for iVDR disk + * HHD424020F7SV00. Increase to 2secs when parallel probing + * is in place. + */ + ATA_TMOUT_FF_WAIT = 4 * 100 / 5, + + BUS_UNKNOWN = 0, + BUS_DMA = 1, + BUS_IDLE = 2, + BUS_NOINTR = 3, + BUS_NODATA = 4, + BUS_TIMER = 5, + BUS_PIO = 6, + BUS_EDD = 7, + BUS_IDENTIFY = 8, + BUS_PACKET = 9, + + PORT_UNKNOWN = 0, + PORT_ENABLED = 1, + PORT_DISABLED = 2, + + /* encoding various smaller bitmaps into a single + * unsigned long bitmap + */ + ATA_NR_PIO_MODES = 7, + ATA_NR_MWDMA_MODES = 5, + ATA_NR_UDMA_MODES = 8, + + ATA_SHIFT_PIO = 0, + ATA_SHIFT_MWDMA = ATA_SHIFT_PIO + ATA_NR_PIO_MODES, + ATA_SHIFT_UDMA = ATA_SHIFT_MWDMA + ATA_NR_MWDMA_MODES, + + ATA_DMA_PAD_SZ = 4, + + ATA_ERING_SIZE = 32, + + ATA_DEFER_LINK = 1, + ATA_DEFER_PORT = 2, + + ATA_EH_DESC_LEN = 80, + + ATA_EH_REVALIDATE = (1 << 0), + ATA_EH_SOFTRESET = (1 << 1), + ATA_EH_HARDRESET = (1 << 2), + ATA_EH_ENABLE_LINK = (1 << 3), + ATA_EH_LPM = (1 << 4), + + ATA_EH_RESET_MASK = ATA_EH_SOFTRESET | ATA_EH_HARDRESET, + ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE, + + ATA_EHI_HOTPLUGGED = (1 << 0), + ATA_EHI_RESUME_LINK = (1 << 1), + ATA_EHI_NO_AUTOPSY = (1 << 2), + ATA_EHI_QUIET = (1 << 3), + + ATA_EHI_DID_SOFTRESET = (1 << 16), + ATA_EHI_DID_HARDRESET = (1 << 17), + ATA_EHI_PRINTINFO = (1 << 18), + ATA_EHI_SETMODE = (1 << 19), + ATA_EHI_POST_SETMODE = (1 << 20), + + ATA_EHI_DID_RESET = ATA_EHI_DID_SOFTRESET | ATA_EHI_DID_HARDRESET, + ATA_EHI_RESET_MODIFIER_MASK = ATA_EHI_RESUME_LINK, + + ATA_EH_MAX_TRIES = 5, + + ATA_PROBE_MAX_TRIES = 3, + ATA_EH_DEV_TRIES = 3, + ATA_EH_PMP_TRIES = 5, + ATA_EH_PMP_LINK_TRIES = 3, + + SATA_PMP_SCR_TIMEOUT = 250, + + /* Horkage types. May be set by libata or controller on drives + (some horkage may be drive/controller pair dependant */ + + ATA_HORKAGE_DIAGNOSTIC = (1 << 0), + ATA_HORKAGE_NODMA = (1 << 1), + ATA_HORKAGE_NONCQ = (1 << 2), + ATA_HORKAGE_MAX_SEC_128 = (1 << 3), + ATA_HORKAGE_BROKEN_HPA = (1 << 4), + ATA_HORKAGE_SKIP_PM = (1 << 5), + ATA_HORKAGE_HPA_SIZE = (1 << 6), + ATA_HORKAGE_IPM = (1 << 7), + ATA_HORKAGE_IVB = (1 << 8), + ATA_HORKAGE_STUCK_ERR = (1 << 9), + + ATA_DMA_MASK_ATA = (1 << 0), + ATA_DMA_MASK_ATAPI = (1 << 1), + ATA_DMA_MASK_CFA = (1 << 2), + + ATAPI_READ = 0, + ATAPI_WRITE = 1, + ATAPI_READ_CD = 2, + ATAPI_PASS_THRU = 3, + ATAPI_MISC = 4, +}; + +enum ata_completion_errors { + AC_ERR_DEV = (1 << 0), + AC_ERR_HSM = (1 << 1), + AC_ERR_TIMEOUT = (1 << 2), + AC_ERR_MEDIA = (1 << 3), + AC_ERR_ATA_BUS = (1 << 4), + AC_ERR_HOST_BUS = (1 << 5), + AC_ERR_SYSTEM = (1 << 6), + AC_ERR_INVALID = (1 << 7), + AC_ERR_OTHER = (1 << 8), + AC_ERR_NODEV_HINT = (1 << 9), + AC_ERR_NCQ = (1 << 10), +}; + +enum ata_xfer_mask { + ATA_MASK_PIO = ((1LU << ATA_NR_PIO_MODES) - 1) << ATA_SHIFT_PIO, + ATA_MASK_MWDMA = ((1LU << ATA_NR_MWDMA_MODES) - 1) << ATA_SHIFT_MWDMA, + ATA_MASK_UDMA = ((1LU << ATA_NR_UDMA_MODES) - 1) << ATA_SHIFT_UDMA, +}; + +struct ata_port_info { +#ifndef __U_BOOT__ + struct scsi_host_template *sht; +#endif + unsigned long flags; + unsigned long link_flags; + unsigned long pio_mask; + unsigned long mwdma_mask; + unsigned long udma_mask; +#ifndef __U_BOOT__ + const struct ata_port_operations *port_ops; + void *private_data; +#endif +}; + +struct ata_ioports { + void __iomem *cmd_addr; + void __iomem *data_addr; + void __iomem *error_addr; + void __iomem *feature_addr; + void __iomem *nsect_addr; + void __iomem *lbal_addr; + void __iomem *lbam_addr; + void __iomem *lbah_addr; + void __iomem *device_addr; + void __iomem *status_addr; + void __iomem *command_addr; + void __iomem *altstatus_addr; + void __iomem *ctl_addr; +#ifndef __U_BOOT__ + void __iomem *bmdma_addr; +#endif + void __iomem *scr_addr; +}; + +struct ata_host { +#ifndef __U_BOOT__ + void __iomem * const *iomap; + void *private_data; + const struct ata_port_operations *ops; + unsigned long flags; + struct ata_port *simplex_claimed; +#endif + unsigned int n_ports; + struct ata_port *ports[0]; +}; + +#ifndef __U_BOOT__ +struct ata_port_stats { + unsigned long unhandled_irq; + unsigned long idle_irq; + unsigned long rw_reqbuf; +}; +#endif + +struct ata_device { + struct ata_link *link; + unsigned int devno; + unsigned long flags; + unsigned int horkage; +#ifndef __U_BOOT__ + struct scsi_device *sdev; +#ifdef CONFIG_ATA_ACPI + acpi_handle acpi_handle; + union acpi_object *gtf_cache; +#endif +#endif + u64 n_sectors; + unsigned int class; + + union { + u16 id[ATA_ID_WORDS]; + u32 gscr[SATA_PMP_GSCR_DWORDS]; + }; +#ifndef __U_BOOT__ + u8 pio_mode; + u8 dma_mode; + u8 xfer_mode; + unsigned int xfer_shift; +#endif + unsigned int multi_count; + unsigned int max_sectors; + unsigned int cdb_len; +#ifndef __U_BOOT__ + unsigned long pio_mask; + unsigned long mwdma_mask; +#endif + unsigned long udma_mask; + u16 cylinders; + u16 heads; + u16 sectors; +#ifndef __U_BOOT__ + int spdn_cnt; +#endif +}; + +enum dma_data_direction { + DMA_BIDIRECTIONAL = 0, + DMA_TO_DEVICE = 1, + DMA_FROM_DEVICE = 2, + DMA_NONE = 3, +}; + +struct ata_link { + struct ata_port *ap; + int pmp; + unsigned int active_tag; + u32 sactive; + unsigned int flags; + unsigned int hw_sata_spd_limit; +#ifndef __U_BOOT__ + unsigned int sata_spd_limit; + unsigned int sata_spd; + struct ata_device device[2]; +#endif +}; + +struct ata_port { + unsigned long flags; + unsigned int pflags; + unsigned int print_id; + unsigned int port_no; + + struct ata_ioports ioaddr; + + u8 ctl; + u8 last_ctl; + unsigned int pio_mask; + unsigned int mwdma_mask; + unsigned int udma_mask; + unsigned int cbl; + + struct ata_queued_cmd qcmd[ATA_MAX_QUEUE]; + unsigned long qc_allocated; + unsigned int qc_active; + int nr_active_links; + + struct ata_link link; +#ifndef __U_BOOT__ + int nr_pmp_links; + struct ata_link *pmp_link; +#endif + struct ata_link *excl_link; + int nr_pmp_links; +#ifndef __U_BOOT__ + struct ata_port_stats stats; + struct device *dev; + u32 msg_enable; +#endif + struct ata_host *host; + void *port_task_data; + + unsigned int hsm_task_state; + void *private_data; + unsigned char *pdata; +}; + +#endif diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c new file mode 100644 index 0000000..78e3da4 --- /dev/null +++ b/drivers/ata/sata_mv.c @@ -0,0 +1,1051 @@ +/* + * Copyright (C) Excito Elektronik i SkÃ¥ne AB, 2010. + * Author: Tor Krill + * + * Copyright (C) 2015 Stefan Roese + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * This driver supports the SATA controller of some Mavell SoC's. + * Here a (most likely incomplete) list of the supported SoC's: + * - Kirkwood + * - Armada 370 + * - Armada XP + * + * This driver implementation is an alternative to the already available + * driver via the "ide" commands interface (drivers/block/mvsata_ide.c). + * But this driver only supports PIO mode and as this new driver also + * supports transfer via DMA, its much faster. + * + * Please note, that the newer SoC's (e.g. Armada 38x) are not supported + * by this driver. As they have an AHCI compatible SATA controller + * integrated. + */ + +/* + * TODO: + * Better error recovery + * No support for using PRDs (Thus max 64KB transfers) + * No NCQ support + * No port multiplier support + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_KIRKWOOD) +#include +#define SATAHC_BASE KW_SATA_BASE +#else +#include +#define SATAHC_BASE MVEBU_AXP_SATA_BASE +#endif + +#define SATA0_BASE (SATAHC_BASE + 0x2000) +#define SATA1_BASE (SATAHC_BASE + 0x4000) + +/* EDMA registers */ +#define EDMA_CFG 0x000 +#define EDMA_CFG_NCQ (1 << 5) +#define EDMA_CFG_EQUE (1 << 9) +#define EDMA_TIMER 0x004 +#define EDMA_IECR 0x008 +#define EDMA_IEMR 0x00c +#define EDMA_RQBA_HI 0x010 +#define EDMA_RQIPR 0x014 +#define EDMA_RQIPR_IPMASK (0x1f << 5) +#define EDMA_RQIPR_IPSHIFT 5 +#define EDMA_RQOPR 0x018 +#define EDMA_RQOPR_OPMASK (0x1f << 5) +#define EDMA_RQOPR_OPSHIFT 5 +#define EDMA_RSBA_HI 0x01c +#define EDMA_RSIPR 0x020 +#define EDMA_RSIPR_IPMASK (0x1f << 3) +#define EDMA_RSIPR_IPSHIFT 3 +#define EDMA_RSOPR 0x024 +#define EDMA_RSOPR_OPMASK (0x1f << 3) +#define EDMA_RSOPR_OPSHIFT 3 +#define EDMA_CMD 0x028 +#define EDMA_CMD_ENEDMA (0x01 << 0) +#define EDMA_CMD_DISEDMA (0x01 << 1) +#define EDMA_CMD_ATARST (0x01 << 2) +#define EDMA_CMD_FREEZE (0x01 << 4) +#define EDMA_TEST_CTL 0x02c +#define EDMA_STATUS 0x030 +#define EDMA_IORTO 0x034 +#define EDMA_CDTR 0x040 +#define EDMA_HLTCND 0x060 +#define EDMA_NTSR 0x094 + +/* Basic DMA registers */ +#define BDMA_CMD 0x224 +#define BDMA_STATUS 0x228 +#define BDMA_DTLB 0x22c +#define BDMA_DTHB 0x230 +#define BDMA_DRL 0x234 +#define BDMA_DRH 0x238 + +/* SATA Interface registers */ +#define SIR_ICFG 0x050 +#define SIR_CFG_GEN2EN (0x1 << 7) +#define SIR_PLL_CFG 0x054 +#define SIR_SSTATUS 0x300 +#define SSTATUS_DET_MASK (0x0f << 0) +#define SIR_SERROR 0x304 +#define SIR_SCONTROL 0x308 +#define SIR_SCONTROL_DETEN (0x01 << 0) +#define SIR_LTMODE 0x30c +#define SIR_LTMODE_NELBE (0x01 << 7) +#define SIR_PHYMODE3 0x310 +#define SIR_PHYMODE4 0x314 +#define SIR_PHYMODE1 0x32c +#define SIR_PHYMODE2 0x330 +#define SIR_BIST_CTRL 0x334 +#define SIR_BIST_DW1 0x338 +#define SIR_BIST_DW2 0x33c +#define SIR_SERR_IRQ_MASK 0x340 +#define SIR_SATA_IFCTRL 0x344 +#define SIR_SATA_TESTCTRL 0x348 +#define SIR_SATA_IFSTATUS 0x34c +#define SIR_VEND_UNIQ 0x35c +#define SIR_FIS_CFG 0x360 +#define SIR_FIS_IRQ_CAUSE 0x364 +#define SIR_FIS_IRQ_MASK 0x368 +#define SIR_FIS_DWORD0 0x370 +#define SIR_FIS_DWORD1 0x374 +#define SIR_FIS_DWORD2 0x378 +#define SIR_FIS_DWORD3 0x37c +#define SIR_FIS_DWORD4 0x380 +#define SIR_FIS_DWORD5 0x384 +#define SIR_FIS_DWORD6 0x388 +#define SIR_PHYM9_GEN2 0x398 +#define SIR_PHYM9_GEN1 0x39c +#define SIR_PHY_CFG 0x3a0 +#define SIR_PHYCTL 0x3a4 +#define SIR_PHYM10 0x3a8 +#define SIR_PHYM12 0x3b0 + +/* Shadow registers */ +#define PIO_DATA 0x100 +#define PIO_ERR_FEATURES 0x104 +#define PIO_SECTOR_COUNT 0x108 +#define PIO_LBA_LOW 0x10c +#define PIO_LBA_MID 0x110 +#define PIO_LBA_HI 0x114 +#define PIO_DEVICE 0x118 +#define PIO_CMD_STATUS 0x11c +#define PIO_STATUS_ERR (0x01 << 0) +#define PIO_STATUS_DRQ (0x01 << 3) +#define PIO_STATUS_DF (0x01 << 5) +#define PIO_STATUS_DRDY (0x01 << 6) +#define PIO_STATUS_BSY (0x01 << 7) +#define PIO_CTRL_ALTSTAT 0x120 + +/* SATAHC arbiter registers */ +#define SATAHC_CFG 0x000 +#define SATAHC_RQOP 0x004 +#define SATAHC_RQIP 0x008 +#define SATAHC_ICT 0x00c +#define SATAHC_ITT 0x010 +#define SATAHC_ICR 0x014 +#define SATAHC_ICR_PORT0 (0x01 << 0) +#define SATAHC_ICR_PORT1 (0x01 << 1) +#define SATAHC_MIC 0x020 +#define SATAHC_MIM 0x024 +#define SATAHC_LED_CFG 0x02c + +#define REQUEST_QUEUE_SIZE 32 +#define RESPONSE_QUEUE_SIZE REQUEST_QUEUE_SIZE + +struct crqb { + u32 dtb_low; /* DW0 */ + u32 dtb_high; /* DW1 */ + u32 control_flags; /* DW2 */ + u32 drb_count; /* DW3 */ + u32 ata_cmd_feat; /* DW4 */ + u32 ata_addr; /* DW5 */ + u32 ata_addr_exp; /* DW6 */ + u32 ata_sect_count; /* DW7 */ +}; + +#define CRQB_ALIGN 0x400 + +#define CRQB_CNTRLFLAGS_DIR (0x01 << 0) +#define CRQB_CNTRLFLAGS_DQTAGMASK (0x1f << 1) +#define CRQB_CNTRLFLAGS_DQTAGSHIFT 1 +#define CRQB_CNTRLFLAGS_PMPORTMASK (0x0f << 12) +#define CRQB_CNTRLFLAGS_PMPORTSHIFT 12 +#define CRQB_CNTRLFLAGS_PRDMODE (0x01 << 16) +#define CRQB_CNTRLFLAGS_HQTAGMASK (0x1f << 17) +#define CRQB_CNTRLFLAGS_HQTAGSHIFT 17 + +#define CRQB_CMDFEAT_CMDMASK (0xff << 16) +#define CRQB_CMDFEAT_CMDSHIFT 16 +#define CRQB_CMDFEAT_FEATMASK (0xff << 16) +#define CRQB_CMDFEAT_FEATSHIFT 24 + +#define CRQB_ADDR_LBA_LOWMASK (0xff << 0) +#define CRQB_ADDR_LBA_LOWSHIFT 0 +#define CRQB_ADDR_LBA_MIDMASK (0xff << 8) +#define CRQB_ADDR_LBA_MIDSHIFT 8 +#define CRQB_ADDR_LBA_HIGHMASK (0xff << 16) +#define CRQB_ADDR_LBA_HIGHSHIFT 16 +#define CRQB_ADDR_DEVICE_MASK (0xff << 24) +#define CRQB_ADDR_DEVICE_SHIFT 24 + +#define CRQB_ADDR_LBA_LOW_EXP_MASK (0xff << 0) +#define CRQB_ADDR_LBA_LOW_EXP_SHIFT 0 +#define CRQB_ADDR_LBA_MID_EXP_MASK (0xff << 8) +#define CRQB_ADDR_LBA_MID_EXP_SHIFT 8 +#define CRQB_ADDR_LBA_HIGH_EXP_MASK (0xff << 16) +#define CRQB_ADDR_LBA_HIGH_EXP_SHIFT 16 +#define CRQB_ADDR_FEATURE_EXP_MASK (0xff << 24) +#define CRQB_ADDR_FEATURE_EXP_SHIFT 24 + +#define CRQB_SECTCOUNT_COUNT_MASK (0xff << 0) +#define CRQB_SECTCOUNT_COUNT_SHIFT 0 +#define CRQB_SECTCOUNT_COUNT_EXP_MASK (0xff << 8) +#define CRQB_SECTCOUNT_COUNT_EXP_SHIFT 8 + +#define MVSATA_WIN_CONTROL(w) (MVEBU_AXP_SATA_BASE + 0x30 + ((w) << 4)) +#define MVSATA_WIN_BASE(w) (MVEBU_AXP_SATA_BASE + 0x34 + ((w) << 4)) + +struct eprd { + u32 phyaddr_low; + u32 bytecount_eot; + u32 phyaddr_hi; + u32 reserved; +}; + +#define EPRD_PHYADDR_MASK 0xfffffffe +#define EPRD_BYTECOUNT_MASK 0x0000ffff +#define EPRD_EOT (0x01 << 31) + +struct crpb { + u32 id; + u32 flags; + u32 timestamp; +}; + +#define CRPB_ALIGN 0x100 + +#define READ_CMD 0 +#define WRITE_CMD 1 + +/* + * Since we don't use PRDs yet max transfer size + * is 64KB + */ +#define MV_ATA_MAX_SECTORS (65535 / ATA_SECT_SIZE) + +/* Keep track if hw is initialized or not */ +static u32 hw_init; + +struct mv_priv { + char name[12]; + u32 link; + u32 regbase; + u32 queue_depth; + u16 pio; + u16 mwdma; + u16 udma; + + void *crqb_alloc; + struct crqb *request; + + void *crpb_alloc; + struct crpb *response; +}; + +static int ata_wait_register(u32 *addr, u32 mask, u32 val, u32 timeout_msec) +{ + ulong start; + + start = get_timer(0); + do { + if ((in_le32(addr) & mask) == val) + return 0; + } while (get_timer(start) < timeout_msec); + + return -ETIMEDOUT; +} + +/* Cut from sata_mv in linux kernel */ +static int mv_stop_edma_engine(int port) +{ + struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; + int i; + + /* Disable eDMA. The disable bit auto clears. */ + out_le32(priv->regbase + EDMA_CMD, EDMA_CMD_DISEDMA); + + /* Wait for the chip to confirm eDMA is off. */ + for (i = 10000; i > 0; i--) { + u32 reg = in_le32(priv->regbase + EDMA_CMD); + if (!(reg & EDMA_CMD_ENEDMA)) { + debug("EDMA stop on port %d succesful\n", port); + return 0; + } + udelay(10); + } + debug("EDMA stop on port %d failed\n", port); + return -1; +} + +static int mv_start_edma_engine(int port) +{ + struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; + u32 tmp; + + /* Check preconditions */ + tmp = in_le32(priv->regbase + SIR_SSTATUS); + if ((tmp & SSTATUS_DET_MASK) != 0x03) { + printf("Device error on port: %d\n", port); + return -1; + } + + tmp = in_le32(priv->regbase + PIO_CMD_STATUS); + if (tmp & (ATA_BUSY | ATA_DRQ)) { + printf("Device not ready on port: %d\n", port); + return -1; + } + + /* Clear interrupt cause */ + out_le32(priv->regbase + EDMA_IECR, 0x0); + + tmp = in_le32(SATAHC_BASE + SATAHC_ICR); + tmp &= ~(port == 0 ? SATAHC_ICR_PORT0 : SATAHC_ICR_PORT1); + out_le32(SATAHC_BASE + SATAHC_ICR, tmp); + + /* Configure edma operation */ + tmp = in_le32(priv->regbase + EDMA_CFG); + tmp &= ~EDMA_CFG_NCQ; /* No NCQ */ + tmp &= ~EDMA_CFG_EQUE; /* Dont queue operations */ + out_le32(priv->regbase + EDMA_CFG, tmp); + + out_le32(priv->regbase + SIR_FIS_IRQ_CAUSE, 0x0); + + /* Configure fis, set all to no-wait for now */ + out_le32(priv->regbase + SIR_FIS_CFG, 0x0); + + /* Setup request queue */ + out_le32(priv->regbase + EDMA_RQBA_HI, 0x0); + out_le32(priv->regbase + EDMA_RQIPR, priv->request); + out_le32(priv->regbase + EDMA_RQOPR, 0x0); + + /* Setup response queue */ + out_le32(priv->regbase + EDMA_RSBA_HI, 0x0); + out_le32(priv->regbase + EDMA_RSOPR, priv->response); + out_le32(priv->regbase + EDMA_RSIPR, 0x0); + + /* Start edma */ + out_le32(priv->regbase + EDMA_CMD, EDMA_CMD_ENEDMA); + + return 0; +} + +static int mv_reset_channel(int port) +{ + struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; + + /* Make sure edma is stopped */ + mv_stop_edma_engine(port); + + out_le32(priv->regbase + EDMA_CMD, EDMA_CMD_ATARST); + udelay(25); /* allow reset propagation */ + out_le32(priv->regbase + EDMA_CMD, 0); + mdelay(10); + + return 0; +} + +static void mv_reset_port(int port) +{ + struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; + + mv_reset_channel(port); + + out_le32(priv->regbase + EDMA_CMD, 0x0); + out_le32(priv->regbase + EDMA_CFG, 0x101f); + out_le32(priv->regbase + EDMA_IECR, 0x0); + out_le32(priv->regbase + EDMA_IEMR, 0x0); + out_le32(priv->regbase + EDMA_RQBA_HI, 0x0); + out_le32(priv->regbase + EDMA_RQIPR, 0x0); + out_le32(priv->regbase + EDMA_RQOPR, 0x0); + out_le32(priv->regbase + EDMA_RSBA_HI, 0x0); + out_le32(priv->regbase + EDMA_RSIPR, 0x0); + out_le32(priv->regbase + EDMA_RSOPR, 0x0); + out_le32(priv->regbase + EDMA_IORTO, 0xfa); +} + +static void mv_reset_one_hc(void) +{ + out_le32(SATAHC_BASE + SATAHC_ICT, 0x00); + out_le32(SATAHC_BASE + SATAHC_ITT, 0x00); + out_le32(SATAHC_BASE + SATAHC_ICR, 0x00); +} + +static int probe_port(int port) +{ + struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; + int tries, tries2, set15 = 0; + u32 tmp; + + debug("Probe port: %d\n", port); + + for (tries = 0; tries < 2; tries++) { + /* Clear SError */ + out_le32(priv->regbase + SIR_SERROR, 0x0); + + /* trigger com-init */ + tmp = in_le32(priv->regbase + SIR_SCONTROL); + tmp = (tmp & 0x0f0) | 0x300 | SIR_SCONTROL_DETEN; + out_le32(priv->regbase + SIR_SCONTROL, tmp); + + mdelay(1); + + tmp = in_le32(priv->regbase + SIR_SCONTROL); + tries2 = 5; + do { + tmp = (tmp & 0x0f0) | 0x300; + out_le32(priv->regbase + SIR_SCONTROL, tmp); + mdelay(10); + tmp = in_le32(priv->regbase + SIR_SCONTROL); + } while ((tmp & 0xf0f) != 0x300 && tries2--); + + mdelay(10); + + for (tries2 = 0; tries2 < 200; tries2++) { + tmp = in_le32(priv->regbase + SIR_SSTATUS); + if ((tmp & SSTATUS_DET_MASK) == 0x03) { + debug("Found device on port\n"); + return 0; + } + mdelay(1); + } + + if ((tmp & SSTATUS_DET_MASK) == 0) { + debug("No device attached on port %d\n", port); + return -ENODEV; + } + + if (!set15) { + /* Try on 1.5Gb/S */ + debug("Try 1.5Gb link\n"); + set15 = 1; + out_le32(priv->regbase + SIR_SCONTROL, 0x304); + + tmp = in_le32(priv->regbase + SIR_ICFG); + tmp &= ~SIR_CFG_GEN2EN; + out_le32(priv->regbase + SIR_ICFG, tmp); + + mv_reset_channel(port); + } + } + + debug("Failed to probe port\n"); + return -1; +} + +/* Get request queue in pointer */ +static int get_reqip(int port) +{ + struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; + u32 tmp; + + tmp = in_le32(priv->regbase + EDMA_RQIPR) & EDMA_RQIPR_IPMASK; + tmp = tmp >> EDMA_RQIPR_IPSHIFT; + + return tmp; +} + +static void set_reqip(int port, int reqin) +{ + struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; + u32 tmp; + + tmp = in_le32(priv->regbase + EDMA_RQIPR) & ~EDMA_RQIPR_IPMASK; + tmp |= ((reqin << EDMA_RQIPR_IPSHIFT) & EDMA_RQIPR_IPMASK); + out_le32(priv->regbase + EDMA_RQIPR, tmp); +} + +/* Get next available slot, ignoring possible overwrite */ +static int get_next_reqip(int port) +{ + int slot = get_reqip(port); + slot = (slot + 1) % REQUEST_QUEUE_SIZE; + return slot; +} + +/* Get response queue in pointer */ +static int get_rspip(int port) +{ + struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; + u32 tmp; + + tmp = in_le32(priv->regbase + EDMA_RSIPR) & EDMA_RSIPR_IPMASK; + tmp = tmp >> EDMA_RSIPR_IPSHIFT; + + return tmp; +} + +/* Get response queue out pointer */ +static int get_rspop(int port) +{ + struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; + u32 tmp; + + tmp = in_le32(priv->regbase + EDMA_RSOPR) & EDMA_RSOPR_OPMASK; + tmp = tmp >> EDMA_RSOPR_OPSHIFT; + return tmp; +} + +/* Get next response queue pointer */ +static int get_next_rspop(int port) +{ + return (get_rspop(port) + 1) % RESPONSE_QUEUE_SIZE; +} + +/* Set response queue pointer */ +static void set_rspop(int port, int reqin) +{ + struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; + u32 tmp; + + tmp = in_le32(priv->regbase + EDMA_RSOPR) & ~EDMA_RSOPR_OPMASK; + tmp |= ((reqin << EDMA_RSOPR_OPSHIFT) & EDMA_RSOPR_OPMASK); + + out_le32(priv->regbase + EDMA_RSOPR, tmp); +} + +static int wait_dma_completion(int port, int index, u32 timeout_msec) +{ + u32 tmp, res; + + tmp = port == 0 ? SATAHC_ICR_PORT0 : SATAHC_ICR_PORT1; + res = ata_wait_register((u32 *)(SATAHC_BASE + SATAHC_ICR), tmp, + tmp, timeout_msec); + if (res) + printf("Failed to wait for completion on port %d\n", port); + + return res; +} + +static void process_responses(int port) +{ +#ifdef DEBUG + struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; +#endif + u32 tmp; + u32 outind = get_rspop(port); + + /* Ack interrupts */ + tmp = in_le32(SATAHC_BASE + SATAHC_ICR); + if (port == 0) + tmp &= ~(BIT(0) | BIT(8)); + else + tmp &= ~(BIT(1) | BIT(9)); + tmp &= ~(BIT(4)); + out_le32(SATAHC_BASE + SATAHC_ICR, tmp); + + while (get_rspip(port) != outind) { +#ifdef DEBUG + debug("Response index %d flags %08x on port %d\n", outind, + priv->response[outind].flags, port); +#endif + outind = get_next_rspop(port); + set_rspop(port, outind); + } +} + +static int mv_ata_exec_ata_cmd(int port, struct sata_fis_h2d *cfis, + u8 *buffer, u32 len, u32 iswrite) +{ + struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; + struct crqb *req; + int slot; + u32 start; + + if (len >= 64 * 1024) { + printf("We only support <64K transfers for now\n"); + return -1; + } + + /* Initialize request */ + slot = get_reqip(port); + memset(&priv->request[slot], 0, sizeof(struct crqb)); + req = &priv->request[slot]; + + req->dtb_low = (u32)buffer; + + /* Dont use PRDs */ + req->control_flags = CRQB_CNTRLFLAGS_PRDMODE; + req->control_flags |= iswrite ? 0 : CRQB_CNTRLFLAGS_DIR; + req->control_flags |= + ((cfis->pm_port_c << CRQB_CNTRLFLAGS_PMPORTSHIFT) + & CRQB_CNTRLFLAGS_PMPORTMASK); + + req->drb_count = len; + + req->ata_cmd_feat = (cfis->command << CRQB_CMDFEAT_CMDSHIFT) & + CRQB_CMDFEAT_CMDMASK; + req->ata_cmd_feat |= (cfis->features << CRQB_CMDFEAT_FEATSHIFT) & + CRQB_CMDFEAT_FEATMASK; + + req->ata_addr = (cfis->lba_low << CRQB_ADDR_LBA_LOWSHIFT) & + CRQB_ADDR_LBA_LOWMASK; + req->ata_addr |= (cfis->lba_mid << CRQB_ADDR_LBA_MIDSHIFT) & + CRQB_ADDR_LBA_MIDMASK; + req->ata_addr |= (cfis->lba_high << CRQB_ADDR_LBA_HIGHSHIFT) & + CRQB_ADDR_LBA_HIGHMASK; + req->ata_addr |= (cfis->device << CRQB_ADDR_DEVICE_SHIFT) & + CRQB_ADDR_DEVICE_MASK; + + req->ata_addr_exp = (cfis->lba_low_exp << CRQB_ADDR_LBA_LOW_EXP_SHIFT) & + CRQB_ADDR_LBA_LOW_EXP_MASK; + req->ata_addr_exp |= + (cfis->lba_mid_exp << CRQB_ADDR_LBA_MID_EXP_SHIFT) & + CRQB_ADDR_LBA_MID_EXP_MASK; + req->ata_addr_exp |= + (cfis->lba_high_exp << CRQB_ADDR_LBA_HIGH_EXP_SHIFT) & + CRQB_ADDR_LBA_HIGH_EXP_MASK; + req->ata_addr_exp |= + (cfis->features_exp << CRQB_ADDR_FEATURE_EXP_SHIFT) & + CRQB_ADDR_FEATURE_EXP_MASK; + + req->ata_sect_count = + (cfis->sector_count << CRQB_SECTCOUNT_COUNT_SHIFT) & + CRQB_SECTCOUNT_COUNT_MASK; + req->ata_sect_count |= + (cfis->sector_count_exp << CRQB_SECTCOUNT_COUNT_EXP_SHIFT) & + CRQB_SECTCOUNT_COUNT_EXP_MASK; + + /* Flush data */ + start = (u32)req & ~(ARCH_DMA_MINALIGN - 1); + flush_dcache_range(start, + start + ALIGN(sizeof(*req), ARCH_DMA_MINALIGN)); + + /* Trigger operation */ + slot = get_next_reqip(port); + set_reqip(port, slot); + + /* Wait for completion */ + if (wait_dma_completion(port, slot, 10000)) { + printf("ATA operation timed out\n"); + return -1; + } + + process_responses(port); + + /* Invalidate data on read */ + if (buffer && len) { + start = (u32)buffer & ~(ARCH_DMA_MINALIGN - 1); + invalidate_dcache_range(start, + start + ALIGN(len, ARCH_DMA_MINALIGN)); + } + + return len; +} + +static u32 mv_sata_rw_cmd_ext(int port, lbaint_t start, u32 blkcnt, + u8 *buffer, int is_write) +{ + struct sata_fis_h2d cfis; + u32 res; + u64 block; + + block = (u64)start; + + memset(&cfis, 0, sizeof(struct sata_fis_h2d)); + + cfis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; + cfis.command = (is_write) ? ATA_CMD_WRITE_EXT : ATA_CMD_READ_EXT; + + cfis.lba_high_exp = (block >> 40) & 0xff; + cfis.lba_mid_exp = (block >> 32) & 0xff; + cfis.lba_low_exp = (block >> 24) & 0xff; + cfis.lba_high = (block >> 16) & 0xff; + cfis.lba_mid = (block >> 8) & 0xff; + cfis.lba_low = block & 0xff; + cfis.device = ATA_LBA; + cfis.sector_count_exp = (blkcnt >> 8) & 0xff; + cfis.sector_count = blkcnt & 0xff; + + res = mv_ata_exec_ata_cmd(port, &cfis, buffer, ATA_SECT_SIZE * blkcnt, + is_write); + + return res >= 0 ? blkcnt : res; +} + +static u32 mv_sata_rw_cmd(int port, lbaint_t start, u32 blkcnt, u8 *buffer, + int is_write) +{ + struct sata_fis_h2d cfis; + lbaint_t block; + u32 res; + + block = start; + + memset(&cfis, 0, sizeof(struct sata_fis_h2d)); + + cfis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; + cfis.command = (is_write) ? ATA_CMD_WRITE : ATA_CMD_READ; + cfis.device = ATA_LBA; + + cfis.device |= (block >> 24) & 0xf; + cfis.lba_high = (block >> 16) & 0xff; + cfis.lba_mid = (block >> 8) & 0xff; + cfis.lba_low = block & 0xff; + cfis.sector_count = (u8)(blkcnt & 0xff); + + res = mv_ata_exec_ata_cmd(port, &cfis, buffer, ATA_SECT_SIZE * blkcnt, + is_write); + + return res >= 0 ? blkcnt : res; +} + +static u32 ata_low_level_rw(int dev, lbaint_t blknr, lbaint_t blkcnt, + void *buffer, int is_write) +{ + lbaint_t start, blks; + u8 *addr; + int max_blks; + + debug("%s: %ld %ld\n", __func__, blknr, blkcnt); + + start = blknr; + blks = blkcnt; + addr = (u8 *)buffer; + + max_blks = MV_ATA_MAX_SECTORS; + do { + if (blks > max_blks) { + if (sata_dev_desc[dev].lba48) { + mv_sata_rw_cmd_ext(dev, start, max_blks, addr, + is_write); + } else { + mv_sata_rw_cmd(dev, start, max_blks, addr, + is_write); + } + start += max_blks; + blks -= max_blks; + addr += ATA_SECT_SIZE * max_blks; + } else { + if (sata_dev_desc[dev].lba48) { + mv_sata_rw_cmd_ext(dev, start, blks, addr, + is_write); + } else { + mv_sata_rw_cmd(dev, start, blks, addr, + is_write); + } + start += blks; + blks = 0; + addr += ATA_SECT_SIZE * blks; + } + } while (blks != 0); + + return blkcnt; +} + +static int mv_ata_exec_ata_cmd_nondma(int port, + struct sata_fis_h2d *cfis, u8 *buffer, + u32 len, u32 iswrite) +{ + struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; + int i; + u16 *tp; + + debug("%s\n", __func__); + + out_le32(priv->regbase + PIO_SECTOR_COUNT, cfis->sector_count); + out_le32(priv->regbase + PIO_LBA_HI, cfis->lba_high); + out_le32(priv->regbase + PIO_LBA_MID, cfis->lba_mid); + out_le32(priv->regbase + PIO_LBA_LOW, cfis->lba_low); + out_le32(priv->regbase + PIO_ERR_FEATURES, cfis->features); + out_le32(priv->regbase + PIO_DEVICE, cfis->device); + out_le32(priv->regbase + PIO_CMD_STATUS, cfis->command); + + if (ata_wait_register((u32 *)(priv->regbase + PIO_CMD_STATUS), + ATA_BUSY, 0x0, 10000)) { + debug("Failed to wait for completion\n"); + return -1; + } + + if (len > 0) { + tp = (u16 *)buffer; + for (i = 0; i < len / 2; i++) { + if (iswrite) + out_le16(priv->regbase + PIO_DATA, *tp++); + else + *tp++ = in_le16(priv->regbase + PIO_DATA); + } + } + + return len; +} + +static int mv_sata_identify(int port, u16 *id) +{ + struct sata_fis_h2d h2d; + + memset(&h2d, 0, sizeof(struct sata_fis_h2d)); + + h2d.fis_type = SATA_FIS_TYPE_REGISTER_H2D; + h2d.command = ATA_CMD_ID_ATA; + + /* Give device time to get operational */ + mdelay(10); + + return mv_ata_exec_ata_cmd_nondma(port, &h2d, (u8 *)id, + ATA_ID_WORDS * 2, READ_CMD); +} + +static void mv_sata_xfer_mode(int port, u16 *id) +{ + struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; + + priv->pio = id[ATA_ID_PIO_MODES]; + priv->mwdma = id[ATA_ID_MWDMA_MODES]; + priv->udma = id[ATA_ID_UDMA_MODES]; + debug("pio %04x, mwdma %04x, udma %04x\n", priv->pio, priv->mwdma, + priv->udma); +} + +static void mv_sata_set_features(int port) +{ + struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; + struct sata_fis_h2d cfis; + u8 udma_cap; + + memset(&cfis, 0, sizeof(struct sata_fis_h2d)); + + cfis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; + cfis.command = ATA_CMD_SET_FEATURES; + cfis.features = SETFEATURES_XFER; + + /* First check the device capablity */ + udma_cap = (u8) (priv->udma & 0xff); + + if (udma_cap == ATA_UDMA6) + cfis.sector_count = XFER_UDMA_6; + if (udma_cap == ATA_UDMA5) + cfis.sector_count = XFER_UDMA_5; + if (udma_cap == ATA_UDMA4) + cfis.sector_count = XFER_UDMA_4; + if (udma_cap == ATA_UDMA3) + cfis.sector_count = XFER_UDMA_3; + + mv_ata_exec_ata_cmd_nondma(port, &cfis, NULL, 0, READ_CMD); +} + +int mv_sata_spin_down(int dev) +{ + struct sata_fis_h2d cfis; + struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[dev].priv; + + if (priv->link == 0) { + debug("No device on port: %d\n", dev); + return 1; + } + + memset(&cfis, 0, sizeof(struct sata_fis_h2d)); + + cfis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; + cfis.command = ATA_CMD_STANDBY; + + return mv_ata_exec_ata_cmd_nondma(dev, &cfis, NULL, 0, READ_CMD); +} + +int mv_sata_spin_up(int dev) +{ + struct sata_fis_h2d cfis; + struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[dev].priv; + + if (priv->link == 0) { + debug("No device on port: %d\n", dev); + return 1; + } + + memset(&cfis, 0, sizeof(struct sata_fis_h2d)); + + cfis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; + cfis.command = ATA_CMD_IDLE; + + return mv_ata_exec_ata_cmd_nondma(dev, &cfis, NULL, 0, READ_CMD); +} + +ulong sata_read(int dev, ulong blknr, lbaint_t blkcnt, void *buffer) +{ + return ata_low_level_rw(dev, blknr, blkcnt, buffer, READ_CMD); +} + +ulong sata_write(int dev, ulong blknr, lbaint_t blkcnt, const void *buffer) +{ + return ata_low_level_rw(dev, blknr, blkcnt, (void *)buffer, WRITE_CMD); +} + +/* + * Initialize SATA memory windows + */ +static void mvsata_ide_conf_mbus_windows(void) +{ + const struct mbus_dram_target_info *dram; + int i; + + dram = mvebu_mbus_dram_info(); + + /* Disable windows, Set Size/Base to 0 */ + for (i = 0; i < 4; i++) { + writel(0, MVSATA_WIN_CONTROL(i)); + writel(0, MVSATA_WIN_BASE(i)); + } + + for (i = 0; i < dram->num_cs; i++) { + const struct mbus_dram_window *cs = dram->cs + i; + writel(((cs->size - 1) & 0xffff0000) | (cs->mbus_attr << 8) | + (dram->mbus_dram_target_id << 4) | 1, + MVSATA_WIN_CONTROL(i)); + writel(cs->base & 0xffff0000, MVSATA_WIN_BASE(i)); + } +} + +int init_sata(int dev) +{ + struct mv_priv *priv; + + debug("Initialize sata dev: %d\n", dev); + + if (dev < 0 || dev >= CONFIG_SYS_SATA_MAX_DEVICE) { + printf("Invalid sata device %d\n", dev); + return -1; + } + + priv = (struct mv_priv *)malloc(sizeof(struct mv_priv)); + if (!priv) { + printf("Failed to allocate memory for private sata data\n"); + return -ENOMEM; + } + + memset((void *)priv, 0, sizeof(struct mv_priv)); + + /* Allocate and align request buffer */ + priv->crqb_alloc = malloc(sizeof(struct crqb) * REQUEST_QUEUE_SIZE + + CRQB_ALIGN); + if (!priv->crqb_alloc) { + printf("Unable to allocate memory for request queue\n"); + return -ENOMEM; + } + memset(priv->crqb_alloc, 0, + sizeof(struct crqb) * REQUEST_QUEUE_SIZE + CRQB_ALIGN); + priv->request = (struct crqb *)(((u32) priv->crqb_alloc + CRQB_ALIGN) & + ~(CRQB_ALIGN - 1)); + + /* Allocate and align response buffer */ + priv->crpb_alloc = malloc(sizeof(struct crpb) * REQUEST_QUEUE_SIZE + + CRPB_ALIGN); + if (!priv->crpb_alloc) { + printf("Unable to allocate memory for response queue\n"); + return -ENOMEM; + } + memset(priv->crpb_alloc, 0, + sizeof(struct crpb) * REQUEST_QUEUE_SIZE + CRPB_ALIGN); + priv->response = (struct crpb *)(((u32) priv->crpb_alloc + CRPB_ALIGN) & + ~(CRPB_ALIGN - 1)); + + sata_dev_desc[dev].priv = (void *)priv; + + sprintf(priv->name, "SATA%d", dev); + + priv->regbase = dev == 0 ? SATA0_BASE : SATA1_BASE; + + if (!hw_init) { + debug("Initialize sata hw\n"); + hw_init = 1; + mv_reset_one_hc(); + mvsata_ide_conf_mbus_windows(); + } + + mv_reset_port(dev); + + if (probe_port(dev)) { + priv->link = 0; + return -ENODEV; + } + priv->link = 1; + + return 0; +} + +int reset_sata(int dev) +{ + return 0; +} + +int scan_sata(int port) +{ + unsigned char serial[ATA_ID_SERNO_LEN + 1]; + unsigned char firmware[ATA_ID_FW_REV_LEN + 1]; + unsigned char product[ATA_ID_PROD_LEN + 1]; + u64 n_sectors; + u16 *id; + struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; + + if (!priv->link) + return -ENODEV; + + id = (u16 *)malloc(ATA_ID_WORDS * 2); + if (!id) { + printf("Failed to malloc id data\n"); + return -ENOMEM; + } + + mv_sata_identify(port, id); + ata_swap_buf_le16(id, ATA_ID_WORDS); +#ifdef DEBUG + ata_dump_id(id); +#endif + + /* Serial number */ + ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial)); + memcpy(sata_dev_desc[port].product, serial, sizeof(serial)); + + /* Firmware version */ + ata_id_c_string(id, firmware, ATA_ID_FW_REV, sizeof(firmware)); + memcpy(sata_dev_desc[port].revision, firmware, sizeof(firmware)); + + /* Product model */ + ata_id_c_string(id, product, ATA_ID_PROD, sizeof(product)); + memcpy(sata_dev_desc[port].vendor, product, sizeof(product)); + + /* Total sectors */ + n_sectors = ata_id_n_sectors(id); + sata_dev_desc[port].lba = n_sectors; + + /* Check if support LBA48 */ + if (ata_id_has_lba48(id)) { + sata_dev_desc[port].lba48 = 1; + debug("Device support LBA48\n"); + } + + /* Get the NCQ queue depth from device */ + priv->queue_depth = ata_id_queue_depth(id); + + /* Get the xfer mode from device */ + mv_sata_xfer_mode(port, id); + + /* Set the xfer mode to highest speed */ + mv_sata_set_features(port); + + /* Start up */ + mv_start_edma_engine(port); + + return 0; +} diff --git a/drivers/ata/sata_sandbox.c b/drivers/ata/sata_sandbox.c new file mode 100644 index 0000000..bd967d2 --- /dev/null +++ b/drivers/ata/sata_sandbox.c @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2015 Google, Inc + * Written by Simon Glass + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include + +int init_sata(int dev) +{ + return 0; +} + +int reset_sata(int dev) +{ + return 0; +} + +int scan_sata(int dev) +{ + return 0; +} + +ulong sata_read(int dev, ulong blknr, lbaint_t blkcnt, void *buffer) +{ + return 0; +} + +ulong sata_write(int dev, ulong blknr, lbaint_t blkcnt, const void *buffer) +{ + return 0; +} diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c new file mode 100644 index 0000000..daff7d4 --- /dev/null +++ b/drivers/ata/sata_sil.c @@ -0,0 +1,715 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. + * Author: Tang Yuantian + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sata_sil.h" + +/* Convert sectorsize to wordsize */ +#define ATA_SECTOR_WORDS (ATA_SECT_SIZE/2) +#define virt_to_bus(devno, v) pci_virt_to_mem(devno, (void *) (v)) + +static struct sata_info sata_info; + +static struct pci_device_id supported[] = { + {PCI_VENDOR_ID_SILICONIMAGE, PCI_DEVICE_ID_SIL3131}, + {PCI_VENDOR_ID_SILICONIMAGE, PCI_DEVICE_ID_SIL3132}, + {PCI_VENDOR_ID_SILICONIMAGE, PCI_DEVICE_ID_SIL3124}, + {} +}; + +static void sil_sata_dump_fis(struct sata_fis_d2h *s) +{ + printf("Status FIS dump:\n"); + printf("fis_type: %02x\n", s->fis_type); + printf("pm_port_i: %02x\n", s->pm_port_i); + printf("status: %02x\n", s->status); + printf("error: %02x\n", s->error); + printf("lba_low: %02x\n", s->lba_low); + printf("lba_mid: %02x\n", s->lba_mid); + printf("lba_high: %02x\n", s->lba_high); + printf("device: %02x\n", s->device); + printf("lba_low_exp: %02x\n", s->lba_low_exp); + printf("lba_mid_exp: %02x\n", s->lba_mid_exp); + printf("lba_high_exp: %02x\n", s->lba_high_exp); + printf("res1: %02x\n", s->res1); + printf("sector_count: %02x\n", s->sector_count); + printf("sector_count_exp: %02x\n", s->sector_count_exp); +} + +static const char *sata_spd_string(unsigned int speed) +{ + static const char * const spd_str[] = { + "1.5 Gbps", + "3.0 Gbps", + "6.0 Gbps", + }; + + if ((speed - 1) > 2) + return ""; + + return spd_str[speed - 1]; +} + +static u32 ata_wait_register(void *reg, u32 mask, + u32 val, int timeout_msec) +{ + u32 tmp; + + tmp = readl(reg); + while ((tmp & mask) == val && timeout_msec > 0) { + mdelay(1); + timeout_msec--; + tmp = readl(reg); + } + + return tmp; +} + +static void sil_config_port(void *port) +{ + /* configure IRQ WoC */ + writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR); + + /* zero error counters. */ + writew(0x8000, port + PORT_DECODE_ERR_THRESH); + writew(0x8000, port + PORT_CRC_ERR_THRESH); + writew(0x8000, port + PORT_HSHK_ERR_THRESH); + writew(0x0000, port + PORT_DECODE_ERR_CNT); + writew(0x0000, port + PORT_CRC_ERR_CNT); + writew(0x0000, port + PORT_HSHK_ERR_CNT); + + /* always use 64bit activation */ + writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR); + + /* clear port multiplier enable and resume bits */ + writel(PORT_CS_PMP_EN | PORT_CS_PMP_RESUME, port + PORT_CTRL_CLR); +} + +static int sil_init_port(void *port) +{ + u32 tmp; + + writel(PORT_CS_INIT, port + PORT_CTRL_STAT); + ata_wait_register(port + PORT_CTRL_STAT, + PORT_CS_INIT, PORT_CS_INIT, 100); + tmp = ata_wait_register(port + PORT_CTRL_STAT, + PORT_CS_RDY, 0, 100); + + if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY) + return 1; + + return 0; +} + +static void sil_read_fis(int dev, int tag, struct sata_fis_d2h *fis) +{ + struct sil_sata *sata = sata_dev_desc[dev].priv; + void *port = sata->port; + struct sil_prb *prb; + int i; + u32 *src, *dst; + + prb = port + PORT_LRAM + tag * PORT_LRAM_SLOT_SZ; + src = (u32 *)&prb->fis; + dst = (u32 *)fis; + for (i = 0; i < sizeof(struct sata_fis_h2d); i += 4) + *dst++ = readl(src++); +} + +static int sil_exec_cmd(int dev, struct sil_cmd_block *pcmd, int tag) +{ + struct sil_sata *sata = sata_dev_desc[dev].priv; + void *port = sata->port; + u64 paddr = virt_to_bus(sata->devno, pcmd); + u32 irq_mask, irq_stat; + int rc; + + writel(PORT_IRQ_COMPLETE | PORT_IRQ_ERROR, port + PORT_IRQ_ENABLE_CLR); + + /* better to add momery barrior here */ + writel((u32)paddr, port + PORT_CMD_ACTIVATE + tag * 8); + writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + tag * 8 + 4); + + irq_mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT; + irq_stat = ata_wait_register(port + PORT_IRQ_STAT, irq_mask, + 0, 10000); + + /* clear IRQs */ + writel(irq_mask, port + PORT_IRQ_STAT); + irq_stat >>= PORT_IRQ_RAW_SHIFT; + + if (irq_stat & PORT_IRQ_COMPLETE) + rc = 0; + else { + /* force port into known state */ + sil_init_port(port); + if (irq_stat & PORT_IRQ_ERROR) + rc = 1; /* error */ + else + rc = 2; /* busy */ + } + + return rc; +} + +static int sil_cmd_set_feature(int dev) +{ + struct sil_sata *sata = sata_dev_desc[dev].priv; + struct sil_cmd_block cmdb, *pcmd = &cmdb; + struct sata_fis_d2h fis; + u8 udma_cap; + int ret; + + memset((void *)&cmdb, 0, sizeof(struct sil_cmd_block)); + pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; + pcmd->prb.fis.pm_port_c = (1 << 7); + pcmd->prb.fis.command = ATA_CMD_SET_FEATURES; + pcmd->prb.fis.features = SETFEATURES_XFER; + + /* First check the device capablity */ + udma_cap = (u8)(sata->udma & 0xff); + debug("udma_cap %02x\n", udma_cap); + + if (udma_cap == ATA_UDMA6) + pcmd->prb.fis.sector_count = XFER_UDMA_6; + if (udma_cap == ATA_UDMA5) + pcmd->prb.fis.sector_count = XFER_UDMA_5; + if (udma_cap == ATA_UDMA4) + pcmd->prb.fis.sector_count = XFER_UDMA_4; + if (udma_cap == ATA_UDMA3) + pcmd->prb.fis.sector_count = XFER_UDMA_3; + + ret = sil_exec_cmd(dev, pcmd, 0); + if (ret) { + sil_read_fis(dev, 0, &fis); + printf("Err: exe cmd(0x%x).\n", + readl(sata->port + PORT_SERROR)); + sil_sata_dump_fis(&fis); + return 1; + } + + return 0; +} + +static int sil_cmd_identify_device(int dev, u16 *id) +{ + struct sil_sata *sata = sata_dev_desc[dev].priv; + struct sil_cmd_block cmdb, *pcmd = &cmdb; + struct sata_fis_d2h fis; + int ret; + + memset((void *)&cmdb, 0, sizeof(struct sil_cmd_block)); + pcmd->prb.ctrl = cpu_to_le16(PRB_CTRL_PROTOCOL); + pcmd->prb.prot = cpu_to_le16(PRB_PROT_READ); + pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; + pcmd->prb.fis.pm_port_c = (1 << 7); + pcmd->prb.fis.command = ATA_CMD_ID_ATA; + pcmd->sge.addr = cpu_to_le64(virt_to_bus(sata->devno, id)); + pcmd->sge.cnt = cpu_to_le32(sizeof(id[0]) * ATA_ID_WORDS); + pcmd->sge.flags = cpu_to_le32(SGE_TRM); + + ret = sil_exec_cmd(dev, pcmd, 0); + if (ret) { + sil_read_fis(dev, 0, &fis); + printf("Err: id cmd(0x%x).\n", readl(sata->port + PORT_SERROR)); + sil_sata_dump_fis(&fis); + return 1; + } + ata_swap_buf_le16(id, ATA_ID_WORDS); + + return 0; +} + +static int sil_cmd_soft_reset(int dev) +{ + struct sil_cmd_block cmdb, *pcmd = &cmdb; + struct sil_sata *sata = sata_dev_desc[dev].priv; + struct sata_fis_d2h fis; + void *port = sata->port; + int ret; + + /* put the port into known state */ + if (sil_init_port(port)) { + printf("SRST: port %d not ready\n", dev); + return 1; + } + + memset((void *)&cmdb, 0, sizeof(struct sil_cmd_block)); + + pcmd->prb.ctrl = cpu_to_le16(PRB_CTRL_SRST); + pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; + pcmd->prb.fis.pm_port_c = 0xf; + + ret = sil_exec_cmd(dev, &cmdb, 0); + if (ret) { + sil_read_fis(dev, 0, &fis); + printf("SRST cmd error.\n"); + sil_sata_dump_fis(&fis); + return 1; + } + + return 0; +} + +static ulong sil_sata_rw_cmd(int dev, ulong start, ulong blkcnt, + u8 *buffer, int is_write) +{ + struct sil_sata *sata = sata_dev_desc[dev].priv; + struct sil_cmd_block cmdb, *pcmd = &cmdb; + struct sata_fis_d2h fis; + u64 block; + int ret; + + block = (u64)start; + memset(pcmd, 0, sizeof(struct sil_cmd_block)); + pcmd->prb.ctrl = cpu_to_le16(PRB_CTRL_PROTOCOL); + pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; + pcmd->prb.fis.pm_port_c = (1 << 7); + if (is_write) { + pcmd->prb.fis.command = ATA_CMD_WRITE; + pcmd->prb.prot = cpu_to_le16(PRB_PROT_WRITE); + } else { + pcmd->prb.fis.command = ATA_CMD_READ; + pcmd->prb.prot = cpu_to_le16(PRB_PROT_READ); + } + + pcmd->prb.fis.device = ATA_LBA; + pcmd->prb.fis.device |= (block >> 24) & 0xf; + pcmd->prb.fis.lba_high = (block >> 16) & 0xff; + pcmd->prb.fis.lba_mid = (block >> 8) & 0xff; + pcmd->prb.fis.lba_low = block & 0xff; + pcmd->prb.fis.sector_count = (u8)blkcnt & 0xff; + + pcmd->sge.addr = cpu_to_le64(virt_to_bus(sata->devno, buffer)); + pcmd->sge.cnt = cpu_to_le32(blkcnt * ATA_SECT_SIZE); + pcmd->sge.flags = cpu_to_le32(SGE_TRM); + + ret = sil_exec_cmd(dev, pcmd, 0); + if (ret) { + sil_read_fis(dev, 0, &fis); + printf("Err: rw cmd(0x%08x).\n", + readl(sata->port + PORT_SERROR)); + sil_sata_dump_fis(&fis); + return 1; + } + + return blkcnt; +} + +static ulong sil_sata_rw_cmd_ext(int dev, ulong start, ulong blkcnt, + u8 *buffer, int is_write) +{ + struct sil_sata *sata = sata_dev_desc[dev].priv; + struct sil_cmd_block cmdb, *pcmd = &cmdb; + struct sata_fis_d2h fis; + u64 block; + int ret; + + block = (u64)start; + memset(pcmd, 0, sizeof(struct sil_cmd_block)); + pcmd->prb.ctrl = cpu_to_le16(PRB_CTRL_PROTOCOL); + pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; + pcmd->prb.fis.pm_port_c = (1 << 7); + if (is_write) { + pcmd->prb.fis.command = ATA_CMD_WRITE_EXT; + pcmd->prb.prot = cpu_to_le16(PRB_PROT_WRITE); + } else { + pcmd->prb.fis.command = ATA_CMD_READ_EXT; + pcmd->prb.prot = cpu_to_le16(PRB_PROT_READ); + } + + pcmd->prb.fis.lba_high_exp = (block >> 40) & 0xff; + pcmd->prb.fis.lba_mid_exp = (block >> 32) & 0xff; + pcmd->prb.fis.lba_low_exp = (block >> 24) & 0xff; + pcmd->prb.fis.lba_high = (block >> 16) & 0xff; + pcmd->prb.fis.lba_mid = (block >> 8) & 0xff; + pcmd->prb.fis.lba_low = block & 0xff; + pcmd->prb.fis.device = ATA_LBA; + pcmd->prb.fis.sector_count_exp = (blkcnt >> 8) & 0xff; + pcmd->prb.fis.sector_count = blkcnt & 0xff; + + pcmd->sge.addr = cpu_to_le64(virt_to_bus(sata->devno, buffer)); + pcmd->sge.cnt = cpu_to_le32(blkcnt * ATA_SECT_SIZE); + pcmd->sge.flags = cpu_to_le32(SGE_TRM); + + ret = sil_exec_cmd(dev, pcmd, 0); + if (ret) { + sil_read_fis(dev, 0, &fis); + printf("Err: rw ext cmd(0x%08x).\n", + readl(sata->port + PORT_SERROR)); + sil_sata_dump_fis(&fis); + return 1; + } + + return blkcnt; +} + +static ulong sil_sata_rw_lba28(int dev, ulong blknr, lbaint_t blkcnt, + const void *buffer, int is_write) +{ + ulong start, blks, max_blks; + u8 *addr; + + start = blknr; + blks = blkcnt; + addr = (u8 *)buffer; + + max_blks = ATA_MAX_SECTORS; + do { + if (blks > max_blks) { + sil_sata_rw_cmd(dev, start, max_blks, addr, is_write); + start += max_blks; + blks -= max_blks; + addr += ATA_SECT_SIZE * max_blks; + } else { + sil_sata_rw_cmd(dev, start, blks, addr, is_write); + start += blks; + blks = 0; + addr += ATA_SECT_SIZE * blks; + } + } while (blks != 0); + + return blkcnt; +} + +static ulong sil_sata_rw_lba48(int dev, ulong blknr, lbaint_t blkcnt, + const void *buffer, int is_write) +{ + ulong start, blks, max_blks; + u8 *addr; + + start = blknr; + blks = blkcnt; + addr = (u8 *)buffer; + + max_blks = ATA_MAX_SECTORS_LBA48; + do { + if (blks > max_blks) { + sil_sata_rw_cmd_ext(dev, start, max_blks, + addr, is_write); + start += max_blks; + blks -= max_blks; + addr += ATA_SECT_SIZE * max_blks; + } else { + sil_sata_rw_cmd_ext(dev, start, blks, + addr, is_write); + start += blks; + blks = 0; + addr += ATA_SECT_SIZE * blks; + } + } while (blks != 0); + + return blkcnt; +} + +static void sil_sata_cmd_flush_cache(int dev) +{ + struct sil_cmd_block cmdb, *pcmd = &cmdb; + + memset((void *)pcmd, 0, sizeof(struct sil_cmd_block)); + pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; + pcmd->prb.fis.pm_port_c = (1 << 7); + pcmd->prb.fis.command = ATA_CMD_FLUSH; + + sil_exec_cmd(dev, pcmd, 0); +} + +static void sil_sata_cmd_flush_cache_ext(int dev) +{ + struct sil_cmd_block cmdb, *pcmd = &cmdb; + + memset((void *)pcmd, 0, sizeof(struct sil_cmd_block)); + pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; + pcmd->prb.fis.pm_port_c = (1 << 7); + pcmd->prb.fis.command = ATA_CMD_FLUSH_EXT; + + sil_exec_cmd(dev, pcmd, 0); +} + +static void sil_sata_init_wcache(int dev, u16 *id) +{ + struct sil_sata *sata = sata_dev_desc[dev].priv; + + if (ata_id_has_wcache(id) && ata_id_wcache_enabled(id)) + sata->wcache = 1; + if (ata_id_has_flush(id)) + sata->flush = 1; + if (ata_id_has_flush_ext(id)) + sata->flush_ext = 1; +} + +static int sil_sata_get_wcache(int dev) +{ + struct sil_sata *sata = sata_dev_desc[dev].priv; + + return sata->wcache; +} + +static int sil_sata_get_flush(int dev) +{ + struct sil_sata *sata = sata_dev_desc[dev].priv; + + return sata->flush; +} + +static int sil_sata_get_flush_ext(int dev) +{ + struct sil_sata *sata = sata_dev_desc[dev].priv; + + return sata->flush_ext; +} + +/* + * SATA interface between low level driver and command layer + */ +ulong sata_read(int dev, ulong blknr, lbaint_t blkcnt, void *buffer) +{ + struct sil_sata *sata = sata_dev_desc[dev].priv; + ulong rc; + + if (sata->lba48) + rc = sil_sata_rw_lba48(dev, blknr, blkcnt, buffer, READ_CMD); + else + rc = sil_sata_rw_lba28(dev, blknr, blkcnt, buffer, READ_CMD); + + return rc; +} + +/* + * SATA interface between low level driver and command layer + */ +ulong sata_write(int dev, ulong blknr, lbaint_t blkcnt, const void *buffer) +{ + struct sil_sata *sata = sata_dev_desc[dev].priv; + ulong rc; + + if (sata->lba48) { + rc = sil_sata_rw_lba48(dev, blknr, blkcnt, buffer, WRITE_CMD); + if (sil_sata_get_wcache(dev) && sil_sata_get_flush_ext(dev)) + sil_sata_cmd_flush_cache_ext(dev); + } else { + rc = sil_sata_rw_lba28(dev, blknr, blkcnt, buffer, WRITE_CMD); + if (sil_sata_get_wcache(dev) && sil_sata_get_flush(dev)) + sil_sata_cmd_flush_cache(dev); + } + + return rc; +} + +/* + * SATA interface between low level driver and command layer + */ +int init_sata(int dev) +{ + static int init_done, idx; + pci_dev_t devno; + u16 word; + + if (init_done == 1 && dev < sata_info.maxport) + return 0; + + init_done = 1; + + /* Find PCI device(s) */ + devno = pci_find_devices(supported, idx++); + if (devno == -1) + return 1; + + pci_read_config_word(devno, PCI_DEVICE_ID, &word); + + /* get the port count */ + word &= 0xf; + + sata_info.portbase = sata_info.maxport; + sata_info.maxport = sata_info.portbase + word; + sata_info.devno = devno; + + /* Read out all BARs */ + sata_info.iobase[0] = (ulong)pci_map_bar(devno, + PCI_BASE_ADDRESS_0, PCI_REGION_MEM); + sata_info.iobase[1] = (ulong)pci_map_bar(devno, + PCI_BASE_ADDRESS_2, PCI_REGION_MEM); + sata_info.iobase[2] = (ulong)pci_map_bar(devno, + PCI_BASE_ADDRESS_4, PCI_REGION_MEM); + + /* mask out the unused bits */ + sata_info.iobase[0] &= 0xffffff80; + sata_info.iobase[1] &= 0xfffffc00; + sata_info.iobase[2] &= 0xffffff80; + + /* Enable Bus Mastering and memory region */ + pci_write_config_word(devno, PCI_COMMAND, + PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + + /* Check if mem accesses and Bus Mastering are enabled. */ + pci_read_config_word(devno, PCI_COMMAND, &word); + if (!(word & PCI_COMMAND_MEMORY) || + (!(word & PCI_COMMAND_MASTER))) { + printf("Error: Can not enable MEM access or Bus Mastering.\n"); + debug("PCI command: %04x\n", word); + return 1; + } + + /* GPIO off */ + writel(0, (void *)(sata_info.iobase[0] + HOST_FLASH_CMD)); + /* clear global reset & mask interrupts during initialization */ + writel(0, (void *)(sata_info.iobase[0] + HOST_CTRL)); + + return 0; +} + +int reset_sata(int dev) +{ + return 0; +} + +/* + * SATA interface between low level driver and command layer + */ +int scan_sata(int dev) +{ + unsigned char serial[ATA_ID_SERNO_LEN + 1]; + unsigned char firmware[ATA_ID_FW_REV_LEN + 1]; + unsigned char product[ATA_ID_PROD_LEN + 1]; + struct sil_sata *sata; + void *port; + int cnt; + u16 *id; + u32 tmp; + + if (dev >= sata_info.maxport) { + printf("SATA#%d is not present\n", dev); + return 1; + } + + printf("SATA#%d\n", dev); + port = (void *)sata_info.iobase[1] + + PORT_REGS_SIZE * (dev - sata_info.portbase); + + /* Initial PHY setting */ + writel(0x20c, port + PORT_PHY_CFG); + + /* clear port RST */ + tmp = readl(port + PORT_CTRL_STAT); + if (tmp & PORT_CS_PORT_RST) { + writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR); + tmp = ata_wait_register(port + PORT_CTRL_STAT, + PORT_CS_PORT_RST, PORT_CS_PORT_RST, 100); + if (tmp & PORT_CS_PORT_RST) + printf("Err: Failed to clear port RST\n"); + } + + /* Check if device is present */ + for (cnt = 0; cnt < 100; cnt++) { + tmp = readl(port + PORT_SSTATUS); + if ((tmp & 0xF) == 0x3) + break; + mdelay(1); + } + + tmp = readl(port + PORT_SSTATUS); + if ((tmp & 0xf) != 0x3) { + printf(" (No RDY)\n"); + return 1; + } + + /* Wait for port ready */ + tmp = ata_wait_register(port + PORT_CTRL_STAT, + PORT_CS_RDY, PORT_CS_RDY, 100); + if ((tmp & PORT_CS_RDY) != PORT_CS_RDY) { + printf("%d port not ready.\n", dev); + return 1; + } + + /* configure port */ + sil_config_port(port); + + /* Reset port */ + writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT); + readl(port + PORT_CTRL_STAT); + tmp = ata_wait_register(port + PORT_CTRL_STAT, PORT_CS_DEV_RST, + PORT_CS_DEV_RST, 100); + if (tmp & PORT_CS_DEV_RST) { + printf("%d port reset failed.\n", dev); + return 1; + } + + sata = (struct sil_sata *)malloc(sizeof(struct sil_sata)); + if (!sata) { + printf("%d no memory.\n", dev); + return 1; + } + memset((void *)sata, 0, sizeof(struct sil_sata)); + + /* turn on port interrupt */ + tmp = readl((void *)(sata_info.iobase[0] + HOST_CTRL)); + tmp |= (1 << (dev - sata_info.portbase)); + writel(tmp, (void *)(sata_info.iobase[0] + HOST_CTRL)); + + /* Save the private struct to block device struct */ + sata_dev_desc[dev].priv = (void *)sata; + sata->port = port; + sata->devno = sata_info.devno; + sprintf(sata->name, "SATA#%d", dev); + sil_cmd_soft_reset(dev); + tmp = readl(port + PORT_SSTATUS); + tmp = (tmp >> 4) & 0xf; + printf(" (%s)\n", sata_spd_string(tmp)); + + id = (u16 *)malloc(ATA_ID_WORDS * 2); + if (!id) { + printf("Id malloc failed\n"); + free((void *)sata); + return 1; + } + sil_cmd_identify_device(dev, id); + +#ifdef CONFIG_LBA48 + /* Check if support LBA48 */ + if (ata_id_has_lba48(id)) { + sata_dev_desc[dev].lba48 = 1; + sata->lba48 = 1; + debug("Device supports LBA48\n"); + } else + debug("Device supports LBA28\n"); +#endif + + /* Serial number */ + ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial)); + memcpy(sata_dev_desc[dev].product, serial, sizeof(serial)); + + /* Firmware version */ + ata_id_c_string(id, firmware, ATA_ID_FW_REV, sizeof(firmware)); + memcpy(sata_dev_desc[dev].revision, firmware, sizeof(firmware)); + + /* Product model */ + ata_id_c_string(id, product, ATA_ID_PROD, sizeof(product)); + memcpy(sata_dev_desc[dev].vendor, product, sizeof(product)); + + /* Totoal sectors */ + sata_dev_desc[dev].lba = ata_id_n_sectors(id); + + sil_sata_init_wcache(dev, id); + sil_cmd_set_feature(dev); + +#ifdef DEBUG + sil_cmd_identify_device(dev, id); + ata_dump_id(id); +#endif + free((void *)id); + + return 0; +} diff --git a/drivers/ata/sata_sil.h b/drivers/ata/sata_sil.h new file mode 100644 index 0000000..55954ef --- /dev/null +++ b/drivers/ata/sata_sil.h @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. + * Author: Tang Yuantian + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef SATA_SIL3132_H +#define SATA_SIL3132_H + +#define READ_CMD 0 +#define WRITE_CMD 1 + +/* + * SATA device driver struct for each dev + */ +struct sil_sata { + char name[12]; + void *port; /* the port base address */ + int lba48; + u16 pio; + u16 mwdma; + u16 udma; + pci_dev_t devno; + int wcache; + int flush; + int flush_ext; +}; + +/* sata info for each controller */ +struct sata_info { + ulong iobase[3]; + pci_dev_t devno; + int portbase; + int maxport; +}; + +/* + * Scatter gather entry (SGE),MUST 8 bytes aligned + */ +struct sil_sge { + __le64 addr; + __le32 cnt; + __le32 flags; +} __attribute__ ((aligned(8), packed)); + +/* + * Port request block, MUST 8 bytes aligned + */ +struct sil_prb { + __le16 ctrl; + __le16 prot; + __le32 rx_cnt; + struct sata_fis_h2d fis; +} __attribute__ ((aligned(8), packed)); + +struct sil_cmd_block { + struct sil_prb prb; + struct sil_sge sge; +}; + +enum { + HOST_SLOT_STAT = 0x00, /* 32 bit slot stat * 4 */ + HOST_CTRL = 0x40, + HOST_IRQ_STAT = 0x44, + HOST_PHY_CFG = 0x48, + HOST_BIST_CTRL = 0x50, + HOST_BIST_PTRN = 0x54, + HOST_BIST_STAT = 0x58, + HOST_MEM_BIST_STAT = 0x5c, + HOST_FLASH_CMD = 0x70, + /* 8 bit regs */ + HOST_FLASH_DATA = 0x74, + HOST_TRANSITION_DETECT = 0x75, + HOST_GPIO_CTRL = 0x76, + HOST_I2C_ADDR = 0x78, /* 32 bit */ + HOST_I2C_DATA = 0x7c, + HOST_I2C_XFER_CNT = 0x7e, + HOST_I2C_CTRL = 0x7f, + + /* HOST_SLOT_STAT bits */ + HOST_SSTAT_ATTN = (1 << 31), + + /* HOST_CTRL bits */ + HOST_CTRL_M66EN = (1 << 16), /* M66EN PCI bus signal */ + HOST_CTRL_TRDY = (1 << 17), /* latched PCI TRDY */ + HOST_CTRL_STOP = (1 << 18), /* latched PCI STOP */ + HOST_CTRL_DEVSEL = (1 << 19), /* latched PCI DEVSEL */ + HOST_CTRL_REQ64 = (1 << 20), /* latched PCI REQ64 */ + HOST_CTRL_GLOBAL_RST = (1 << 31), /* global reset */ + + /* + * Port registers + * (8192 bytes @ +0x0000, +0x2000, +0x4000 and +0x6000 @ BAR2) + */ + PORT_REGS_SIZE = 0x2000, + + PORT_LRAM = 0x0000, /* 31 LRAM slots and PMP regs */ + PORT_LRAM_SLOT_SZ = 0x0080, /* 32 bytes PRB + 2 SGE, ACT... */ + + PORT_PMP = 0x0f80, /* 8 bytes PMP * 16 (128 bytes) */ + PORT_PMP_STATUS = 0x0000, /* port device status offset */ + PORT_PMP_QACTIVE = 0x0004, /* port device QActive offset */ + PORT_PMP_SIZE = 0x0008, /* 8 bytes per PMP */ + + /* 32 bit regs */ + PORT_CTRL_STAT = 0x1000, /* write: ctrl-set, read: stat */ + PORT_CTRL_CLR = 0x1004, /* write: ctrl-clear */ + PORT_IRQ_STAT = 0x1008, /* high: status, low: interrupt */ + PORT_IRQ_ENABLE_SET = 0x1010, /* write: enable-set */ + PORT_IRQ_ENABLE_CLR = 0x1014, /* write: enable-clear */ + PORT_ACTIVATE_UPPER_ADDR = 0x101c, + PORT_EXEC_FIFO = 0x1020, /* command execution fifo */ + PORT_CMD_ERR = 0x1024, /* command error number */ + PORT_FIS_CFG = 0x1028, + PORT_FIFO_THRES = 0x102c, + + /* 16 bit regs */ + PORT_DECODE_ERR_CNT = 0x1040, + PORT_DECODE_ERR_THRESH = 0x1042, + PORT_CRC_ERR_CNT = 0x1044, + PORT_CRC_ERR_THRESH = 0x1046, + PORT_HSHK_ERR_CNT = 0x1048, + PORT_HSHK_ERR_THRESH = 0x104a, + + /* 32 bit regs */ + PORT_PHY_CFG = 0x1050, + PORT_SLOT_STAT = 0x1800, + PORT_CMD_ACTIVATE = 0x1c00, /* 64 bit cmd activate * 31 */ + PORT_CONTEXT = 0x1e04, + PORT_EXEC_DIAG = 0x1e00, /* 32bit exec diag * 16 */ + PORT_PSD_DIAG = 0x1e40, /* 32bit psd diag * 16 */ + PORT_SCONTROL = 0x1f00, + PORT_SSTATUS = 0x1f04, + PORT_SERROR = 0x1f08, + PORT_SACTIVE = 0x1f0c, + + /* PORT_CTRL_STAT bits */ + PORT_CS_PORT_RST = (1 << 0), /* port reset */ + PORT_CS_DEV_RST = (1 << 1), /* device reset */ + PORT_CS_INIT = (1 << 2), /* port initialize */ + PORT_CS_IRQ_WOC = (1 << 3), /* interrupt write one to clear */ + PORT_CS_CDB16 = (1 << 5), /* 0=12b cdb, 1=16b cdb */ + PORT_CS_PMP_RESUME = (1 << 6), /* PMP resume */ + PORT_CS_32BIT_ACTV = (1 << 10), /* 32-bit activation */ + PORT_CS_PMP_EN = (1 << 13), /* port multiplier enable */ + PORT_CS_RDY = (1 << 31), /* port ready to accept commands */ + + /* PORT_IRQ_STAT/ENABLE_SET/CLR */ + /* bits[11:0] are masked */ + PORT_IRQ_COMPLETE = (1 << 0), /* command(s) completed */ + PORT_IRQ_ERROR = (1 << 1), /* command execution error */ + PORT_IRQ_PORTRDY_CHG = (1 << 2), /* port ready change */ + PORT_IRQ_PWR_CHG = (1 << 3), /* power management change */ + PORT_IRQ_PHYRDY_CHG = (1 << 4), /* PHY ready change */ + PORT_IRQ_COMWAKE = (1 << 5), /* COMWAKE received */ + PORT_IRQ_UNK_FIS = (1 << 6), /* unknown FIS received */ + PORT_IRQ_DEV_XCHG = (1 << 7), /* device exchanged */ + PORT_IRQ_8B10B = (1 << 8), /* 8b/10b decode error threshold */ + PORT_IRQ_CRC = (1 << 9), /* CRC error threshold */ + PORT_IRQ_HANDSHAKE = (1 << 10), /* handshake error threshold */ + PORT_IRQ_SDB_NOTIFY = (1 << 11), /* SDB notify received */ + + DEF_PORT_IRQ = PORT_IRQ_COMPLETE | PORT_IRQ_ERROR | + PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG | + PORT_IRQ_UNK_FIS | PORT_IRQ_SDB_NOTIFY, + + /* bits[27:16] are unmasked (raw) */ + PORT_IRQ_RAW_SHIFT = 16, + PORT_IRQ_MASKED_MASK = 0x7ff, + PORT_IRQ_RAW_MASK = (0x7ff << PORT_IRQ_RAW_SHIFT), + + /* ENABLE_SET/CLR specific, intr steering - 2 bit field */ + PORT_IRQ_STEER_SHIFT = 30, + PORT_IRQ_STEER_MASK = (3 << PORT_IRQ_STEER_SHIFT), + + /* PORT_CMD_ERR constants */ + PORT_CERR_DEV = 1, /* Error bit in D2H Register FIS */ + PORT_CERR_SDB = 2, /* Error bit in SDB FIS */ + PORT_CERR_DATA = 3, /* Error in data FIS not detected by dev */ + PORT_CERR_SEND = 4, /* Initial cmd FIS transmission failure */ + PORT_CERR_INCONSISTENT = 5, /* Protocol mismatch */ + PORT_CERR_DIRECTION = 6, /* Data direction mismatch */ + PORT_CERR_UNDERRUN = 7, /* Ran out of SGEs while writing */ + PORT_CERR_OVERRUN = 8, /* Ran out of SGEs while reading */ + + /* bits of PRB control field */ + PRB_CTRL_PROTOCOL = (1 << 0), /* override def. ATA protocol */ + PRB_CTRL_PACKET_READ = (1 << 4), /* PACKET cmd read */ + PRB_CTRL_PACKET_WRITE = (1 << 5), /* PACKET cmd write */ + PRB_CTRL_NIEN = (1 << 6), /* Mask completion irq */ + PRB_CTRL_SRST = (1 << 7), /* Soft reset request (ign BSY?) */ + + /* PRB protocol field */ + PRB_PROT_PACKET = (1 << 0), + PRB_PROT_TCQ = (1 << 1), + PRB_PROT_NCQ = (1 << 2), + PRB_PROT_READ = (1 << 3), + PRB_PROT_WRITE = (1 << 4), + PRB_PROT_TRANSPARENT = (1 << 5), + + /* + * Other constants + */ + SGE_TRM = (1 << 31), /* Last SGE in chain */ + SGE_LNK = (1 << 30), /* linked list + Points to SGT, not SGE */ + SGE_DRD = (1 << 29), /* discard data read (/dev/null) + data address ignored */ + + CMD_ERR = 0x21, +}; + +#endif diff --git a/drivers/ata/sata_sil3114.c b/drivers/ata/sata_sil3114.c new file mode 100644 index 0000000..61ffb66 --- /dev/null +++ b/drivers/ata/sata_sil3114.c @@ -0,0 +1,835 @@ +/* + * Copyright (C) Excito Elektronik i SkÃ¥ne AB, All rights reserved. + * Author: Tor Krill + * + * SPDX-License-Identifier: GPL-2.0+ + * + * This is a driver for Silicon Image sil3114 sata chip modelled on + * the ata_piix driver + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sata_sil3114.h" + +/* Convert sectorsize to wordsize */ +#define ATA_SECTOR_WORDS (ATA_SECT_SIZE/2) + +/* Forwards */ +u8 sil3114_spin_up (int num); +u8 sil3114_spin_down (int num); +static int sata_bus_softreset (int num); +static void sata_identify (int num, int dev); +static u8 check_power_mode (int num); +static void sata_port (struct sata_ioports *ioport); +static void set_Feature_cmd (int num, int dev); +static u8 sata_busy_wait (struct sata_ioports *ioaddr, int bits, + unsigned int max, u8 usealtstatus); +static u8 sata_chk_status (struct sata_ioports *ioaddr, u8 usealtstatus); +static void msleep (int count); + +static u32 iobase[6] = { 0, 0, 0, 0, 0, 0}; /* PCI BAR registers for device */ + +static struct sata_port port[CONFIG_SYS_SATA_MAX_DEVICE]; + +static void output_data (struct sata_ioports *ioaddr, u16 * sect_buf, int words) +{ + while (words--) { + __raw_writew (*sect_buf++, (void *)ioaddr->data_addr); + } +} + +static int input_data (struct sata_ioports *ioaddr, u16 * sect_buf, int words) +{ + while (words--) { + *sect_buf++ = __raw_readw ((void *)ioaddr->data_addr); + } + return 0; +} + +static int sata_bus_softreset (int num) +{ + u8 status = 0; + + port[num].dev_mask = 1; + + port[num].ctl_reg = 0x08; /*Default value of control reg */ + writeb (port[num].ctl_reg, port[num].ioaddr.ctl_addr); + udelay (10); + writeb (port[num].ctl_reg | ATA_SRST, port[num].ioaddr.ctl_addr); + udelay (10); + writeb (port[num].ctl_reg, port[num].ioaddr.ctl_addr); + + /* spec mandates ">= 2ms" before checking status. + * We wait 150ms, because that was the magic delay used for + * ATAPI devices in Hale Landis's ATADRVR, for the period of time + * between when the ATA command register is written, and then + * status is checked. Because waiting for "a while" before + * checking status is fine, post SRST, we perform this magic + * delay here as well. + */ + msleep (150); + status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 300, 0); + while ((status & ATA_BUSY)) { + msleep (100); + status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 3, 0); + } + + if (status & ATA_BUSY) { + printf ("ata%u is slow to respond,plz be patient\n", num); + } + + while ((status & ATA_BUSY)) { + msleep (100); + status = sata_chk_status (&port[num].ioaddr, 0); + } + + if (status & ATA_BUSY) { + printf ("ata%u failed to respond : ", num); + printf ("bus reset failed\n"); + port[num].dev_mask = 0; + return 1; + } + return 0; +} + +static void sata_identify (int num, int dev) +{ + u8 cmd = 0, status = 0, devno = num; + u16 iobuf[ATA_SECTOR_WORDS]; + u64 n_sectors = 0; + + memset (iobuf, 0, sizeof (iobuf)); + + if (!(port[num].dev_mask & 0x01)) { + printf ("dev%d is not present on port#%d\n", dev, num); + return; + } + + debug ("port=%d dev=%d\n", num, dev); + + status = 0; + cmd = ATA_CMD_ID_ATA; /*Device Identify Command */ + writeb (cmd, port[num].ioaddr.command_addr); + readb (port[num].ioaddr.altstatus_addr); + udelay (10); + + status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 1000, 0); + if (status & ATA_ERR) { + printf ("\ndevice not responding\n"); + port[num].dev_mask &= ~0x01; + return; + } + + input_data (&port[num].ioaddr, iobuf, ATA_SECTOR_WORDS); + + ata_swap_buf_le16 (iobuf, ATA_SECTOR_WORDS); + + debug ("Specific config: %x\n", iobuf[2]); + + /* we require LBA and DMA support (bits 8 & 9 of word 49) */ + if (!ata_id_has_dma (iobuf) || !ata_id_has_lba (iobuf)) { + debug ("ata%u: no dma/lba\n", num); + } +#ifdef DEBUG + ata_dump_id (iobuf); +#endif + n_sectors = ata_id_n_sectors (iobuf); + + if (n_sectors == 0) { + port[num].dev_mask &= ~0x01; + return; + } + ata_id_c_string (iobuf, (unsigned char *)sata_dev_desc[devno].revision, + ATA_ID_FW_REV, sizeof (sata_dev_desc[devno].revision)); + ata_id_c_string (iobuf, (unsigned char *)sata_dev_desc[devno].vendor, + ATA_ID_PROD, sizeof (sata_dev_desc[devno].vendor)); + ata_id_c_string (iobuf, (unsigned char *)sata_dev_desc[devno].product, + ATA_ID_SERNO, sizeof (sata_dev_desc[devno].product)); + + /* TODO - atm we asume harddisk ie not removable */ + sata_dev_desc[devno].removable = 0; + + sata_dev_desc[devno].lba = (u32) n_sectors; + debug("lba=0x%lx\n", sata_dev_desc[devno].lba); + +#ifdef CONFIG_LBA48 + if (iobuf[83] & (1 << 10)) { + sata_dev_desc[devno].lba48 = 1; + } else { + sata_dev_desc[devno].lba48 = 0; + } +#endif + + /* assuming HD */ + sata_dev_desc[devno].type = DEV_TYPE_HARDDISK; + sata_dev_desc[devno].blksz = ATA_SECT_SIZE; + sata_dev_desc[devno].lun = 0; /* just to fill something in... */ +} + +static void set_Feature_cmd (int num, int dev) +{ + u8 status = 0; + + if (!(port[num].dev_mask & 0x01)) { + debug ("dev%d is not present on port#%d\n", dev, num); + return; + } + + writeb (SETFEATURES_XFER, port[num].ioaddr.feature_addr); + writeb (XFER_PIO_4, port[num].ioaddr.nsect_addr); + writeb (0, port[num].ioaddr.lbal_addr); + writeb (0, port[num].ioaddr.lbam_addr); + writeb (0, port[num].ioaddr.lbah_addr); + + writeb (ATA_DEVICE_OBS, port[num].ioaddr.device_addr); + writeb (ATA_CMD_SET_FEATURES, port[num].ioaddr.command_addr); + + udelay (50); + msleep (150); + + status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 5000, 0); + if ((status & (ATA_BUSY | ATA_ERR))) { + printf ("Error : status 0x%02x\n", status); + port[num].dev_mask &= ~0x01; + } +} + +u8 sil3114_spin_down (int num) +{ + u8 status = 0; + + debug ("Spin down disk\n"); + + if (!(port[num].dev_mask & 0x01)) { + debug ("Device ata%d is not present\n", num); + return 1; + } + + if ((status = check_power_mode (num)) == 0x00) { + debug ("Already in standby\n"); + return 0; + } + + if (status == 0x01) { + printf ("Failed to check power mode on ata%d\n", num); + return 1; + } + + if (!((status = sata_chk_status (&port[num].ioaddr, 0)) & ATA_DRDY)) { + printf ("Device ata%d not ready\n", num); + return 1; + } + + writeb (0x00, port[num].ioaddr.feature_addr); + + writeb (0x00, port[num].ioaddr.nsect_addr); + writeb (0x00, port[num].ioaddr.lbal_addr); + writeb (0x00, port[num].ioaddr.lbam_addr); + writeb (0x00, port[num].ioaddr.lbah_addr); + + writeb (ATA_DEVICE_OBS, port[num].ioaddr.device_addr); + writeb (ATA_CMD_STANDBY, port[num].ioaddr.command_addr); + + status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 30000, 0); + if ((status & (ATA_BUSY | ATA_ERR))) { + printf ("Error waiting for disk spin down: status 0x%02x\n", + status); + port[num].dev_mask &= ~0x01; + return 1; + } + return 0; +} + +u8 sil3114_spin_up (int num) +{ + u8 status = 0; + + debug ("Spin up disk\n"); + + if (!(port[num].dev_mask & 0x01)) { + debug ("Device ata%d is not present\n", num); + return 1; + } + + if ((status = check_power_mode (num)) != 0x00) { + if (status == 0x01) { + printf ("Failed to check power mode on ata%d\n", num); + return 1; + } else { + /* should be up and running already */ + return 0; + } + } + + if (!((status = sata_chk_status (&port[num].ioaddr, 0)) & ATA_DRDY)) { + printf ("Device ata%d not ready\n", num); + return 1; + } + + debug ("Stautus of device check: %d\n", status); + + writeb (0x00, port[num].ioaddr.feature_addr); + + writeb (0x00, port[num].ioaddr.nsect_addr); + writeb (0x00, port[num].ioaddr.lbal_addr); + writeb (0x00, port[num].ioaddr.lbam_addr); + writeb (0x00, port[num].ioaddr.lbah_addr); + + writeb (ATA_DEVICE_OBS, port[num].ioaddr.device_addr); + writeb (ATA_CMD_IDLE, port[num].ioaddr.command_addr); + + status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 30000, 0); + if ((status & (ATA_BUSY | ATA_ERR))) { + printf ("Error waiting for disk spin up: status 0x%02x\n", + status); + port[num].dev_mask &= ~0x01; + return 1; + } + + /* Wait for disk to enter Active state */ + do { + msleep (10); + status = check_power_mode (num); + } while ((status == 0x00) || (status == 0x80)); + + if (status == 0x01) { + printf ("Falied waiting for disk to spin up\n"); + return 1; + } + + return 0; +} + +/* Return value is not the usual here + * 0x00 - Device stand by + * 0x01 - Operation failed + * 0x80 - Device idle + * 0xff - Device active +*/ +static u8 check_power_mode (int num) +{ + u8 status = 0; + u8 res = 0; + if (!(port[num].dev_mask & 0x01)) { + debug ("Device ata%d is not present\n", num); + return 1; + } + + if (!(sata_chk_status (&port[num].ioaddr, 0) & ATA_DRDY)) { + printf ("Device ata%d not ready\n", num); + return 1; + } + + writeb (0, port[num].ioaddr.feature_addr); + writeb (0, port[num].ioaddr.nsect_addr); + writeb (0, port[num].ioaddr.lbal_addr); + writeb (0, port[num].ioaddr.lbam_addr); + writeb (0, port[num].ioaddr.lbah_addr); + + writeb (ATA_DEVICE_OBS, port[num].ioaddr.device_addr); + writeb (ATA_CMD_CHK_POWER, port[num].ioaddr.command_addr); + + status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 5000, 0); + if ((status & (ATA_BUSY | ATA_ERR))) { + printf + ("Error waiting for check power mode complete : status 0x%02x\n", + status); + port[num].dev_mask &= ~0x01; + return 1; + } + res = readb (port[num].ioaddr.nsect_addr); + debug ("Check powermode: %d\n", res); + return res; + +} + +static void sata_port (struct sata_ioports *ioport) +{ + ioport->data_addr = ioport->cmd_addr + ATA_REG_DATA; + ioport->error_addr = ioport->cmd_addr + ATA_REG_ERR; + ioport->feature_addr = ioport->cmd_addr + ATA_REG_FEATURE; + ioport->nsect_addr = ioport->cmd_addr + ATA_REG_NSECT; + ioport->lbal_addr = ioport->cmd_addr + ATA_REG_LBAL; + ioport->lbam_addr = ioport->cmd_addr + ATA_REG_LBAM; + ioport->lbah_addr = ioport->cmd_addr + ATA_REG_LBAH; + ioport->device_addr = ioport->cmd_addr + ATA_REG_DEVICE; + ioport->status_addr = ioport->cmd_addr + ATA_REG_STATUS; + ioport->command_addr = ioport->cmd_addr + ATA_REG_CMD; +} + +static u8 wait_for_irq (int num, unsigned int max) +{ + + u32 port = iobase[5]; + switch (num) { + case 0: + port += VND_TF_CNST_CH0; + break; + case 1: + port += VND_TF_CNST_CH1; + break; + case 2: + port += VND_TF_CNST_CH2; + break; + case 3: + port += VND_TF_CNST_CH3; + break; + default: + return 1; + } + + do { + if (readl (port) & VND_TF_CNST_INTST) { + break; + } + udelay (1000); + max--; + } while ((max > 0)); + + return (max == 0); +} + +static u8 sata_busy_wait (struct sata_ioports *ioaddr, int bits, + unsigned int max, u8 usealtstatus) +{ + u8 status; + + do { + if (!((status = sata_chk_status (ioaddr, usealtstatus)) & bits)) { + break; + } + udelay (1000); + max--; + } while ((status & bits) && (max > 0)); + + return status; +} + +static u8 sata_chk_status (struct sata_ioports *ioaddr, u8 usealtstatus) +{ + if (!usealtstatus) { + return readb (ioaddr->status_addr); + } else { + return readb (ioaddr->altstatus_addr); + } +} + +static void msleep (int count) +{ + int i; + + for (i = 0; i < count; i++) + udelay (1000); +} + +/* Read up to 255 sectors + * + * Returns sectors read +*/ +static u8 do_one_read (int device, ulong block, u8 blkcnt, u16 * buff, + uchar lba48) +{ + + u8 sr = 0; + u8 status; + u64 blknr = (u64) block; + + if (!(sata_chk_status (&port[device].ioaddr, 0) & ATA_DRDY)) { + printf ("Device ata%d not ready\n", device); + return 0; + } + + /* Set up transfer */ +#ifdef CONFIG_LBA48 + if (lba48) { + /* write high bits */ + writeb (0, port[device].ioaddr.nsect_addr); + writeb ((blknr >> 24) & 0xFF, port[device].ioaddr.lbal_addr); + writeb ((blknr >> 32) & 0xFF, port[device].ioaddr.lbam_addr); + writeb ((blknr >> 40) & 0xFF, port[device].ioaddr.lbah_addr); + } +#endif + writeb (blkcnt, port[device].ioaddr.nsect_addr); + writeb (((blknr) >> 0) & 0xFF, port[device].ioaddr.lbal_addr); + writeb ((blknr >> 8) & 0xFF, port[device].ioaddr.lbam_addr); + writeb ((blknr >> 16) & 0xFF, port[device].ioaddr.lbah_addr); + +#ifdef CONFIG_LBA48 + if (lba48) { + writeb (ATA_LBA, port[device].ioaddr.device_addr); + writeb (ATA_CMD_PIO_READ_EXT, port[device].ioaddr.command_addr); + } else +#endif + { + writeb (ATA_LBA | ((blknr >> 24) & 0xF), + port[device].ioaddr.device_addr); + writeb (ATA_CMD_PIO_READ, port[device].ioaddr.command_addr); + } + + status = sata_busy_wait (&port[device].ioaddr, ATA_BUSY, 10000, 1); + + if (status & ATA_BUSY) { + u8 err = 0; + + printf ("Device %d not responding status %d\n", device, status); + err = readb (port[device].ioaddr.error_addr); + printf ("Error reg = 0x%x\n", err); + + return (sr); + } + while (blkcnt--) { + + if (wait_for_irq (device, 500)) { + printf ("ata%u irq failed\n", device); + return sr; + } + + status = sata_chk_status (&port[device].ioaddr, 0); + if (status & ATA_ERR) { + printf ("ata%u error %d\n", device, + readb (port[device].ioaddr.error_addr)); + return sr; + } + /* Read one sector */ + input_data (&port[device].ioaddr, buff, ATA_SECTOR_WORDS); + buff += ATA_SECTOR_WORDS; + sr++; + + } + return sr; +} + +ulong sata_read (int device, ulong block, lbaint_t blkcnt, void *buff) +{ + ulong n = 0, sread; + u16 *buffer = (u16 *) buff; + u8 status = 0; + u64 blknr = (u64) block; + unsigned char lba48 = 0; + +#ifdef CONFIG_LBA48 + if (blknr > 0xfffffff) { + if (!sata_dev_desc[device].lba48) { + printf ("Drive doesn't support 48-bit addressing\n"); + return 0; + } + /* more than 28 bits used, use 48bit mode */ + lba48 = 1; + } +#endif + + while (blkcnt > 0) { + + if (blkcnt > 255) { + sread = 255; + } else { + sread = blkcnt; + } + + status = do_one_read (device, blknr, sread, buffer, lba48); + if (status != sread) { + printf ("Read failed\n"); + return n; + } + + blkcnt -= sread; + blknr += sread; + n += sread; + buffer += sread * ATA_SECTOR_WORDS; + } + return n; +} + +ulong sata_write (int device, ulong block, lbaint_t blkcnt, const void *buff) +{ + ulong n = 0; + u16 *buffer = (u16 *) buff; + unsigned char status = 0, num = 0; + u64 blknr = (u64) block; +#ifdef CONFIG_LBA48 + unsigned char lba48 = 0; + + if (blknr > 0xfffffff) { + if (!sata_dev_desc[device].lba48) { + printf ("Drive doesn't support 48-bit addressing\n"); + return 0; + } + /* more than 28 bits used, use 48bit mode */ + lba48 = 1; + } +#endif + /*Port Number */ + num = device; + + while (blkcnt-- > 0) { + status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 500, 0); + if (status & ATA_BUSY) { + printf ("ata%u failed to respond\n", port[num].port_no); + return n; + } +#ifdef CONFIG_LBA48 + if (lba48) { + /* write high bits */ + writeb (0, port[num].ioaddr.nsect_addr); + writeb ((blknr >> 24) & 0xFF, + port[num].ioaddr.lbal_addr); + writeb ((blknr >> 32) & 0xFF, + port[num].ioaddr.lbam_addr); + writeb ((blknr >> 40) & 0xFF, + port[num].ioaddr.lbah_addr); + } +#endif + writeb (1, port[num].ioaddr.nsect_addr); + writeb ((blknr >> 0) & 0xFF, port[num].ioaddr.lbal_addr); + writeb ((blknr >> 8) & 0xFF, port[num].ioaddr.lbam_addr); + writeb ((blknr >> 16) & 0xFF, port[num].ioaddr.lbah_addr); +#ifdef CONFIG_LBA48 + if (lba48) { + writeb (ATA_LBA, port[num].ioaddr.device_addr); + writeb (ATA_CMD_PIO_WRITE_EXT, port[num].ioaddr.command_addr); + } else +#endif + { + writeb (ATA_LBA | ((blknr >> 24) & 0xF), + port[num].ioaddr.device_addr); + writeb (ATA_CMD_PIO_WRITE, port[num].ioaddr.command_addr); + } + + msleep (50); + /*may take up to 4 sec */ + status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 4000, 0); + if ((status & (ATA_DRQ | ATA_BUSY | ATA_ERR)) != ATA_DRQ) { + printf ("Error no DRQ dev %d blk %ld: sts 0x%02x\n", + device, (ulong) blknr, status); + return (n); + } + + output_data (&port[num].ioaddr, buffer, ATA_SECTOR_WORDS); + readb (port[num].ioaddr.altstatus_addr); + udelay (50); + + ++n; + ++blknr; + buffer += ATA_SECTOR_WORDS; + } + return n; +} + +/* Driver implementation */ +static u8 sil_get_device_cache_line (pci_dev_t pdev) +{ + u8 cache_line = 0; + pci_read_config_byte (pdev, PCI_CACHE_LINE_SIZE, &cache_line); + return cache_line; +} + +int init_sata (int dev) +{ + static u8 init_done = 0; + static int res = 1; + pci_dev_t devno; + u8 cls = 0; + u16 cmd = 0; + u32 sconf = 0; + + if (init_done) { + return res; + } + + init_done = 1; + + if ((devno = pci_find_device (SIL_VEND_ID, SIL3114_DEVICE_ID, 0)) == -1) { + res = 1; + return res; + } + + /* Read out all BARs, even though we only use MMIO from BAR5 */ + pci_read_config_dword (devno, PCI_BASE_ADDRESS_0, &iobase[0]); + pci_read_config_dword (devno, PCI_BASE_ADDRESS_1, &iobase[1]); + pci_read_config_dword (devno, PCI_BASE_ADDRESS_2, &iobase[2]); + pci_read_config_dword (devno, PCI_BASE_ADDRESS_3, &iobase[3]); + pci_read_config_dword (devno, PCI_BASE_ADDRESS_4, &iobase[4]); + pci_read_config_dword (devno, PCI_BASE_ADDRESS_5, &iobase[5]); + + if ((iobase[0] == 0xFFFFFFFF) || (iobase[1] == 0xFFFFFFFF) || + (iobase[2] == 0xFFFFFFFF) || (iobase[3] == 0xFFFFFFFF) || + (iobase[4] == 0xFFFFFFFF) || (iobase[5] == 0xFFFFFFFF)) { + printf ("Error no base addr for SATA controller\n"); + res = 1; + return res; + } + + /* mask off unused bits */ + iobase[0] &= 0xfffffffc; + iobase[1] &= 0xfffffff8; + iobase[2] &= 0xfffffffc; + iobase[3] &= 0xfffffff8; + iobase[4] &= 0xfffffff0; + iobase[5] &= 0xfffffc00; + + /* from sata_sil in Linux kernel */ + cls = sil_get_device_cache_line (devno); + if (cls) { + cls >>= 3; + cls++; /* cls = (line_size/8)+1 */ + writel (cls << 8 | cls, iobase[5] + VND_FIFOCFG_CH0); + writel (cls << 8 | cls, iobase[5] + VND_FIFOCFG_CH1); + writel (cls << 8 | cls, iobase[5] + VND_FIFOCFG_CH2); + writel (cls << 8 | cls, iobase[5] + VND_FIFOCFG_CH3); + } else { + printf ("Cache line not set. Driver may not function\n"); + } + + /* Enable operation */ + pci_read_config_word (devno, PCI_COMMAND, &cmd); + cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_IO | PCI_COMMAND_MEMORY; + pci_write_config_word (devno, PCI_COMMAND, cmd); + + /* Disable interrupt usage */ + pci_read_config_dword (devno, VND_SYSCONFSTAT, &sconf); + sconf |= (VND_SYSCONFSTAT_CHN_0_INTBLOCK | VND_SYSCONFSTAT_CHN_1_INTBLOCK); + pci_write_config_dword (devno, VND_SYSCONFSTAT, sconf); + + res = 0; + return res; +} + +int reset_sata(int dev) +{ + return 0; +} + +/* Check if device is connected to port */ +int sata_bus_probe (int portno) +{ + u32 port = iobase[5]; + u32 val; + switch (portno) { + case 0: + port += VND_SSTATUS_CH0; + break; + case 1: + port += VND_SSTATUS_CH1; + break; + case 2: + port += VND_SSTATUS_CH2; + break; + case 3: + port += VND_SSTATUS_CH3; + break; + default: + return 0; + } + val = readl (port); + if ((val & SATA_DET_PRES) == SATA_DET_PRES) { + return 1; + } else { + return 0; + } +} + +int sata_phy_reset (int portno) +{ + u32 port = iobase[5]; + u32 val; + switch (portno) { + case 0: + port += VND_SCONTROL_CH0; + break; + case 1: + port += VND_SCONTROL_CH1; + break; + case 2: + port += VND_SCONTROL_CH2; + break; + case 3: + port += VND_SCONTROL_CH3; + break; + default: + return 0; + } + val = readl (port); + writel (val | SATA_SC_DET_RST, port); + msleep (150); + writel (val & ~SATA_SC_DET_RST, port); + return 0; +} + +int scan_sata (int dev) +{ + /* A bit brain dead, but the code has a legacy */ + switch (dev) { + case 0: + port[0].port_no = 0; + port[0].ioaddr.cmd_addr = iobase[5] + VND_TF0_CH0; + port[0].ioaddr.altstatus_addr = port[0].ioaddr.ctl_addr = + (iobase[5] + VND_TF2_CH0) | ATA_PCI_CTL_OFS; + port[0].ioaddr.bmdma_addr = iobase[5] + VND_BMDMA_CH0; + break; +#if (CONFIG_SYS_SATA_MAX_DEVICE >= 1) + case 1: + port[1].port_no = 0; + port[1].ioaddr.cmd_addr = iobase[5] + VND_TF0_CH1; + port[1].ioaddr.altstatus_addr = port[1].ioaddr.ctl_addr = + (iobase[5] + VND_TF2_CH1) | ATA_PCI_CTL_OFS; + port[1].ioaddr.bmdma_addr = iobase[5] + VND_BMDMA_CH1; + break; +#elif (CONFIG_SYS_SATA_MAX_DEVICE >= 2) + case 2: + port[2].port_no = 0; + port[2].ioaddr.cmd_addr = iobase[5] + VND_TF0_CH2; + port[2].ioaddr.altstatus_addr = port[2].ioaddr.ctl_addr = + (iobase[5] + VND_TF2_CH2) | ATA_PCI_CTL_OFS; + port[2].ioaddr.bmdma_addr = iobase[5] + VND_BMDMA_CH2; + break; +#elif (CONFIG_SYS_SATA_MAX_DEVICE >= 3) + case 3: + port[3].port_no = 0; + port[3].ioaddr.cmd_addr = iobase[5] + VND_TF0_CH3; + port[3].ioaddr.altstatus_addr = port[3].ioaddr.ctl_addr = + (iobase[5] + VND_TF2_CH3) | ATA_PCI_CTL_OFS; + port[3].ioaddr.bmdma_addr = iobase[5] + VND_BMDMA_CH3; + break; +#endif + default: + printf ("Tried to scan unknown port: ata%d\n", dev); + return 1; + } + + /* Initialize other registers */ + sata_port (&port[dev].ioaddr); + + /* Check for attached device */ + if (!sata_bus_probe (dev)) { + port[dev].port_state = 0; + debug ("SATA#%d port is not present\n", dev); + } else { + debug ("SATA#%d port is present\n", dev); + if (sata_bus_softreset (dev)) { + /* soft reset failed, try a hard one */ + sata_phy_reset (dev); + if (sata_bus_softreset (dev)) { + port[dev].port_state = 0; + } else { + port[dev].port_state = 1; + } + } else { + port[dev].port_state = 1; + } + } + if (port[dev].port_state == 1) { + /* Probe device and set xfer mode */ + sata_identify (dev, 0); + set_Feature_cmd (dev, 0); + } + + return 0; +} diff --git a/drivers/ata/sata_sil3114.h b/drivers/ata/sata_sil3114.h new file mode 100644 index 0000000..091fca1 --- /dev/null +++ b/drivers/ata/sata_sil3114.h @@ -0,0 +1,134 @@ +/* + * Copyright (C) Excito Elektronik i SkÃ¥ne AB, All rights reserved. + * Author: Tor Krill + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef SATA_SIL3114_H +#define SATA_SIL3114_H + +struct sata_ioports { + unsigned long cmd_addr; + unsigned long data_addr; + unsigned long error_addr; + unsigned long feature_addr; + unsigned long nsect_addr; + unsigned long lbal_addr; + unsigned long lbam_addr; + unsigned long lbah_addr; + unsigned long device_addr; + unsigned long status_addr; + unsigned long command_addr; + unsigned long altstatus_addr; + unsigned long ctl_addr; + unsigned long bmdma_addr; + unsigned long scr_addr; +}; + +struct sata_port { + unsigned char port_no; /* primary=0, secondary=1 */ + struct sata_ioports ioaddr; /* ATA cmd/ctl/dma reg blks */ + unsigned char ctl_reg; + unsigned char last_ctl; + unsigned char port_state; /* 1-port is available and */ + /* 0-port is not available */ + unsigned char dev_mask; +}; + +/* Missing ata defines */ +#define ATA_CMD_STANDBY 0xE2 +#define ATA_CMD_STANDBYNOW1 0xE0 +#define ATA_CMD_IDLE 0xE3 +#define ATA_CMD_IDLEIMMEDIATE 0xE1 + +/* Defines for SIL3114 chip */ + +/* PCI defines */ +#define SIL_VEND_ID 0x1095 +#define SIL3114_DEVICE_ID 0x3114 + +/* some vendor specific registers */ +#define VND_SYSCONFSTAT 0x88 /* System Configuration Status and Command */ +#define VND_SYSCONFSTAT_CHN_0_INTBLOCK (1<<22) +#define VND_SYSCONFSTAT_CHN_1_INTBLOCK (1<<23) +#define VND_SYSCONFSTAT_CHN_2_INTBLOCK (1<<24) +#define VND_SYSCONFSTAT_CHN_3_INTBLOCK (1<<25) + +/* internal registers mapped by BAR5 */ +/* SATA Control*/ +#define VND_SCONTROL_CH0 0x100 +#define VND_SCONTROL_CH1 0x180 +#define VND_SCONTROL_CH2 0x300 +#define VND_SCONTROL_CH3 0x380 + +#define SATA_SC_IPM_T2P (1<<16) +#define SATA_SC_IPM_T2S (2<<16) +#define SATA_SC_SPD_1_5 (1<<4) +#define SATA_SC_SPD_3_0 (2<<4) +#define SATA_SC_DET_RST (1) /* ATA Reset sequence */ +#define SATA_SC_DET_PDIS (4) /* PHY Disable */ + +/* SATA Status */ +#define VND_SSTATUS_CH0 0x104 +#define VND_SSTATUS_CH1 0x184 +#define VND_SSTATUS_CH2 0x304 +#define VND_SSTATUS_CH3 0x384 + +#define SATA_SS_IPM_ACTIVE (1<<8) +#define SATA_SS_IPM_PARTIAL (2<<8) +#define SATA_SS_IPM_SLUMBER (6<<8) +#define SATA_SS_SPD_1_5 (1<<4) +#define SATA_SS_SPD_3_0 (2<<4) +#define SATA_DET_P_NOPHY (1) /* Device presence but no PHY connection established */ +#define SATA_DET_PRES (3) /* Device presence and active PHY */ +#define SATA_DET_OFFLINE (4) /* Device offline or in loopback mode */ + +/* Task file registers in BAR5 mapping */ +#define VND_TF0_CH0 0x80 +#define VND_TF0_CH1 0xc0 +#define VND_TF0_CH2 0x280 +#define VND_TF0_CH3 0x2c0 +#define VND_TF1_CH0 0x88 +#define VND_TF1_CH1 0xc8 +#define VND_TF1_CH2 0x288 +#define VND_TF1_CH3 0x2c8 +#define VND_TF2_CH0 0x88 +#define VND_TF2_CH1 0xc8 +#define VND_TF2_CH2 0x288 +#define VND_TF2_CH3 0x2c8 + +#define VND_BMDMA_CH0 0x00 +#define VND_BMDMA_CH1 0x08 +#define VND_BMDMA_CH2 0x200 +#define VND_BMDMA_CH3 0x208 +#define VND_BMDMA2_CH0 0x10 +#define VND_BMDMA2_CH1 0x18 +#define VND_BMDMA2_CH2 0x210 +#define VND_BMDMA2_CH3 0x218 + +/* FIFO control */ +#define VND_FIFOCFG_CH0 0x40 +#define VND_FIFOCFG_CH1 0x44 +#define VND_FIFOCFG_CH2 0x240 +#define VND_FIFOCFG_CH3 0x244 + +/* Task File configuration and status */ +#define VND_TF_CNST_CH0 0xa0 +#define VND_TF_CNST_CH1 0xe0 +#define VND_TF_CNST_CH2 0x2a0 +#define VND_TF_CNST_CH3 0x2e0 + +#define VND_TF_CNST_BFCMD (1<<1) +#define VND_TF_CNST_CHNRST (1<<2) +#define VND_TF_CNST_VDMA (1<<10) +#define VND_TF_CNST_INTST (1<<11) +#define VND_TF_CNST_WDTO (1<<12) +#define VND_TF_CNST_WDEN (1<<13) +#define VND_TF_CNST_WDIEN (1<<14) + +/* for testing */ +#define VND_SSDR 0x04c /* System Software Data Register */ +#define VND_FMACS 0x050 /* Flash Memory Address control and status */ + +#endif diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index ed7fa88..1ddd650 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -10,28 +10,6 @@ config BLK be partitioned into several areas, called 'partitions' in U-Boot. A filesystem can be placed in each partition. -config AHCI - bool "Support SATA controllers with driver model" - depends on DM - help - This enables a uclass for disk controllers in U-Boot. Various driver - types can use this, such as AHCI/SATA. It does not provide any standard - operations at present. The block device interface has not been converted - to driver model. - -config SATA - bool "Support SATA controllers" - help - This enables support for SATA (Serial Advanced Technology - Attachment), a serial bus standard for connecting to hard drives and - other storage devices. - - SATA replaces PATA (originally just ATA), which stands for Parallel AT - Attachment, where AT refers to an IBM AT (Advanced Technology) - computer released in 1984. - - See also CMD_SATA which provides command-line support. - config SCSI bool "Support SCSI controllers" help @@ -59,29 +37,6 @@ config BLOCK_CACHE it will prevent repeated reads from directory structures and other filesystem data structures. -menu "SATA/SCSI device support" - -config SATA_CEVA - bool "Ceva Sata controller" - depends on AHCI - depends on DM_SCSI - help - This option enables Ceva Sata controller hard IP available on Xilinx - ZynqMP. Support up to 2 external devices. Complient with SATA 3.1 and - AHCI 1.3 specifications with hot-plug detect feature. - - -config DWC_AHCI - bool "Enable Synopsys DWC AHCI driver support" - select SCSI_AHCI - select PHY - depends on DM_SCSI - help - Enable this driver to support Sata devices through - Synopsys DWC AHCI module. - -endmenu - config IDE bool "Support IDE controllers" help diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 035e078..064c76f 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -11,22 +11,8 @@ ifndef CONFIG_BLK obj-y += blk_legacy.o endif -obj-$(CONFIG_DWC_AHCI) += dwc_ahci.o -obj-$(CONFIG_AHCI) += ahci-uclass.o -obj-$(CONFIG_DM_SCSI) += scsi-uclass.o -obj-$(CONFIG_SCSI_AHCI) += ahci.o -obj-$(CONFIG_DWC_AHSATA) += dwc_ahsata.o -obj-$(CONFIG_FSL_SATA) += fsl_sata.o obj-$(CONFIG_IDE) += ide.o obj-$(CONFIG_IDE_FTIDE020) += ftide020.o -obj-$(CONFIG_LIBATA) += libata.o -obj-$(CONFIG_MVSATA_IDE) += mvsata_ide.o -obj-$(CONFIG_MX51_PATA) += mxc_ata.o -obj-$(CONFIG_SATA_CEVA) += sata_ceva.o -obj-$(CONFIG_SATA_DWC) += sata_dwc.o -obj-$(CONFIG_SATA_MV) += sata_mv.o -obj-$(CONFIG_SATA_SIL3114) += sata_sil3114.o -obj-$(CONFIG_SATA_SIL) += sata_sil.o -obj-$(CONFIG_SANDBOX) += sandbox.o sandbox_scsi.o sata_sandbox.o +obj-$(CONFIG_SANDBOX) += sandbox.o sandbox_scsi.o obj-$(CONFIG_SYSTEMACE) += systemace.o obj-$(CONFIG_BLOCK_CACHE) += blkcache.o diff --git a/drivers/block/ahci-uclass.c b/drivers/block/ahci-uclass.c deleted file mode 100644 index 7b8c326..0000000 --- a/drivers/block/ahci-uclass.c +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2015 Google, Inc - * Written by Simon Glass - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include - -UCLASS_DRIVER(ahci) = { - .id = UCLASS_AHCI, - .name = "ahci", -}; diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c deleted file mode 100644 index f474471..0000000 --- a/drivers/block/ahci.c +++ /dev/null @@ -1,1094 +0,0 @@ -/* - * Copyright (C) Freescale Semiconductor, Inc. 2006. - * Author: Jason Jin - * Zhang Wei - * - * SPDX-License-Identifier: GPL-2.0+ - * - * with the reference on libata and ahci drvier in kernel - */ -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static int ata_io_flush(u8 port); - -struct ahci_probe_ent *probe_ent = NULL; -u16 *ataid[AHCI_MAX_PORTS]; - -#define writel_with_flush(a,b) do { writel(a,b); readl(b); } while (0) - -/* - * Some controllers limit number of blocks they can read/write at once. - * Contemporary SSD devices work much faster if the read/write size is aligned - * to a power of 2. Let's set default to 128 and allowing to be overwritten if - * needed. - */ -#ifndef MAX_SATA_BLOCKS_READ_WRITE -#define MAX_SATA_BLOCKS_READ_WRITE 0x80 -#endif - -/* Maximum timeouts for each event */ -#define WAIT_MS_SPINUP 20000 -#define WAIT_MS_DATAIO 10000 -#define WAIT_MS_FLUSH 5000 -#define WAIT_MS_LINKUP 200 - -__weak void __iomem *ahci_port_base(void __iomem *base, u32 port) -{ - return base + 0x100 + (port * 0x80); -} - - -static void ahci_setup_port(struct ahci_ioports *port, void __iomem *base, - unsigned int port_idx) -{ - base = ahci_port_base(base, port_idx); - - port->cmd_addr = base; - port->scr_addr = base + PORT_SCR; -} - - -#define msleep(a) udelay(a * 1000) - -static void ahci_dcache_flush_range(unsigned long begin, unsigned long len) -{ - const unsigned long start = begin; - const unsigned long end = start + len; - - debug("%s: flush dcache: [%#lx, %#lx)\n", __func__, start, end); - flush_dcache_range(start, end); -} - -/* - * SATA controller DMAs to physical RAM. Ensure data from the - * controller is invalidated from dcache; next access comes from - * physical RAM. - */ -static void ahci_dcache_invalidate_range(unsigned long begin, unsigned long len) -{ - const unsigned long start = begin; - const unsigned long end = start + len; - - debug("%s: invalidate dcache: [%#lx, %#lx)\n", __func__, start, end); - invalidate_dcache_range(start, end); -} - -/* - * Ensure data for SATA controller is flushed out of dcache and - * written to physical memory. - */ -static void ahci_dcache_flush_sata_cmd(struct ahci_ioports *pp) -{ - ahci_dcache_flush_range((unsigned long)pp->cmd_slot, - AHCI_PORT_PRIV_DMA_SZ); -} - -static int waiting_for_cmd_completed(void __iomem *offset, - int timeout_msec, - u32 sign) -{ - int i; - u32 status; - - for (i = 0; ((status = readl(offset)) & sign) && i < timeout_msec; i++) - msleep(1); - - return (i < timeout_msec) ? 0 : -1; -} - -int __weak ahci_link_up(struct ahci_probe_ent *probe_ent, u8 port) -{ - u32 tmp; - int j = 0; - void __iomem *port_mmio = probe_ent->port[port].port_mmio; - - /* - * Bring up SATA link. - * SATA link bringup time is usually less than 1 ms; only very - * rarely has it taken between 1-2 ms. Never seen it above 2 ms. - */ - while (j < WAIT_MS_LINKUP) { - tmp = readl(port_mmio + PORT_SCR_STAT); - tmp &= PORT_SCR_STAT_DET_MASK; - if (tmp == PORT_SCR_STAT_DET_PHYRDY) - return 0; - udelay(1000); - j++; - } - return 1; -} - -#ifdef CONFIG_SUNXI_AHCI -/* The sunxi AHCI controller requires this undocumented setup */ -static void sunxi_dma_init(void __iomem *port_mmio) -{ - clrsetbits_le32(port_mmio + PORT_P0DMACR, 0x0000ff00, 0x00004400); -} -#endif - -int ahci_reset(void __iomem *base) -{ - int i = 1000; - u32 __iomem *host_ctl_reg = base + HOST_CTL; - u32 tmp = readl(host_ctl_reg); /* global controller reset */ - - if ((tmp & HOST_RESET) == 0) - writel_with_flush(tmp | HOST_RESET, host_ctl_reg); - - /* - * reset must complete within 1 second, or - * the hardware should be considered fried. - */ - do { - udelay(1000); - tmp = readl(host_ctl_reg); - i--; - } while ((i > 0) && (tmp & HOST_RESET)); - - if (i == 0) { - printf("controller reset failed (0x%x)\n", tmp); - return -1; - } - - return 0; -} - -static int ahci_host_init(struct ahci_probe_ent *probe_ent) -{ -#if !defined(CONFIG_SCSI_AHCI_PLAT) && !defined(CONFIG_DM_SCSI) -# ifdef CONFIG_DM_PCI - struct udevice *dev = probe_ent->dev; - struct pci_child_platdata *pplat = dev_get_parent_platdata(dev); -# else - pci_dev_t pdev = probe_ent->dev; - unsigned short vendor; -# endif - u16 tmp16; -#endif - void __iomem *mmio = probe_ent->mmio_base; - u32 tmp, cap_save, cmd; - int i, j, ret; - void __iomem *port_mmio; - u32 port_map; - - debug("ahci_host_init: start\n"); - - cap_save = readl(mmio + HOST_CAP); - cap_save &= ((1 << 28) | (1 << 17)); - cap_save |= (1 << 27); /* Staggered Spin-up. Not needed. */ - - ret = ahci_reset(probe_ent->mmio_base); - if (ret) - return ret; - - writel_with_flush(HOST_AHCI_EN, mmio + HOST_CTL); - writel(cap_save, mmio + HOST_CAP); - writel_with_flush(0xf, mmio + HOST_PORTS_IMPL); - -#if !defined(CONFIG_SCSI_AHCI_PLAT) && !defined(CONFIG_DM_SCSI) -# ifdef CONFIG_DM_PCI - if (pplat->vendor == PCI_VENDOR_ID_INTEL) { - u16 tmp16; - - dm_pci_read_config16(dev, 0x92, &tmp16); - dm_pci_write_config16(dev, 0x92, tmp16 | 0xf); - } -# else - pci_read_config_word(pdev, PCI_VENDOR_ID, &vendor); - - if (vendor == PCI_VENDOR_ID_INTEL) { - u16 tmp16; - pci_read_config_word(pdev, 0x92, &tmp16); - tmp16 |= 0xf; - pci_write_config_word(pdev, 0x92, tmp16); - } -# endif -#endif - probe_ent->cap = readl(mmio + HOST_CAP); - probe_ent->port_map = readl(mmio + HOST_PORTS_IMPL); - port_map = probe_ent->port_map; - probe_ent->n_ports = (probe_ent->cap & 0x1f) + 1; - - debug("cap 0x%x port_map 0x%x n_ports %d\n", - probe_ent->cap, probe_ent->port_map, probe_ent->n_ports); - - if (probe_ent->n_ports > CONFIG_SYS_SCSI_MAX_SCSI_ID) - probe_ent->n_ports = CONFIG_SYS_SCSI_MAX_SCSI_ID; - - for (i = 0; i < probe_ent->n_ports; i++) { - if (!(port_map & (1 << i))) - continue; - probe_ent->port[i].port_mmio = ahci_port_base(mmio, i); - port_mmio = (u8 *) probe_ent->port[i].port_mmio; - ahci_setup_port(&probe_ent->port[i], mmio, i); - - /* make sure port is not active */ - tmp = readl(port_mmio + PORT_CMD); - if (tmp & (PORT_CMD_LIST_ON | PORT_CMD_FIS_ON | - PORT_CMD_FIS_RX | PORT_CMD_START)) { - debug("Port %d is active. Deactivating.\n", i); - tmp &= ~(PORT_CMD_LIST_ON | PORT_CMD_FIS_ON | - PORT_CMD_FIS_RX | PORT_CMD_START); - writel_with_flush(tmp, port_mmio + PORT_CMD); - - /* spec says 500 msecs for each bit, so - * this is slightly incorrect. - */ - msleep(500); - } - -#ifdef CONFIG_SUNXI_AHCI - sunxi_dma_init(port_mmio); -#endif - - /* Add the spinup command to whatever mode bits may - * already be on in the command register. - */ - cmd = readl(port_mmio + PORT_CMD); - cmd |= PORT_CMD_SPIN_UP; - writel_with_flush(cmd, port_mmio + PORT_CMD); - - /* Bring up SATA link. */ - ret = ahci_link_up(probe_ent, i); - if (ret) { - printf("SATA link %d timeout.\n", i); - continue; - } else { - debug("SATA link ok.\n"); - } - - /* Clear error status */ - tmp = readl(port_mmio + PORT_SCR_ERR); - if (tmp) - writel(tmp, port_mmio + PORT_SCR_ERR); - - debug("Spinning up device on SATA port %d... ", i); - - j = 0; - while (j < WAIT_MS_SPINUP) { - tmp = readl(port_mmio + PORT_TFDATA); - if (!(tmp & (ATA_BUSY | ATA_DRQ))) - break; - udelay(1000); - tmp = readl(port_mmio + PORT_SCR_STAT); - tmp &= PORT_SCR_STAT_DET_MASK; - if (tmp == PORT_SCR_STAT_DET_PHYRDY) - break; - j++; - } - - tmp = readl(port_mmio + PORT_SCR_STAT) & PORT_SCR_STAT_DET_MASK; - if (tmp == PORT_SCR_STAT_DET_COMINIT) { - debug("SATA link %d down (COMINIT received), retrying...\n", i); - i--; - continue; - } - - printf("Target spinup took %d ms.\n", j); - if (j == WAIT_MS_SPINUP) - debug("timeout.\n"); - else - debug("ok.\n"); - - tmp = readl(port_mmio + PORT_SCR_ERR); - debug("PORT_SCR_ERR 0x%x\n", tmp); - writel(tmp, port_mmio + PORT_SCR_ERR); - - /* ack any pending irq events for this port */ - tmp = readl(port_mmio + PORT_IRQ_STAT); - debug("PORT_IRQ_STAT 0x%x\n", tmp); - if (tmp) - writel(tmp, port_mmio + PORT_IRQ_STAT); - - writel(1 << i, mmio + HOST_IRQ_STAT); - - /* register linkup ports */ - tmp = readl(port_mmio + PORT_SCR_STAT); - debug("SATA port %d status: 0x%x\n", i, tmp); - if ((tmp & PORT_SCR_STAT_DET_MASK) == PORT_SCR_STAT_DET_PHYRDY) - probe_ent->link_port_map |= (0x01 << i); - } - - tmp = readl(mmio + HOST_CTL); - debug("HOST_CTL 0x%x\n", tmp); - writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL); - tmp = readl(mmio + HOST_CTL); - debug("HOST_CTL 0x%x\n", tmp); -#if !defined(CONFIG_DM_SCSI) -#ifndef CONFIG_SCSI_AHCI_PLAT -# ifdef CONFIG_DM_PCI - dm_pci_read_config16(dev, PCI_COMMAND, &tmp16); - tmp |= PCI_COMMAND_MASTER; - dm_pci_write_config16(dev, PCI_COMMAND, tmp16); -# else - pci_read_config_word(pdev, PCI_COMMAND, &tmp16); - tmp |= PCI_COMMAND_MASTER; - pci_write_config_word(pdev, PCI_COMMAND, tmp16); -# endif -#endif -#endif - return 0; -} - - -static void ahci_print_info(struct ahci_probe_ent *probe_ent) -{ -#if !defined(CONFIG_SCSI_AHCI_PLAT) && !defined(CONFIG_DM_SCSI) -# if defined(CONFIG_DM_PCI) - struct udevice *dev = probe_ent->dev; -# else - pci_dev_t pdev = probe_ent->dev; -# endif - u16 cc; -#endif - void __iomem *mmio = probe_ent->mmio_base; - u32 vers, cap, cap2, impl, speed; - const char *speed_s; - const char *scc_s; - - vers = readl(mmio + HOST_VERSION); - cap = probe_ent->cap; - cap2 = readl(mmio + HOST_CAP2); - impl = probe_ent->port_map; - - speed = (cap >> 20) & 0xf; - if (speed == 1) - speed_s = "1.5"; - else if (speed == 2) - speed_s = "3"; - else if (speed == 3) - speed_s = "6"; - else - speed_s = "?"; - -#if defined(CONFIG_SCSI_AHCI_PLAT) || defined(CONFIG_DM_SCSI) - scc_s = "SATA"; -#else -# ifdef CONFIG_DM_PCI - dm_pci_read_config16(dev, 0x0a, &cc); -# else - pci_read_config_word(pdev, 0x0a, &cc); -# endif - if (cc == 0x0101) - scc_s = "IDE"; - else if (cc == 0x0106) - scc_s = "SATA"; - else if (cc == 0x0104) - scc_s = "RAID"; - else - scc_s = "unknown"; -#endif - printf("AHCI %02x%02x.%02x%02x " - "%u slots %u ports %s Gbps 0x%x impl %s mode\n", - (vers >> 24) & 0xff, - (vers >> 16) & 0xff, - (vers >> 8) & 0xff, - vers & 0xff, - ((cap >> 8) & 0x1f) + 1, (cap & 0x1f) + 1, speed_s, impl, scc_s); - - printf("flags: " - "%s%s%s%s%s%s%s" - "%s%s%s%s%s%s%s" - "%s%s%s%s%s%s\n", - cap & (1 << 31) ? "64bit " : "", - cap & (1 << 30) ? "ncq " : "", - cap & (1 << 28) ? "ilck " : "", - cap & (1 << 27) ? "stag " : "", - cap & (1 << 26) ? "pm " : "", - cap & (1 << 25) ? "led " : "", - cap & (1 << 24) ? "clo " : "", - cap & (1 << 19) ? "nz " : "", - cap & (1 << 18) ? "only " : "", - cap & (1 << 17) ? "pmp " : "", - cap & (1 << 16) ? "fbss " : "", - cap & (1 << 15) ? "pio " : "", - cap & (1 << 14) ? "slum " : "", - cap & (1 << 13) ? "part " : "", - cap & (1 << 7) ? "ccc " : "", - cap & (1 << 6) ? "ems " : "", - cap & (1 << 5) ? "sxs " : "", - cap2 & (1 << 2) ? "apst " : "", - cap2 & (1 << 1) ? "nvmp " : "", - cap2 & (1 << 0) ? "boh " : ""); -} - -#ifndef CONFIG_SCSI_AHCI_PLAT -# if defined(CONFIG_DM_PCI) || defined(CONFIG_DM_SCSI) -static int ahci_init_one(struct udevice *dev) -# else -static int ahci_init_one(pci_dev_t dev) -# endif -{ -#if !defined(CONFIG_DM_SCSI) - u16 vendor; -#endif - int rc; - - probe_ent = malloc(sizeof(struct ahci_probe_ent)); - if (!probe_ent) { - printf("%s: No memory for probe_ent\n", __func__); - return -ENOMEM; - } - - memset(probe_ent, 0, sizeof(struct ahci_probe_ent)); - probe_ent->dev = dev; - - probe_ent->host_flags = ATA_FLAG_SATA - | ATA_FLAG_NO_LEGACY - | ATA_FLAG_MMIO - | ATA_FLAG_PIO_DMA - | ATA_FLAG_NO_ATAPI; - probe_ent->pio_mask = 0x1f; - probe_ent->udma_mask = 0x7f; /*Fixme,assume to support UDMA6 */ - -#if !defined(CONFIG_DM_SCSI) -#ifdef CONFIG_DM_PCI - probe_ent->mmio_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_5, - PCI_REGION_MEM); - - /* Take from kernel: - * JMicron-specific fixup: - * make sure we're in AHCI mode - */ - dm_pci_read_config16(dev, PCI_VENDOR_ID, &vendor); - if (vendor == 0x197b) - dm_pci_write_config8(dev, 0x41, 0xa1); -#else - probe_ent->mmio_base = pci_map_bar(dev, PCI_BASE_ADDRESS_5, - PCI_REGION_MEM); - - /* Take from kernel: - * JMicron-specific fixup: - * make sure we're in AHCI mode - */ - pci_read_config_word(dev, PCI_VENDOR_ID, &vendor); - if (vendor == 0x197b) - pci_write_config_byte(dev, 0x41, 0xa1); -#endif -#else - struct scsi_platdata *plat = dev_get_platdata(dev); - probe_ent->mmio_base = (void *)plat->base; -#endif - - debug("ahci mmio_base=0x%p\n", probe_ent->mmio_base); - /* initialize adapter */ - rc = ahci_host_init(probe_ent); - if (rc) - goto err_out; - - ahci_print_info(probe_ent); - - return 0; - - err_out: - return rc; -} -#endif - -#define MAX_DATA_BYTE_COUNT (4*1024*1024) - -static int ahci_fill_sg(u8 port, unsigned char *buf, int buf_len) -{ - struct ahci_ioports *pp = &(probe_ent->port[port]); - struct ahci_sg *ahci_sg = pp->cmd_tbl_sg; - u32 sg_count; - int i; - - sg_count = ((buf_len - 1) / MAX_DATA_BYTE_COUNT) + 1; - if (sg_count > AHCI_MAX_SG) { - printf("Error:Too much sg!\n"); - return -1; - } - - for (i = 0; i < sg_count; i++) { - ahci_sg->addr = - cpu_to_le32((unsigned long) buf + i * MAX_DATA_BYTE_COUNT); - ahci_sg->addr_hi = 0; - ahci_sg->flags_size = cpu_to_le32(0x3fffff & - (buf_len < MAX_DATA_BYTE_COUNT - ? (buf_len - 1) - : (MAX_DATA_BYTE_COUNT - 1))); - ahci_sg++; - buf_len -= MAX_DATA_BYTE_COUNT; - } - - return sg_count; -} - - -static void ahci_fill_cmd_slot(struct ahci_ioports *pp, u32 opts) -{ - pp->cmd_slot->opts = cpu_to_le32(opts); - pp->cmd_slot->status = 0; - pp->cmd_slot->tbl_addr = cpu_to_le32((u32)pp->cmd_tbl & 0xffffffff); -#ifdef CONFIG_PHYS_64BIT - pp->cmd_slot->tbl_addr_hi = - cpu_to_le32((u32)(((pp->cmd_tbl) >> 16) >> 16)); -#endif -} - -static int wait_spinup(void __iomem *port_mmio) -{ - ulong start; - u32 tf_data; - - start = get_timer(0); - do { - tf_data = readl(port_mmio + PORT_TFDATA); - if (!(tf_data & ATA_BUSY)) - return 0; - } while (get_timer(start) < WAIT_MS_SPINUP); - - return -ETIMEDOUT; -} - -static int ahci_port_start(u8 port) -{ - struct ahci_ioports *pp = &(probe_ent->port[port]); - void __iomem *port_mmio = pp->port_mmio; - u32 port_status; - void __iomem *mem; - - debug("Enter start port: %d\n", port); - port_status = readl(port_mmio + PORT_SCR_STAT); - debug("Port %d status: %x\n", port, port_status); - if ((port_status & 0xf) != 0x03) { - printf("No Link on this port!\n"); - return -1; - } - - mem = malloc(AHCI_PORT_PRIV_DMA_SZ + 2048); - if (!mem) { - free(pp); - printf("%s: No mem for table!\n", __func__); - return -ENOMEM; - } - - /* Aligned to 2048-bytes */ - mem = memalign(2048, AHCI_PORT_PRIV_DMA_SZ); - memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ); - - /* - * First item in chunk of DMA memory: 32-slot command table, - * 32 bytes each in size - */ - pp->cmd_slot = - (struct ahci_cmd_hdr *)(uintptr_t)virt_to_phys((void *)mem); - debug("cmd_slot = %p\n", pp->cmd_slot); - mem += (AHCI_CMD_SLOT_SZ + 224); - - /* - * Second item: Received-FIS area - */ - pp->rx_fis = virt_to_phys((void *)mem); - mem += AHCI_RX_FIS_SZ; - - /* - * Third item: data area for storing a single command - * and its scatter-gather table - */ - pp->cmd_tbl = virt_to_phys((void *)mem); - debug("cmd_tbl_dma = %lx\n", pp->cmd_tbl); - - mem += AHCI_CMD_TBL_HDR; - pp->cmd_tbl_sg = - (struct ahci_sg *)(uintptr_t)virt_to_phys((void *)mem); - - writel_with_flush((unsigned long)pp->cmd_slot, - port_mmio + PORT_LST_ADDR); - - writel_with_flush(pp->rx_fis, port_mmio + PORT_FIS_ADDR); - -#ifdef CONFIG_SUNXI_AHCI - sunxi_dma_init(port_mmio); -#endif - - writel_with_flush(PORT_CMD_ICC_ACTIVE | PORT_CMD_FIS_RX | - PORT_CMD_POWER_ON | PORT_CMD_SPIN_UP | - PORT_CMD_START, port_mmio + PORT_CMD); - - debug("Exit start port %d\n", port); - - /* - * Make sure interface is not busy based on error and status - * information from task file data register before proceeding - */ - return wait_spinup(port_mmio); -} - - -static int ahci_device_data_io(u8 port, u8 *fis, int fis_len, u8 *buf, - int buf_len, u8 is_write) -{ - - struct ahci_ioports *pp = &(probe_ent->port[port]); - void __iomem *port_mmio = pp->port_mmio; - u32 opts; - u32 port_status; - int sg_count; - - debug("Enter %s: for port %d\n", __func__, port); - - if (port > probe_ent->n_ports) { - printf("Invalid port number %d\n", port); - return -1; - } - - port_status = readl(port_mmio + PORT_SCR_STAT); - if ((port_status & 0xf) != 0x03) { - debug("No Link on port %d!\n", port); - return -1; - } - - memcpy((unsigned char *)pp->cmd_tbl, fis, fis_len); - - sg_count = ahci_fill_sg(port, buf, buf_len); - opts = (fis_len >> 2) | (sg_count << 16) | (is_write << 6); - ahci_fill_cmd_slot(pp, opts); - - ahci_dcache_flush_sata_cmd(pp); - ahci_dcache_flush_range((unsigned long)buf, (unsigned long)buf_len); - - writel_with_flush(1, port_mmio + PORT_CMD_ISSUE); - - if (waiting_for_cmd_completed(port_mmio + PORT_CMD_ISSUE, - WAIT_MS_DATAIO, 0x1)) { - printf("timeout exit!\n"); - return -1; - } - - ahci_dcache_invalidate_range((unsigned long)buf, - (unsigned long)buf_len); - debug("%s: %d byte transferred.\n", __func__, pp->cmd_slot->status); - - return 0; -} - - -static char *ata_id_strcpy(u16 *target, u16 *src, int len) -{ - int i; - for (i = 0; i < len / 2; i++) - target[i] = swab16(src[i]); - return (char *)target; -} - -/* - * SCSI INQUIRY command operation. - */ -static int ata_scsiop_inquiry(ccb *pccb) -{ - static const u8 hdr[] = { - 0, - 0, - 0x5, /* claim SPC-3 version compatibility */ - 2, - 95 - 4, - }; - u8 fis[20]; - u16 *idbuf; - ALLOC_CACHE_ALIGN_BUFFER(u16, tmpid, ATA_ID_WORDS); - u8 port; - - /* Clean ccb data buffer */ - memset(pccb->pdata, 0, pccb->datalen); - - memcpy(pccb->pdata, hdr, sizeof(hdr)); - - if (pccb->datalen <= 35) - return 0; - - memset(fis, 0, sizeof(fis)); - /* Construct the FIS */ - fis[0] = 0x27; /* Host to device FIS. */ - fis[1] = 1 << 7; /* Command FIS. */ - fis[2] = ATA_CMD_ID_ATA; /* Command byte. */ - - /* Read id from sata */ - port = pccb->target; - - if (ahci_device_data_io(port, (u8 *) &fis, sizeof(fis), (u8 *)tmpid, - ATA_ID_WORDS * 2, 0)) { - debug("scsi_ahci: SCSI inquiry command failure.\n"); - return -EIO; - } - - if (!ataid[port]) { - ataid[port] = malloc(ATA_ID_WORDS * 2); - if (!ataid[port]) { - printf("%s: No memory for ataid[port]\n", __func__); - return -ENOMEM; - } - } - - idbuf = ataid[port]; - - memcpy(idbuf, tmpid, ATA_ID_WORDS * 2); - ata_swap_buf_le16(idbuf, ATA_ID_WORDS); - - memcpy(&pccb->pdata[8], "ATA ", 8); - ata_id_strcpy((u16 *)&pccb->pdata[16], &idbuf[ATA_ID_PROD], 16); - ata_id_strcpy((u16 *)&pccb->pdata[32], &idbuf[ATA_ID_FW_REV], 4); - -#ifdef DEBUG - ata_dump_id(idbuf); -#endif - return 0; -} - - -/* - * SCSI READ10/WRITE10 command operation. - */ -static int ata_scsiop_read_write(ccb *pccb, u8 is_write) -{ - lbaint_t lba = 0; - u16 blocks = 0; - u8 fis[20]; - u8 *user_buffer = pccb->pdata; - u32 user_buffer_size = pccb->datalen; - - /* Retrieve the base LBA number from the ccb structure. */ - if (pccb->cmd[0] == SCSI_READ16) { - memcpy(&lba, pccb->cmd + 2, 8); - lba = be64_to_cpu(lba); - } else { - u32 temp; - memcpy(&temp, pccb->cmd + 2, 4); - lba = be32_to_cpu(temp); - } - - /* - * Retrieve the base LBA number and the block count from - * the ccb structure. - * - * For 10-byte and 16-byte SCSI R/W commands, transfer - * length 0 means transfer 0 block of data. - * However, for ATA R/W commands, sector count 0 means - * 256 or 65536 sectors, not 0 sectors as in SCSI. - * - * WARNING: one or two older ATA drives treat 0 as 0... - */ - if (pccb->cmd[0] == SCSI_READ16) - blocks = (((u16)pccb->cmd[13]) << 8) | ((u16) pccb->cmd[14]); - else - blocks = (((u16)pccb->cmd[7]) << 8) | ((u16) pccb->cmd[8]); - - debug("scsi_ahci: %s %u blocks starting from lba 0x" LBAFU "\n", - is_write ? "write" : "read", blocks, lba); - - /* Preset the FIS */ - memset(fis, 0, sizeof(fis)); - fis[0] = 0x27; /* Host to device FIS. */ - fis[1] = 1 << 7; /* Command FIS. */ - /* Command byte (read/write). */ - fis[2] = is_write ? ATA_CMD_WRITE_EXT : ATA_CMD_READ_EXT; - - while (blocks) { - u16 now_blocks; /* number of blocks per iteration */ - u32 transfer_size; /* number of bytes per iteration */ - - now_blocks = min((u16)MAX_SATA_BLOCKS_READ_WRITE, blocks); - - transfer_size = ATA_SECT_SIZE * now_blocks; - if (transfer_size > user_buffer_size) { - printf("scsi_ahci: Error: buffer too small.\n"); - return -EIO; - } - - /* - * LBA48 SATA command but only use 32bit address range within - * that (unless we've enabled 64bit LBA support). The next - * smaller command range (28bit) is too small. - */ - fis[4] = (lba >> 0) & 0xff; - fis[5] = (lba >> 8) & 0xff; - fis[6] = (lba >> 16) & 0xff; - fis[7] = 1 << 6; /* device reg: set LBA mode */ - fis[8] = ((lba >> 24) & 0xff); -#ifdef CONFIG_SYS_64BIT_LBA - if (pccb->cmd[0] == SCSI_READ16) { - fis[9] = ((lba >> 32) & 0xff); - fis[10] = ((lba >> 40) & 0xff); - } -#endif - - fis[3] = 0xe0; /* features */ - - /* Block (sector) count */ - fis[12] = (now_blocks >> 0) & 0xff; - fis[13] = (now_blocks >> 8) & 0xff; - - /* Read/Write from ahci */ - if (ahci_device_data_io(pccb->target, (u8 *) &fis, sizeof(fis), - user_buffer, transfer_size, - is_write)) { - debug("scsi_ahci: SCSI %s10 command failure.\n", - is_write ? "WRITE" : "READ"); - return -EIO; - } - - /* If this transaction is a write, do a following flush. - * Writes in u-boot are so rare, and the logic to know when is - * the last write and do a flush only there is sufficiently - * difficult. Just do a flush after every write. This incurs, - * usually, one extra flush when the rare writes do happen. - */ - if (is_write) { - if (-EIO == ata_io_flush(pccb->target)) - return -EIO; - } - user_buffer += transfer_size; - user_buffer_size -= transfer_size; - blocks -= now_blocks; - lba += now_blocks; - } - - return 0; -} - - -/* - * SCSI READ CAPACITY10 command operation. - */ -static int ata_scsiop_read_capacity10(ccb *pccb) -{ - u32 cap; - u64 cap64; - u32 block_size; - - if (!ataid[pccb->target]) { - printf("scsi_ahci: SCSI READ CAPACITY10 command failure. " - "\tNo ATA info!\n" - "\tPlease run SCSI command INQUIRY first!\n"); - return -EPERM; - } - - cap64 = ata_id_n_sectors(ataid[pccb->target]); - if (cap64 > 0x100000000ULL) - cap64 = 0xffffffff; - - cap = cpu_to_be32(cap64); - memcpy(pccb->pdata, &cap, sizeof(cap)); - - block_size = cpu_to_be32((u32)512); - memcpy(&pccb->pdata[4], &block_size, 4); - - return 0; -} - - -/* - * SCSI READ CAPACITY16 command operation. - */ -static int ata_scsiop_read_capacity16(ccb *pccb) -{ - u64 cap; - u64 block_size; - - if (!ataid[pccb->target]) { - printf("scsi_ahci: SCSI READ CAPACITY16 command failure. " - "\tNo ATA info!\n" - "\tPlease run SCSI command INQUIRY first!\n"); - return -EPERM; - } - - cap = ata_id_n_sectors(ataid[pccb->target]); - cap = cpu_to_be64(cap); - memcpy(pccb->pdata, &cap, sizeof(cap)); - - block_size = cpu_to_be64((u64)512); - memcpy(&pccb->pdata[8], &block_size, 8); - - return 0; -} - - -/* - * SCSI TEST UNIT READY command operation. - */ -static int ata_scsiop_test_unit_ready(ccb *pccb) -{ - return (ataid[pccb->target]) ? 0 : -EPERM; -} - - -int scsi_exec(ccb *pccb) -{ - int ret; - - switch (pccb->cmd[0]) { - case SCSI_READ16: - case SCSI_READ10: - ret = ata_scsiop_read_write(pccb, 0); - break; - case SCSI_WRITE10: - ret = ata_scsiop_read_write(pccb, 1); - break; - case SCSI_RD_CAPAC10: - ret = ata_scsiop_read_capacity10(pccb); - break; - case SCSI_RD_CAPAC16: - ret = ata_scsiop_read_capacity16(pccb); - break; - case SCSI_TST_U_RDY: - ret = ata_scsiop_test_unit_ready(pccb); - break; - case SCSI_INQUIRY: - ret = ata_scsiop_inquiry(pccb); - break; - default: - printf("Unsupport SCSI command 0x%02x\n", pccb->cmd[0]); - return false; - } - - if (ret) { - debug("SCSI command 0x%02x ret errno %d\n", pccb->cmd[0], ret); - return false; - } - return true; - -} - -#if defined(CONFIG_DM_SCSI) -void scsi_low_level_init(int busdevfunc, struct udevice *dev) -#else -void scsi_low_level_init(int busdevfunc) -#endif -{ - int i; - u32 linkmap; - -#ifndef CONFIG_SCSI_AHCI_PLAT -# if defined(CONFIG_DM_PCI) - struct udevice *dev; - int ret; - - ret = dm_pci_bus_find_bdf(busdevfunc, &dev); - if (ret) - return; - ahci_init_one(dev); -# elif defined(CONFIG_DM_SCSI) - ahci_init_one(dev); -# else - ahci_init_one(busdevfunc); -# endif -#endif - - linkmap = probe_ent->link_port_map; - - for (i = 0; i < CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) { - if (((linkmap >> i) & 0x01)) { - if (ahci_port_start((u8) i)) { - printf("Can not start port %d\n", i); - continue; - } - } - } -} - -#ifdef CONFIG_SCSI_AHCI_PLAT -int ahci_init(void __iomem *base) -{ - int i, rc = 0; - u32 linkmap; - - probe_ent = malloc(sizeof(struct ahci_probe_ent)); - if (!probe_ent) { - printf("%s: No memory for probe_ent\n", __func__); - return -ENOMEM; - } - - memset(probe_ent, 0, sizeof(struct ahci_probe_ent)); - - probe_ent->host_flags = ATA_FLAG_SATA - | ATA_FLAG_NO_LEGACY - | ATA_FLAG_MMIO - | ATA_FLAG_PIO_DMA - | ATA_FLAG_NO_ATAPI; - probe_ent->pio_mask = 0x1f; - probe_ent->udma_mask = 0x7f; /*Fixme,assume to support UDMA6 */ - - probe_ent->mmio_base = base; - - /* initialize adapter */ - rc = ahci_host_init(probe_ent); - if (rc) - goto err_out; - - ahci_print_info(probe_ent); - - linkmap = probe_ent->link_port_map; - - for (i = 0; i < CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) { - if (((linkmap >> i) & 0x01)) { - if (ahci_port_start((u8) i)) { - printf("Can not start port %d\n", i); - continue; - } - } - } -err_out: - return rc; -} - -void __weak scsi_init(void) -{ -} - -#endif - -/* - * In the general case of generic rotating media it makes sense to have a - * flush capability. It probably even makes sense in the case of SSDs because - * one cannot always know for sure what kind of internal cache/flush mechanism - * is embodied therein. At first it was planned to invoke this after the last - * write to disk and before rebooting. In practice, knowing, a priori, which - * is the last write is difficult. Because writing to the disk in u-boot is - * very rare, this flush command will be invoked after every block write. - */ -static int ata_io_flush(u8 port) -{ - u8 fis[20]; - struct ahci_ioports *pp = &(probe_ent->port[port]); - void __iomem *port_mmio = pp->port_mmio; - u32 cmd_fis_len = 5; /* five dwords */ - - /* Preset the FIS */ - memset(fis, 0, 20); - fis[0] = 0x27; /* Host to device FIS. */ - fis[1] = 1 << 7; /* Command FIS. */ - fis[2] = ATA_CMD_FLUSH_EXT; - - memcpy((unsigned char *)pp->cmd_tbl, fis, 20); - ahci_fill_cmd_slot(pp, cmd_fis_len); - ahci_dcache_flush_sata_cmd(pp); - writel_with_flush(1, port_mmio + PORT_CMD_ISSUE); - - if (waiting_for_cmd_completed(port_mmio + PORT_CMD_ISSUE, - WAIT_MS_FLUSH, 0x1)) { - debug("scsi_ahci: flush command timeout on port %d.\n", port); - return -EIO; - } - - return 0; -} - - -__weak void scsi_bus_reset(void) -{ - /*Not implement*/ -} diff --git a/drivers/block/dwc_ahci.c b/drivers/block/dwc_ahci.c deleted file mode 100644 index 3f839bf..0000000 --- a/drivers/block/dwc_ahci.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * DWC SATA platform driver - * - * (C) Copyright 2016 - * Texas Instruments Incorporated, - * - * Author: Mugunthan V N - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -DECLARE_GLOBAL_DATA_PTR; - -struct dwc_ahci_priv { - void *base; - void *wrapper_base; -}; - -static int dwc_ahci_ofdata_to_platdata(struct udevice *dev) -{ - struct dwc_ahci_priv *priv = dev_get_priv(dev); - struct scsi_platdata *plat = dev_get_platdata(dev); - fdt_addr_t addr; - - plat->max_id = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev), - "max-id", CONFIG_SYS_SCSI_MAX_SCSI_ID); - plat->max_lun = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev), - "max-lun", CONFIG_SYS_SCSI_MAX_LUN); - - priv->base = map_physmem(devfdt_get_addr(dev), sizeof(void *), - MAP_NOCACHE); - - addr = devfdt_get_addr_index(dev, 1); - if (addr != FDT_ADDR_T_NONE) { - priv->wrapper_base = map_physmem(addr, sizeof(void *), - MAP_NOCACHE); - } else { - priv->wrapper_base = NULL; - } - - return 0; -} - -static int dwc_ahci_probe(struct udevice *dev) -{ - struct dwc_ahci_priv *priv = dev_get_priv(dev); - int ret; - struct phy phy; - - ret = generic_phy_get_by_name(dev, "sata-phy", &phy); - if (ret) { - error("can't get the phy from DT\n"); - return ret; - } - - ret = generic_phy_init(&phy); - if (ret) { - error("unable to initialize the sata phy\n"); - return ret; - } - - ret = generic_phy_power_on(&phy); - if (ret) { - error("unable to power on the sata phy\n"); - return ret; - } - - if (priv->wrapper_base) { - u32 val = TI_SATA_IDLE_NO | TI_SATA_STANDBY_NO; - - /* Enable SATA module, No Idle, No Standby */ - writel(val, priv->wrapper_base + TI_SATA_SYSCONFIG); - } - - return ahci_init(priv->base); -} - -static const struct udevice_id dwc_ahci_ids[] = { - { .compatible = "snps,dwc-ahci" }, - { } -}; - -U_BOOT_DRIVER(dwc_ahci) = { - .name = "dwc_ahci", - .id = UCLASS_SCSI, - .of_match = dwc_ahci_ids, - .ofdata_to_platdata = dwc_ahci_ofdata_to_platdata, - .probe = dwc_ahci_probe, - .priv_auto_alloc_size = sizeof(struct dwc_ahci_priv), - .platdata_auto_alloc_size = sizeof(struct scsi_platdata), - .flags = DM_FLAG_ALLOC_PRIV_DMA, -}; diff --git a/drivers/block/dwc_ahsata.c b/drivers/block/dwc_ahsata.c deleted file mode 100644 index c306e92..0000000 --- a/drivers/block/dwc_ahsata.c +++ /dev/null @@ -1,1018 +0,0 @@ -/* - * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. - * Terry Lv - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include "dwc_ahsata.h" - -struct sata_port_regs { - u32 clb; - u32 clbu; - u32 fb; - u32 fbu; - u32 is; - u32 ie; - u32 cmd; - u32 res1[1]; - u32 tfd; - u32 sig; - u32 ssts; - u32 sctl; - u32 serr; - u32 sact; - u32 ci; - u32 sntf; - u32 res2[1]; - u32 dmacr; - u32 res3[1]; - u32 phycr; - u32 physr; -}; - -struct sata_host_regs { - u32 cap; - u32 ghc; - u32 is; - u32 pi; - u32 vs; - u32 ccc_ctl; - u32 ccc_ports; - u32 res1[2]; - u32 cap2; - u32 res2[30]; - u32 bistafr; - u32 bistcr; - u32 bistfctr; - u32 bistsr; - u32 bistdecr; - u32 res3[2]; - u32 oobr; - u32 res4[8]; - u32 timer1ms; - u32 res5[1]; - u32 gparam1r; - u32 gparam2r; - u32 pparamr; - u32 testr; - u32 versionr; - u32 idr; -}; - -#define MAX_DATA_BYTES_PER_SG (4 * 1024 * 1024) -#define MAX_BYTES_PER_TRANS (AHCI_MAX_SG * MAX_DATA_BYTES_PER_SG) - -#define writel_with_flush(a, b) do { writel(a, b); readl(b); } while (0) - -static int is_ready; - -static inline void __iomem *ahci_port_base(void __iomem *base, u32 port) -{ - return base + 0x100 + (port * 0x80); -} - -static int waiting_for_cmd_completed(u8 *offset, - int timeout_msec, - u32 sign) -{ - int i; - u32 status; - - for (i = 0; - ((status = readl(offset)) & sign) && i < timeout_msec; - ++i) - mdelay(1); - - return (i < timeout_msec) ? 0 : -1; -} - -static int ahci_setup_oobr(struct ahci_probe_ent *probe_ent, - int clk) -{ - struct sata_host_regs *host_mmio = - (struct sata_host_regs *)probe_ent->mmio_base; - - writel(SATA_HOST_OOBR_WE, &(host_mmio->oobr)); - writel(0x02060b14, &(host_mmio->oobr)); - - return 0; -} - -static int ahci_host_init(struct ahci_probe_ent *probe_ent) -{ - u32 tmp, cap_save, num_ports; - int i, j, timeout = 1000; - struct sata_port_regs *port_mmio = NULL; - struct sata_host_regs *host_mmio = - (struct sata_host_regs *)probe_ent->mmio_base; - int clk = mxc_get_clock(MXC_SATA_CLK); - - cap_save = readl(&(host_mmio->cap)); - cap_save |= SATA_HOST_CAP_SSS; - - /* global controller reset */ - tmp = readl(&(host_mmio->ghc)); - if ((tmp & SATA_HOST_GHC_HR) == 0) - writel_with_flush(tmp | SATA_HOST_GHC_HR, &(host_mmio->ghc)); - - while ((readl(&(host_mmio->ghc)) & SATA_HOST_GHC_HR) - && --timeout) - ; - - if (timeout <= 0) { - debug("controller reset failed (0x%x)\n", tmp); - return -1; - } - - /* Set timer 1ms */ - writel(clk / 1000, &(host_mmio->timer1ms)); - - ahci_setup_oobr(probe_ent, 0); - - writel_with_flush(SATA_HOST_GHC_AE, &(host_mmio->ghc)); - writel(cap_save, &(host_mmio->cap)); - num_ports = (cap_save & SATA_HOST_CAP_NP_MASK) + 1; - writel_with_flush((1 << num_ports) - 1, - &(host_mmio->pi)); - - /* - * Determine which Ports are implemented by the DWC_ahsata, - * by reading the PI register. This bit map value aids the - * software to determine how many Ports are available and - * which Port registers need to be initialized. - */ - probe_ent->cap = readl(&(host_mmio->cap)); - probe_ent->port_map = readl(&(host_mmio->pi)); - - /* Determine how many command slots the HBA supports */ - probe_ent->n_ports = - (probe_ent->cap & SATA_HOST_CAP_NP_MASK) + 1; - - debug("cap 0x%x port_map 0x%x n_ports %d\n", - probe_ent->cap, probe_ent->port_map, probe_ent->n_ports); - - for (i = 0; i < probe_ent->n_ports; i++) { - probe_ent->port[i].port_mmio = - ahci_port_base(host_mmio, i); - port_mmio = - (struct sata_port_regs *)probe_ent->port[i].port_mmio; - - /* Ensure that the DWC_ahsata is in idle state */ - tmp = readl(&(port_mmio->cmd)); - - /* - * When P#CMD.ST, P#CMD.CR, P#CMD.FRE and P#CMD.FR - * are all cleared, the Port is in an idle state. - */ - if (tmp & (SATA_PORT_CMD_CR | SATA_PORT_CMD_FR | - SATA_PORT_CMD_FRE | SATA_PORT_CMD_ST)) { - - /* - * System software places a Port into the idle state by - * clearing P#CMD.ST and waiting for P#CMD.CR to return - * 0 when read. - */ - tmp &= ~SATA_PORT_CMD_ST; - writel_with_flush(tmp, &(port_mmio->cmd)); - - /* - * spec says 500 msecs for each bit, so - * this is slightly incorrect. - */ - mdelay(500); - - timeout = 1000; - while ((readl(&(port_mmio->cmd)) & SATA_PORT_CMD_CR) - && --timeout) - ; - - if (timeout <= 0) { - debug("port reset failed (0x%x)\n", tmp); - return -1; - } - } - - /* Spin-up device */ - tmp = readl(&(port_mmio->cmd)); - writel((tmp | SATA_PORT_CMD_SUD), &(port_mmio->cmd)); - - /* Wait for spin-up to finish */ - timeout = 1000; - while (!(readl(&(port_mmio->cmd)) | SATA_PORT_CMD_SUD) - && --timeout) - ; - if (timeout <= 0) { - debug("Spin-Up can't finish!\n"); - return -1; - } - - for (j = 0; j < 100; ++j) { - mdelay(10); - tmp = readl(&(port_mmio->ssts)); - if (((tmp & SATA_PORT_SSTS_DET_MASK) == 0x3) || - ((tmp & SATA_PORT_SSTS_DET_MASK) == 0x1)) - break; - } - - /* Wait for COMINIT bit 26 (DIAG_X) in SERR */ - timeout = 1000; - while (!(readl(&(port_mmio->serr)) | SATA_PORT_SERR_DIAG_X) - && --timeout) - ; - if (timeout <= 0) { - debug("Can't find DIAG_X set!\n"); - return -1; - } - - /* - * For each implemented Port, clear the P#SERR - * register, by writing ones to each implemented\ - * bit location. - */ - tmp = readl(&(port_mmio->serr)); - debug("P#SERR 0x%x\n", - tmp); - writel(tmp, &(port_mmio->serr)); - - /* Ack any pending irq events for this port */ - tmp = readl(&(host_mmio->is)); - debug("IS 0x%x\n", tmp); - if (tmp) - writel(tmp, &(host_mmio->is)); - - writel(1 << i, &(host_mmio->is)); - - /* set irq mask (enables interrupts) */ - writel(DEF_PORT_IRQ, &(port_mmio->ie)); - - /* register linkup ports */ - tmp = readl(&(port_mmio->ssts)); - debug("Port %d status: 0x%x\n", i, tmp); - if ((tmp & SATA_PORT_SSTS_DET_MASK) == 0x03) - probe_ent->link_port_map |= (0x01 << i); - } - - tmp = readl(&(host_mmio->ghc)); - debug("GHC 0x%x\n", tmp); - writel(tmp | SATA_HOST_GHC_IE, &(host_mmio->ghc)); - tmp = readl(&(host_mmio->ghc)); - debug("GHC 0x%x\n", tmp); - - return 0; -} - -static void ahci_print_info(struct ahci_probe_ent *probe_ent) -{ - struct sata_host_regs *host_mmio = - (struct sata_host_regs *)probe_ent->mmio_base; - u32 vers, cap, impl, speed; - const char *speed_s; - const char *scc_s; - - vers = readl(&(host_mmio->vs)); - cap = probe_ent->cap; - impl = probe_ent->port_map; - - speed = (cap & SATA_HOST_CAP_ISS_MASK) - >> SATA_HOST_CAP_ISS_OFFSET; - if (speed == 1) - speed_s = "1.5"; - else if (speed == 2) - speed_s = "3"; - else - speed_s = "?"; - - scc_s = "SATA"; - - printf("AHCI %02x%02x.%02x%02x " - "%u slots %u ports %s Gbps 0x%x impl %s mode\n", - (vers >> 24) & 0xff, - (vers >> 16) & 0xff, - (vers >> 8) & 0xff, - vers & 0xff, - ((cap >> 8) & 0x1f) + 1, - (cap & 0x1f) + 1, - speed_s, - impl, - scc_s); - - printf("flags: " - "%s%s%s%s%s%s" - "%s%s%s%s%s%s%s\n", - cap & (1 << 31) ? "64bit " : "", - cap & (1 << 30) ? "ncq " : "", - cap & (1 << 28) ? "ilck " : "", - cap & (1 << 27) ? "stag " : "", - cap & (1 << 26) ? "pm " : "", - cap & (1 << 25) ? "led " : "", - cap & (1 << 24) ? "clo " : "", - cap & (1 << 19) ? "nz " : "", - cap & (1 << 18) ? "only " : "", - cap & (1 << 17) ? "pmp " : "", - cap & (1 << 15) ? "pio " : "", - cap & (1 << 14) ? "slum " : "", - cap & (1 << 13) ? "part " : ""); -} - -static int ahci_init_one(int pdev) -{ - int rc; - struct ahci_probe_ent *probe_ent = NULL; - - probe_ent = malloc(sizeof(struct ahci_probe_ent)); - memset(probe_ent, 0, sizeof(struct ahci_probe_ent)); - probe_ent->dev = pdev; - - probe_ent->host_flags = ATA_FLAG_SATA - | ATA_FLAG_NO_LEGACY - | ATA_FLAG_MMIO - | ATA_FLAG_PIO_DMA - | ATA_FLAG_NO_ATAPI; - - probe_ent->mmio_base = (void __iomem *)CONFIG_DWC_AHSATA_BASE_ADDR; - - /* initialize adapter */ - rc = ahci_host_init(probe_ent); - if (rc) - goto err_out; - - ahci_print_info(probe_ent); - - /* Save the private struct to block device struct */ - sata_dev_desc[pdev].priv = (void *)probe_ent; - - return 0; - -err_out: - return rc; -} - -static int ahci_fill_sg(struct ahci_probe_ent *probe_ent, - u8 port, unsigned char *buf, int buf_len) -{ - struct ahci_ioports *pp = &(probe_ent->port[port]); - struct ahci_sg *ahci_sg = pp->cmd_tbl_sg; - u32 sg_count, max_bytes; - int i; - - max_bytes = MAX_DATA_BYTES_PER_SG; - sg_count = ((buf_len - 1) / max_bytes) + 1; - if (sg_count > AHCI_MAX_SG) { - printf("Error:Too much sg!\n"); - return -1; - } - - for (i = 0; i < sg_count; i++) { - ahci_sg->addr = - cpu_to_le32((u32)buf + i * max_bytes); - ahci_sg->addr_hi = 0; - ahci_sg->flags_size = cpu_to_le32(0x3fffff & - (buf_len < max_bytes - ? (buf_len - 1) - : (max_bytes - 1))); - ahci_sg++; - buf_len -= max_bytes; - } - - return sg_count; -} - -static void ahci_fill_cmd_slot(struct ahci_ioports *pp, u32 cmd_slot, u32 opts) -{ - struct ahci_cmd_hdr *cmd_hdr = (struct ahci_cmd_hdr *)(pp->cmd_slot + - AHCI_CMD_SLOT_SZ * cmd_slot); - - memset(cmd_hdr, 0, AHCI_CMD_SLOT_SZ); - cmd_hdr->opts = cpu_to_le32(opts); - cmd_hdr->status = 0; - pp->cmd_slot->tbl_addr = cpu_to_le32((u32)pp->cmd_tbl & 0xffffffff); -#ifdef CONFIG_PHYS_64BIT - pp->cmd_slot->tbl_addr_hi = - cpu_to_le32((u32)(((pp->cmd_tbl) >> 16) >> 16)); -#endif -} - -#define AHCI_GET_CMD_SLOT(c) ((c) ? ffs(c) : 0) - -static int ahci_exec_ata_cmd(struct ahci_probe_ent *probe_ent, - u8 port, struct sata_fis_h2d *cfis, - u8 *buf, u32 buf_len, s32 is_write) -{ - struct ahci_ioports *pp = &(probe_ent->port[port]); - struct sata_port_regs *port_mmio = - (struct sata_port_regs *)pp->port_mmio; - u32 opts; - int sg_count = 0, cmd_slot = 0; - - cmd_slot = AHCI_GET_CMD_SLOT(readl(&(port_mmio->ci))); - if (32 == cmd_slot) { - printf("Can't find empty command slot!\n"); - return 0; - } - - /* Check xfer length */ - if (buf_len > MAX_BYTES_PER_TRANS) { - printf("Max transfer length is %dB\n\r", - MAX_BYTES_PER_TRANS); - return 0; - } - - memcpy((u8 *)(pp->cmd_tbl), cfis, sizeof(struct sata_fis_h2d)); - if (buf && buf_len) - sg_count = ahci_fill_sg(probe_ent, port, buf, buf_len); - opts = (sizeof(struct sata_fis_h2d) >> 2) | (sg_count << 16); - if (is_write) { - opts |= 0x40; - flush_cache((ulong)buf, buf_len); - } - ahci_fill_cmd_slot(pp, cmd_slot, opts); - - flush_cache((int)(pp->cmd_slot), AHCI_PORT_PRIV_DMA_SZ); - writel_with_flush(1 << cmd_slot, &(port_mmio->ci)); - - if (waiting_for_cmd_completed((u8 *)&(port_mmio->ci), - 10000, 0x1 << cmd_slot)) { - printf("timeout exit!\n"); - return -1; - } - invalidate_dcache_range((int)(pp->cmd_slot), - (int)(pp->cmd_slot)+AHCI_PORT_PRIV_DMA_SZ); - debug("ahci_exec_ata_cmd: %d byte transferred.\n", - pp->cmd_slot->status); - if (!is_write) - invalidate_dcache_range((ulong)buf, (ulong)buf+buf_len); - - return buf_len; -} - -static void ahci_set_feature(u8 dev, u8 port) -{ - struct ahci_probe_ent *probe_ent = - (struct ahci_probe_ent *)sata_dev_desc[dev].priv; - struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN); - struct sata_fis_h2d *cfis = &h2d; - - memset(cfis, 0, sizeof(struct sata_fis_h2d)); - cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; - cfis->pm_port_c = 1 << 7; - cfis->command = ATA_CMD_SET_FEATURES; - cfis->features = SETFEATURES_XFER; - cfis->sector_count = ffs(probe_ent->udma_mask + 1) + 0x3e; - - ahci_exec_ata_cmd(probe_ent, port, cfis, NULL, 0, READ_CMD); -} - -static int ahci_port_start(struct ahci_probe_ent *probe_ent, - u8 port) -{ - struct ahci_ioports *pp = &(probe_ent->port[port]); - struct sata_port_regs *port_mmio = - (struct sata_port_regs *)pp->port_mmio; - u32 port_status; - u32 mem; - int timeout = 10000000; - - debug("Enter start port: %d\n", port); - port_status = readl(&(port_mmio->ssts)); - debug("Port %d status: %x\n", port, port_status); - if ((port_status & 0xf) != 0x03) { - printf("No Link on this port!\n"); - return -1; - } - - mem = (u32)malloc(AHCI_PORT_PRIV_DMA_SZ + 1024); - if (!mem) { - free(pp); - printf("No mem for table!\n"); - return -ENOMEM; - } - - mem = (mem + 0x400) & (~0x3ff); /* Aligned to 1024-bytes */ - memset((u8 *)mem, 0, AHCI_PORT_PRIV_DMA_SZ); - - /* - * First item in chunk of DMA memory: 32-slot command table, - * 32 bytes each in size - */ - pp->cmd_slot = (struct ahci_cmd_hdr *)mem; - debug("cmd_slot = 0x%x\n", (unsigned int) pp->cmd_slot); - mem += (AHCI_CMD_SLOT_SZ * DWC_AHSATA_MAX_CMD_SLOTS); - - /* - * Second item: Received-FIS area, 256-Byte aligned - */ - pp->rx_fis = mem; - mem += AHCI_RX_FIS_SZ; - - /* - * Third item: data area for storing a single command - * and its scatter-gather table - */ - pp->cmd_tbl = mem; - debug("cmd_tbl_dma = 0x%lx\n", pp->cmd_tbl); - - mem += AHCI_CMD_TBL_HDR; - - writel_with_flush(0x00004444, &(port_mmio->dmacr)); - pp->cmd_tbl_sg = (struct ahci_sg *)mem; - writel_with_flush((u32)pp->cmd_slot, &(port_mmio->clb)); - writel_with_flush(pp->rx_fis, &(port_mmio->fb)); - - /* Enable FRE */ - writel_with_flush((SATA_PORT_CMD_FRE | readl(&(port_mmio->cmd))), - &(port_mmio->cmd)); - - /* Wait device ready */ - while ((readl(&(port_mmio->tfd)) & (SATA_PORT_TFD_STS_ERR | - SATA_PORT_TFD_STS_DRQ | SATA_PORT_TFD_STS_BSY)) - && --timeout) - ; - if (timeout <= 0) { - debug("Device not ready for BSY, DRQ and" - "ERR in TFD!\n"); - return -1; - } - - writel_with_flush(PORT_CMD_ICC_ACTIVE | PORT_CMD_FIS_RX | - PORT_CMD_POWER_ON | PORT_CMD_SPIN_UP | - PORT_CMD_START, &(port_mmio->cmd)); - - debug("Exit start port %d\n", port); - - return 0; -} - -int init_sata(int dev) -{ - int i; - u32 linkmap; - struct ahci_probe_ent *probe_ent = NULL; - -#if defined(CONFIG_MX6) - if (!is_mx6dq() && !is_mx6dqp()) - return 1; -#endif - if (dev < 0 || dev > (CONFIG_SYS_SATA_MAX_DEVICE - 1)) { - printf("The sata index %d is out of ranges\n\r", dev); - return -1; - } - - ahci_init_one(dev); - - probe_ent = (struct ahci_probe_ent *)sata_dev_desc[dev].priv; - linkmap = probe_ent->link_port_map; - - if (0 == linkmap) { - printf("No port device detected!\n"); - return 1; - } - - for (i = 0; i < probe_ent->n_ports; i++) { - if ((linkmap >> i) && ((linkmap >> i) & 0x01)) { - if (ahci_port_start(probe_ent, (u8)i)) { - printf("Can not start port %d\n", i); - return 1; - } - probe_ent->hard_port_no = i; - break; - } - } - - return 0; -} - -int reset_sata(int dev) -{ - struct ahci_probe_ent *probe_ent; - struct sata_host_regs *host_mmio; - - if (dev < 0 || dev > (CONFIG_SYS_SATA_MAX_DEVICE - 1)) { - printf("The sata index %d is out of ranges\n\r", dev); - return -1; - } - - probe_ent = (struct ahci_probe_ent *)sata_dev_desc[dev].priv; - if (NULL == probe_ent) - /* not initialized, so nothing to reset */ - return 0; - - host_mmio = (struct sata_host_regs *)probe_ent->mmio_base; - setbits_le32(&host_mmio->ghc, SATA_HOST_GHC_HR); - while (readl(&host_mmio->ghc) & SATA_HOST_GHC_HR) - udelay(100); - - return 0; -} - -static void dwc_ahsata_print_info(int dev) -{ - struct blk_desc *pdev = &(sata_dev_desc[dev]); - - printf("SATA Device Info:\n\r"); -#ifdef CONFIG_SYS_64BIT_LBA - printf("S/N: %s\n\rProduct model number: %s\n\r" - "Firmware version: %s\n\rCapacity: %lld sectors\n\r", - pdev->product, pdev->vendor, pdev->revision, pdev->lba); -#else - printf("S/N: %s\n\rProduct model number: %s\n\r" - "Firmware version: %s\n\rCapacity: %ld sectors\n\r", - pdev->product, pdev->vendor, pdev->revision, pdev->lba); -#endif -} - -static void dwc_ahsata_identify(int dev, u16 *id) -{ - struct ahci_probe_ent *probe_ent = - (struct ahci_probe_ent *)sata_dev_desc[dev].priv; - struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN); - struct sata_fis_h2d *cfis = &h2d; - u8 port = probe_ent->hard_port_no; - - memset(cfis, 0, sizeof(struct sata_fis_h2d)); - - cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; - cfis->pm_port_c = 0x80; /* is command */ - cfis->command = ATA_CMD_ID_ATA; - - ahci_exec_ata_cmd(probe_ent, port, cfis, - (u8 *)id, ATA_ID_WORDS * 2, READ_CMD); - ata_swap_buf_le16(id, ATA_ID_WORDS); -} - -static void dwc_ahsata_xfer_mode(int dev, u16 *id) -{ - struct ahci_probe_ent *probe_ent = - (struct ahci_probe_ent *)sata_dev_desc[dev].priv; - - probe_ent->pio_mask = id[ATA_ID_PIO_MODES]; - probe_ent->udma_mask = id[ATA_ID_UDMA_MODES]; - debug("pio %04x, udma %04x\n\r", - probe_ent->pio_mask, probe_ent->udma_mask); -} - -static u32 dwc_ahsata_rw_cmd(int dev, u32 start, u32 blkcnt, - u8 *buffer, int is_write) -{ - struct ahci_probe_ent *probe_ent = - (struct ahci_probe_ent *)sata_dev_desc[dev].priv; - struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN); - struct sata_fis_h2d *cfis = &h2d; - u8 port = probe_ent->hard_port_no; - u32 block; - - block = start; - - memset(cfis, 0, sizeof(struct sata_fis_h2d)); - - cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; - cfis->pm_port_c = 0x80; /* is command */ - cfis->command = (is_write) ? ATA_CMD_WRITE : ATA_CMD_READ; - cfis->device = ATA_LBA; - - cfis->device |= (block >> 24) & 0xf; - cfis->lba_high = (block >> 16) & 0xff; - cfis->lba_mid = (block >> 8) & 0xff; - cfis->lba_low = block & 0xff; - cfis->sector_count = (u8)(blkcnt & 0xff); - - if (ahci_exec_ata_cmd(probe_ent, port, cfis, - buffer, ATA_SECT_SIZE * blkcnt, is_write) > 0) - return blkcnt; - else - return 0; -} - -void dwc_ahsata_flush_cache(int dev) -{ - struct ahci_probe_ent *probe_ent = - (struct ahci_probe_ent *)sata_dev_desc[dev].priv; - struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN); - struct sata_fis_h2d *cfis = &h2d; - u8 port = probe_ent->hard_port_no; - - memset(cfis, 0, sizeof(struct sata_fis_h2d)); - - cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; - cfis->pm_port_c = 0x80; /* is command */ - cfis->command = ATA_CMD_FLUSH; - - ahci_exec_ata_cmd(probe_ent, port, cfis, NULL, 0, 0); -} - -static u32 dwc_ahsata_rw_cmd_ext(int dev, u32 start, lbaint_t blkcnt, - u8 *buffer, int is_write) -{ - struct ahci_probe_ent *probe_ent = - (struct ahci_probe_ent *)sata_dev_desc[dev].priv; - struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN); - struct sata_fis_h2d *cfis = &h2d; - u8 port = probe_ent->hard_port_no; - u64 block; - - block = (u64)start; - - memset(cfis, 0, sizeof(struct sata_fis_h2d)); - - cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; - cfis->pm_port_c = 0x80; /* is command */ - - cfis->command = (is_write) ? ATA_CMD_WRITE_EXT - : ATA_CMD_READ_EXT; - - cfis->lba_high_exp = (block >> 40) & 0xff; - cfis->lba_mid_exp = (block >> 32) & 0xff; - cfis->lba_low_exp = (block >> 24) & 0xff; - cfis->lba_high = (block >> 16) & 0xff; - cfis->lba_mid = (block >> 8) & 0xff; - cfis->lba_low = block & 0xff; - cfis->device = ATA_LBA; - cfis->sector_count_exp = (blkcnt >> 8) & 0xff; - cfis->sector_count = blkcnt & 0xff; - - if (ahci_exec_ata_cmd(probe_ent, port, cfis, buffer, - ATA_SECT_SIZE * blkcnt, is_write) > 0) - return blkcnt; - else - return 0; -} - -u32 dwc_ahsata_rw_ncq_cmd(int dev, u32 start, lbaint_t blkcnt, - u8 *buffer, int is_write) -{ - struct ahci_probe_ent *probe_ent = - (struct ahci_probe_ent *)sata_dev_desc[dev].priv; - struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN); - struct sata_fis_h2d *cfis = &h2d; - u8 port = probe_ent->hard_port_no; - u64 block; - - if (sata_dev_desc[dev].lba48 != 1) { - printf("execute FPDMA command on non-LBA48 hard disk\n\r"); - return -1; - } - - block = (u64)start; - - memset(cfis, 0, sizeof(struct sata_fis_h2d)); - - cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; - cfis->pm_port_c = 0x80; /* is command */ - - cfis->command = (is_write) ? ATA_CMD_FPDMA_WRITE - : ATA_CMD_FPDMA_READ; - - cfis->lba_high_exp = (block >> 40) & 0xff; - cfis->lba_mid_exp = (block >> 32) & 0xff; - cfis->lba_low_exp = (block >> 24) & 0xff; - cfis->lba_high = (block >> 16) & 0xff; - cfis->lba_mid = (block >> 8) & 0xff; - cfis->lba_low = block & 0xff; - - cfis->device = ATA_LBA; - cfis->features_exp = (blkcnt >> 8) & 0xff; - cfis->features = blkcnt & 0xff; - - /* Use the latest queue */ - ahci_exec_ata_cmd(probe_ent, port, cfis, - buffer, ATA_SECT_SIZE * blkcnt, is_write); - - return blkcnt; -} - -void dwc_ahsata_flush_cache_ext(int dev) -{ - struct ahci_probe_ent *probe_ent = - (struct ahci_probe_ent *)sata_dev_desc[dev].priv; - struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN); - struct sata_fis_h2d *cfis = &h2d; - u8 port = probe_ent->hard_port_no; - - memset(cfis, 0, sizeof(struct sata_fis_h2d)); - - cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; - cfis->pm_port_c = 0x80; /* is command */ - cfis->command = ATA_CMD_FLUSH_EXT; - - ahci_exec_ata_cmd(probe_ent, port, cfis, NULL, 0, 0); -} - -static void dwc_ahsata_init_wcache(int dev, u16 *id) -{ - struct ahci_probe_ent *probe_ent = - (struct ahci_probe_ent *)sata_dev_desc[dev].priv; - - if (ata_id_has_wcache(id) && ata_id_wcache_enabled(id)) - probe_ent->flags |= SATA_FLAG_WCACHE; - if (ata_id_has_flush(id)) - probe_ent->flags |= SATA_FLAG_FLUSH; - if (ata_id_has_flush_ext(id)) - probe_ent->flags |= SATA_FLAG_FLUSH_EXT; -} - -u32 ata_low_level_rw_lba48(int dev, u32 blknr, lbaint_t blkcnt, - const void *buffer, int is_write) -{ - u32 start, blks; - u8 *addr; - int max_blks; - - start = blknr; - blks = blkcnt; - addr = (u8 *)buffer; - - max_blks = ATA_MAX_SECTORS_LBA48; - - do { - if (blks > max_blks) { - if (max_blks != dwc_ahsata_rw_cmd_ext(dev, start, - max_blks, addr, is_write)) - return 0; - start += max_blks; - blks -= max_blks; - addr += ATA_SECT_SIZE * max_blks; - } else { - if (blks != dwc_ahsata_rw_cmd_ext(dev, start, - blks, addr, is_write)) - return 0; - start += blks; - blks = 0; - addr += ATA_SECT_SIZE * blks; - } - } while (blks != 0); - - return blkcnt; -} - -u32 ata_low_level_rw_lba28(int dev, u32 blknr, lbaint_t blkcnt, - const void *buffer, int is_write) -{ - u32 start, blks; - u8 *addr; - int max_blks; - - start = blknr; - blks = blkcnt; - addr = (u8 *)buffer; - - max_blks = ATA_MAX_SECTORS; - do { - if (blks > max_blks) { - if (max_blks != dwc_ahsata_rw_cmd(dev, start, - max_blks, addr, is_write)) - return 0; - start += max_blks; - blks -= max_blks; - addr += ATA_SECT_SIZE * max_blks; - } else { - if (blks != dwc_ahsata_rw_cmd(dev, start, - blks, addr, is_write)) - return 0; - start += blks; - blks = 0; - addr += ATA_SECT_SIZE * blks; - } - } while (blks != 0); - - return blkcnt; -} - -int sata_port_status(int dev, int port) -{ - struct sata_port_regs *port_mmio; - struct ahci_probe_ent *probe_ent = NULL; - - if (dev < 0 || dev > (CONFIG_SYS_SATA_MAX_DEVICE - 1)) - return -EINVAL; - - if (sata_dev_desc[dev].priv == NULL) - return -ENODEV; - - probe_ent = (struct ahci_probe_ent *)sata_dev_desc[dev].priv; - port_mmio = (struct sata_port_regs *)probe_ent->port[port].port_mmio; - - return readl(&(port_mmio->ssts)) & SATA_PORT_SSTS_DET_MASK; -} - -/* - * SATA interface between low level driver and command layer - */ -ulong sata_read(int dev, ulong blknr, lbaint_t blkcnt, void *buffer) -{ - u32 rc; - - if (sata_dev_desc[dev].lba48) - rc = ata_low_level_rw_lba48(dev, blknr, blkcnt, - buffer, READ_CMD); - else - rc = ata_low_level_rw_lba28(dev, blknr, blkcnt, - buffer, READ_CMD); - return rc; -} - -ulong sata_write(int dev, ulong blknr, lbaint_t blkcnt, const void *buffer) -{ - u32 rc; - struct ahci_probe_ent *probe_ent = - (struct ahci_probe_ent *)sata_dev_desc[dev].priv; - u32 flags = probe_ent->flags; - - if (sata_dev_desc[dev].lba48) { - rc = ata_low_level_rw_lba48(dev, blknr, blkcnt, - buffer, WRITE_CMD); - if ((flags & SATA_FLAG_WCACHE) && - (flags & SATA_FLAG_FLUSH_EXT)) - dwc_ahsata_flush_cache_ext(dev); - } else { - rc = ata_low_level_rw_lba28(dev, blknr, blkcnt, - buffer, WRITE_CMD); - if ((flags & SATA_FLAG_WCACHE) && - (flags & SATA_FLAG_FLUSH)) - dwc_ahsata_flush_cache(dev); - } - return rc; -} - -int scan_sata(int dev) -{ - u8 serial[ATA_ID_SERNO_LEN + 1] = { 0 }; - u8 firmware[ATA_ID_FW_REV_LEN + 1] = { 0 }; - u8 product[ATA_ID_PROD_LEN + 1] = { 0 }; - u16 *id; - u64 n_sectors; - struct ahci_probe_ent *probe_ent = - (struct ahci_probe_ent *)sata_dev_desc[dev].priv; - u8 port = probe_ent->hard_port_no; - struct blk_desc *pdev = &(sata_dev_desc[dev]); - - id = (u16 *)memalign(ARCH_DMA_MINALIGN, - roundup(ARCH_DMA_MINALIGN, - (ATA_ID_WORDS * 2))); - if (!id) { - printf("id malloc failed\n\r"); - return -1; - } - - /* Identify device to get information */ - dwc_ahsata_identify(dev, id); - - /* Serial number */ - ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial)); - memcpy(pdev->product, serial, sizeof(serial)); - - /* Firmware version */ - ata_id_c_string(id, firmware, ATA_ID_FW_REV, sizeof(firmware)); - memcpy(pdev->revision, firmware, sizeof(firmware)); - - /* Product model */ - ata_id_c_string(id, product, ATA_ID_PROD, sizeof(product)); - memcpy(pdev->vendor, product, sizeof(product)); - - /* Totoal sectors */ - n_sectors = ata_id_n_sectors(id); - pdev->lba = (u32)n_sectors; - - pdev->type = DEV_TYPE_HARDDISK; - pdev->blksz = ATA_SECT_SIZE; - pdev->lun = 0 ; - - /* Check if support LBA48 */ - if (ata_id_has_lba48(id)) { - pdev->lba48 = 1; - debug("Device support LBA48\n\r"); - } - - /* Get the NCQ queue depth from device */ - probe_ent->flags &= (~SATA_FLAG_Q_DEP_MASK); - probe_ent->flags |= ata_id_queue_depth(id); - - /* Get the xfer mode from device */ - dwc_ahsata_xfer_mode(dev, id); - - /* Get the write cache status from device */ - dwc_ahsata_init_wcache(dev, id); - - /* Set the xfer mode to highest speed */ - ahci_set_feature(dev, port); - - free((void *)id); - - dwc_ahsata_print_info(dev); - - is_ready = 1; - - return 0; -} diff --git a/drivers/block/dwc_ahsata.h b/drivers/block/dwc_ahsata.h deleted file mode 100644 index caa2e50..0000000 --- a/drivers/block/dwc_ahsata.h +++ /dev/null @@ -1,320 +0,0 @@ -/* - * Copyright (C) 2010 Freescale Semiconductor, Inc. - * Terry Lv - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#ifndef __FSL_SATA_H__ -#define __FSL_SATA_H__ - -#define DWC_AHSATA_MAX_CMD_SLOTS 32 - -/* Max host controller numbers */ -#define SATA_HC_MAX_NUM 4 -/* Max command queue depth per host controller */ -#define DWC_AHSATA_HC_MAX_CMD 32 -/* Max port number per host controller */ -#define SATA_HC_MAX_PORT 16 - -/* Generic Host Register */ - -/* HBA Capabilities Register */ -#define SATA_HOST_CAP_S64A 0x80000000 -#define SATA_HOST_CAP_SNCQ 0x40000000 -#define SATA_HOST_CAP_SSNTF 0x20000000 -#define SATA_HOST_CAP_SMPS 0x10000000 -#define SATA_HOST_CAP_SSS 0x08000000 -#define SATA_HOST_CAP_SALP 0x04000000 -#define SATA_HOST_CAP_SAL 0x02000000 -#define SATA_HOST_CAP_SCLO 0x01000000 -#define SATA_HOST_CAP_ISS_MASK 0x00f00000 -#define SATA_HOST_CAP_ISS_OFFSET 20 -#define SATA_HOST_CAP_SNZO 0x00080000 -#define SATA_HOST_CAP_SAM 0x00040000 -#define SATA_HOST_CAP_SPM 0x00020000 -#define SATA_HOST_CAP_PMD 0x00008000 -#define SATA_HOST_CAP_SSC 0x00004000 -#define SATA_HOST_CAP_PSC 0x00002000 -#define SATA_HOST_CAP_NCS 0x00001f00 -#define SATA_HOST_CAP_CCCS 0x00000080 -#define SATA_HOST_CAP_EMS 0x00000040 -#define SATA_HOST_CAP_SXS 0x00000020 -#define SATA_HOST_CAP_NP_MASK 0x0000001f - -/* Global HBA Control Register */ -#define SATA_HOST_GHC_AE 0x80000000 -#define SATA_HOST_GHC_IE 0x00000002 -#define SATA_HOST_GHC_HR 0x00000001 - -/* Interrupt Status Register */ - -/* Ports Implemented Register */ - -/* AHCI Version Register */ -#define SATA_HOST_VS_MJR_MASK 0xffff0000 -#define SATA_HOST_VS_MJR_OFFSET 16 -#define SATA_HOST_VS_MJR_MNR 0x0000ffff - -/* Command Completion Coalescing Control */ -#define SATA_HOST_CCC_CTL_TV_MASK 0xffff0000 -#define SATA_HOST_CCC_CTL_TV_OFFSET 16 -#define SATA_HOST_CCC_CTL_CC_MASK 0x0000ff00 -#define SATA_HOST_CCC_CTL_CC_OFFSET 8 -#define SATA_HOST_CCC_CTL_INT_MASK 0x000000f8 -#define SATA_HOST_CCC_CTL_INT_OFFSET 3 -#define SATA_HOST_CCC_CTL_EN 0x00000001 - -/* Command Completion Coalescing Ports */ - -/* HBA Capabilities Extended Register */ -#define SATA_HOST_CAP2_APST 0x00000004 - -/* BIST Activate FIS Register */ -#define SATA_HOST_BISTAFR_NCP_MASK 0x0000ff00 -#define SATA_HOST_BISTAFR_NCP_OFFSET 8 -#define SATA_HOST_BISTAFR_PD_MASK 0x000000ff -#define SATA_HOST_BISTAFR_PD_OFFSET 0 - -/* BIST Control Register */ -#define SATA_HOST_BISTCR_FERLB 0x00100000 -#define SATA_HOST_BISTCR_TXO 0x00040000 -#define SATA_HOST_BISTCR_CNTCLR 0x00020000 -#define SATA_HOST_BISTCR_NEALB 0x00010000 -#define SATA_HOST_BISTCR_LLC_MASK 0x00000700 -#define SATA_HOST_BISTCR_LLC_OFFSET 8 -#define SATA_HOST_BISTCR_ERREN 0x00000040 -#define SATA_HOST_BISTCR_FLIP 0x00000020 -#define SATA_HOST_BISTCR_PV 0x00000010 -#define SATA_HOST_BISTCR_PATTERN_MASK 0x0000000f -#define SATA_HOST_BISTCR_PATTERN_OFFSET 0 - -/* BIST FIS Count Register */ - -/* BIST Status Register */ -#define SATA_HOST_BISTSR_FRAMERR_MASK 0x0000ffff -#define SATA_HOST_BISTSR_FRAMERR_OFFSET 0 -#define SATA_HOST_BISTSR_BRSTERR_MASK 0x00ff0000 -#define SATA_HOST_BISTSR_BRSTERR_OFFSET 16 - -/* BIST DWORD Error Count Register */ - -/* OOB Register*/ -#define SATA_HOST_OOBR_WE 0x80000000 -#define SATA_HOST_OOBR_cwMin_MASK 0x7f000000 -#define SATA_HOST_OOBR_cwMAX_MASK 0x00ff0000 -#define SATA_HOST_OOBR_ciMin_MASK 0x0000ff00 -#define SATA_HOST_OOBR_ciMax_MASK 0x000000ff - -/* Timer 1-ms Register */ - -/* Global Parameter 1 Register */ -#define SATA_HOST_GPARAM1R_ALIGN_M 0x80000000 -#define SATA_HOST_GPARAM1R_RX_BUFFER 0x40000000 -#define SATA_HOST_GPARAM1R_PHY_DATA_MASK 0x30000000 -#define SATA_HOST_GPARAM1R_PHY_RST 0x08000000 -#define SATA_HOST_GPARAM1R_PHY_CTRL_MASK 0x07e00000 -#define SATA_HOST_GPARAM1R_PHY_STAT_MASK 0x001f8000 -#define SATA_HOST_GPARAM1R_LATCH_M 0x00004000 -#define SATA_HOST_GPARAM1R_BIST_M 0x00002000 -#define SATA_HOST_GPARAM1R_PHY_TYPE 0x00001000 -#define SATA_HOST_GPARAM1R_RETURN_ERR 0x00000400 -#define SATA_HOST_GPARAM1R_AHB_ENDIAN_MASK 0x00000300 -#define SATA_HOST_GPARAM1R_S_HADDR 0X00000080 -#define SATA_HOST_GPARAM1R_M_HADDR 0X00000040 - -/* Global Parameter 2 Register */ -#define SATA_HOST_GPARAM2R_DEV_CP 0x00004000 -#define SATA_HOST_GPARAM2R_DEV_MP 0x00002000 -#define SATA_HOST_GPARAM2R_DEV_ENCODE_M 0x00001000 -#define SATA_HOST_GPARAM2R_RXOOB_CLK_M 0x00000800 -#define SATA_HOST_GPARAM2R_RXOOB_M 0x00000400 -#define SATA_HOST_GPARAM2R_TX_OOB_M 0x00000200 -#define SATA_HOST_GPARAM2R_RXOOB_CLK_MASK 0x000001ff - -/* Port Parameter Register */ -#define SATA_HOST_PPARAMR_TX_MEM_M 0x00000200 -#define SATA_HOST_PPARAMR_TX_MEM_S 0x00000100 -#define SATA_HOST_PPARAMR_RX_MEM_M 0x00000080 -#define SATA_HOST_PPARAMR_RX_MEM_S 0x00000040 -#define SATA_HOST_PPARAMR_TXFIFO_DEPTH_MASK 0x00000038 -#define SATA_HOST_PPARAMR_RXFIFO_DEPTH_MASK 0x00000007 - -/* Test Register */ -#define SATA_HOST_TESTR_PSEL_MASK 0x00070000 -#define SATA_HOST_TESTR_TEST_IF 0x00000001 - -/* Port Register Descriptions */ -/* Port# Command List Base Address Register */ -#define SATA_PORT_CLB_CLB_MASK 0xfffffc00 - -/* Port# Command List Base Address Upper 32-Bits Register */ - -/* Port# FIS Base Address Register */ -#define SATA_PORT_FB_FB_MASK 0xfffffff0 - -/* Port# FIS Base Address Upper 32-Bits Register */ - -/* Port# Interrupt Status Register */ -#define SATA_PORT_IS_CPDS 0x80000000 -#define SATA_PORT_IS_TFES 0x40000000 -#define SATA_PORT_IS_HBFS 0x20000000 -#define SATA_PORT_IS_HBDS 0x10000000 -#define SATA_PORT_IS_IFS 0x08000000 -#define SATA_PORT_IS_INFS 0x04000000 -#define SATA_PORT_IS_OFS 0x01000000 -#define SATA_PORT_IS_IPMS 0x00800000 -#define SATA_PORT_IS_PRCS 0x00400000 -#define SATA_PORT_IS_DMPS 0x00000080 -#define SATA_PORT_IS_PCS 0x00000040 -#define SATA_PORT_IS_DPS 0x00000020 -#define SATA_PORT_IS_UFS 0x00000010 -#define SATA_PORT_IS_SDBS 0x00000008 -#define SATA_PORT_IS_DSS 0x00000004 -#define SATA_PORT_IS_PSS 0x00000002 -#define SATA_PORT_IS_DHRS 0x00000001 - -/* Port# Interrupt Enable Register */ -#define SATA_PORT_IE_CPDE 0x80000000 -#define SATA_PORT_IE_TFEE 0x40000000 -#define SATA_PORT_IE_HBFE 0x20000000 -#define SATA_PORT_IE_HBDE 0x10000000 -#define SATA_PORT_IE_IFE 0x08000000 -#define SATA_PORT_IE_INFE 0x04000000 -#define SATA_PORT_IE_OFE 0x01000000 -#define SATA_PORT_IE_IPME 0x00800000 -#define SATA_PORT_IE_PRCE 0x00400000 -#define SATA_PORT_IE_DMPE 0x00000080 -#define SATA_PORT_IE_PCE 0x00000040 -#define SATA_PORT_IE_DPE 0x00000020 -#define SATA_PORT_IE_UFE 0x00000010 -#define SATA_PORT_IE_SDBE 0x00000008 -#define SATA_PORT_IE_DSE 0x00000004 -#define SATA_PORT_IE_PSE 0x00000002 -#define SATA_PORT_IE_DHRE 0x00000001 - -/* Port# Command Register */ -#define SATA_PORT_CMD_ICC_MASK 0xf0000000 -#define SATA_PORT_CMD_ASP 0x08000000 -#define SATA_PORT_CMD_ALPE 0x04000000 -#define SATA_PORT_CMD_DLAE 0x02000000 -#define SATA_PORT_CMD_ATAPI 0x01000000 -#define SATA_PORT_CMD_APSTE 0x00800000 -#define SATA_PORT_CMD_ESP 0x00200000 -#define SATA_PORT_CMD_CPD 0x00100000 -#define SATA_PORT_CMD_MPSP 0x00080000 -#define SATA_PORT_CMD_HPCP 0x00040000 -#define SATA_PORT_CMD_PMA 0x00020000 -#define SATA_PORT_CMD_CPS 0x00010000 -#define SATA_PORT_CMD_CR 0x00008000 -#define SATA_PORT_CMD_FR 0x00004000 -#define SATA_PORT_CMD_MPSS 0x00002000 -#define SATA_PORT_CMD_CCS_MASK 0x00001f00 -#define SATA_PORT_CMD_FRE 0x00000010 -#define SATA_PORT_CMD_CLO 0x00000008 -#define SATA_PORT_CMD_POD 0x00000004 -#define SATA_PORT_CMD_SUD 0x00000002 -#define SATA_PORT_CMD_ST 0x00000001 - -/* Port# Task File Data Register */ -#define SATA_PORT_TFD_ERR_MASK 0x0000ff00 -#define SATA_PORT_TFD_STS_MASK 0x000000ff -#define SATA_PORT_TFD_STS_ERR 0x00000001 -#define SATA_PORT_TFD_STS_DRQ 0x00000008 -#define SATA_PORT_TFD_STS_BSY 0x00000080 - -/* Port# Signature Register */ - -/* Port# Serial ATA Status {SStatus} Register */ -#define SATA_PORT_SSTS_IPM_MASK 0x00000f00 -#define SATA_PORT_SSTS_SPD_MASK 0x000000f0 -#define SATA_PORT_SSTS_DET_MASK 0x0000000f - -/* Port# Serial ATA Control {SControl} Register */ -#define SATA_PORT_SCTL_IPM_MASK 0x00000f00 -#define SATA_PORT_SCTL_SPD_MASK 0x000000f0 -#define SATA_PORT_SCTL_DET_MASK 0x0000000f - -/* Port# Serial ATA Error {SError} Register */ -#define SATA_PORT_SERR_DIAG_X 0x04000000 -#define SATA_PORT_SERR_DIAG_F 0x02000000 -#define SATA_PORT_SERR_DIAG_T 0x01000000 -#define SATA_PORT_SERR_DIAG_S 0x00800000 -#define SATA_PORT_SERR_DIAG_H 0x00400000 -#define SATA_PORT_SERR_DIAG_C 0x00200000 -#define SATA_PORT_SERR_DIAG_D 0x00100000 -#define SATA_PORT_SERR_DIAG_B 0x00080000 -#define SATA_PORT_SERR_DIAG_W 0x00040000 -#define SATA_PORT_SERR_DIAG_I 0x00020000 -#define SATA_PORT_SERR_DIAG_N 0x00010000 -#define SATA_PORT_SERR_ERR_E 0x00000800 -#define SATA_PORT_SERR_ERR_P 0x00000400 -#define SATA_PORT_SERR_ERR_C 0x00000200 -#define SATA_PORT_SERR_ERR_T 0x00000100 -#define SATA_PORT_SERR_ERR_M 0x00000002 -#define SATA_PORT_SERR_ERR_I 0x00000001 - -/* Port# Serial ATA Active {SActive} Register */ - -/* Port# Command Issue Register */ - -/* Port# Serial ATA Notification Register */ - -/* Port# DMA Control Register */ -#define SATA_PORT_DMACR_RXABL_MASK 0x0000f000 -#define SATA_PORT_DMACR_TXABL_MASK 0x00000f00 -#define SATA_PORT_DMACR_RXTS_MASK 0x000000f0 -#define SATA_PORT_DMACR_TXTS_MASK 0x0000000f - -/* Port# PHY Control Register */ - -/* Port# PHY Status Register */ - -#define SATA_HC_CMD_HDR_ENTRY_SIZE sizeof(struct cmd_hdr_entry) - -/* DW0 -*/ -#define CMD_HDR_DI_CFL_MASK 0x0000001f -#define CMD_HDR_DI_CFL_OFFSET 0 -#define CMD_HDR_DI_A 0x00000020 -#define CMD_HDR_DI_W 0x00000040 -#define CMD_HDR_DI_P 0x00000080 -#define CMD_HDR_DI_R 0x00000100 -#define CMD_HDR_DI_B 0x00000200 -#define CMD_HDR_DI_C 0x00000400 -#define CMD_HDR_DI_PMP_MASK 0x0000f000 -#define CMD_HDR_DI_PMP_OFFSET 12 -#define CMD_HDR_DI_PRDTL 0xffff0000 -#define CMD_HDR_DI_PRDTL_OFFSET 16 - -/* prde_fis_len -*/ -#define CMD_HDR_PRD_ENTRY_SHIFT 16 -#define CMD_HDR_PRD_ENTRY_MASK 0x003f0000 -#define CMD_HDR_FIS_LEN_SHIFT 2 - -/* attribute -*/ -#define CMD_HDR_ATTR_RES 0x00000800 /* Reserved bit, should be 1 */ -#define CMD_HDR_ATTR_VBIST 0x00000400 /* Vendor BIST */ -/* Snoop enable for all descriptor */ -#define CMD_HDR_ATTR_SNOOP 0x00000200 -#define CMD_HDR_ATTR_FPDMA 0x00000100 /* FPDMA queued command */ -#define CMD_HDR_ATTR_RESET 0x00000080 /* Reset - a SRST or device reset */ -/* BIST - require the host to enter BIST mode */ -#define CMD_HDR_ATTR_BIST 0x00000040 -#define CMD_HDR_ATTR_ATAPI 0x00000020 /* ATAPI command */ -#define CMD_HDR_ATTR_TAG 0x0000001f /* TAG mask */ - -#define FLAGS_DMA 0x00000000 -#define FLAGS_FPDMA 0x00000001 - -#define SATA_FLAG_Q_DEP_MASK 0x0000000f -#define SATA_FLAG_WCACHE 0x00000100 -#define SATA_FLAG_FLUSH 0x00000200 -#define SATA_FLAG_FLUSH_EXT 0x00000400 - -#define READ_CMD 0 -#define WRITE_CMD 1 - -#endif /* __FSL_SATA_H__ */ diff --git a/drivers/block/fsl_sata.c b/drivers/block/fsl_sata.c deleted file mode 100644 index 31f7fab..0000000 --- a/drivers/block/fsl_sata.c +++ /dev/null @@ -1,854 +0,0 @@ -/* - * Copyright (C) 2008,2010 Freescale Semiconductor, Inc. - * Dave Liu - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "fsl_sata.h" - -#ifndef CONFIG_SYS_SATA1_FLAGS - #define CONFIG_SYS_SATA1_FLAGS FLAGS_DMA -#endif -#ifndef CONFIG_SYS_SATA2_FLAGS - #define CONFIG_SYS_SATA2_FLAGS FLAGS_DMA -#endif - -static struct fsl_sata_info fsl_sata_info[] = { -#ifdef CONFIG_SATA1 - {CONFIG_SYS_SATA1, CONFIG_SYS_SATA1_FLAGS}, -#else - {0, 0}, -#endif -#ifdef CONFIG_SATA2 - {CONFIG_SYS_SATA2, CONFIG_SYS_SATA2_FLAGS}, -#else - {0, 0}, -#endif -}; - -static inline void sdelay(unsigned long sec) -{ - unsigned long i; - for (i = 0; i < sec; i++) - mdelay(1000); -} - -static void fsl_sata_dump_sfis(struct sata_fis_d2h *s) -{ - printf("Status FIS dump:\n\r"); - printf("fis_type: %02x\n\r", s->fis_type); - printf("pm_port_i: %02x\n\r", s->pm_port_i); - printf("status: %02x\n\r", s->status); - printf("error: %02x\n\r", s->error); - printf("lba_low: %02x\n\r", s->lba_low); - printf("lba_mid: %02x\n\r", s->lba_mid); - printf("lba_high: %02x\n\r", s->lba_high); - printf("device: %02x\n\r", s->device); - printf("lba_low_exp: %02x\n\r", s->lba_low_exp); - printf("lba_mid_exp: %02x\n\r", s->lba_mid_exp); - printf("lba_high_exp: %02x\n\r", s->lba_high_exp); - printf("res1: %02x\n\r", s->res1); - printf("sector_count: %02x\n\r", s->sector_count); - printf("sector_count_exp: %02x\n\r", s->sector_count_exp); -} - -static int ata_wait_register(unsigned __iomem *addr, u32 mask, - u32 val, u32 timeout_msec) -{ - int i; - u32 temp; - - for (i = 0; (((temp = in_le32(addr)) & mask) != val) - && i < timeout_msec; i++) - mdelay(1); - return (i < timeout_msec) ? 0 : -1; -} - -int init_sata(int dev) -{ - u32 length, align; - cmd_hdr_tbl_t *cmd_hdr; - u32 cda; - u32 val32; - fsl_sata_reg_t __iomem *reg; - u32 sig; - int i; - fsl_sata_t *sata; - - if (dev < 0 || dev > (CONFIG_SYS_SATA_MAX_DEVICE - 1)) { - printf("the sata index %d is out of ranges\n\r", dev); - return -1; - } - -#ifdef CONFIG_MPC85xx - if ((dev == 0) && (!is_serdes_configured(SATA1))) { - printf("SATA%d [dev = %d] is not enabled\n", dev+1, dev); - return -1; - } - if ((dev == 1) && (!is_serdes_configured(SATA2))) { - printf("SATA%d [dev = %d] is not enabled\n", dev+1, dev); - return -1; - } -#endif - - /* Allocate SATA device driver struct */ - sata = (fsl_sata_t *)malloc(sizeof(fsl_sata_t)); - if (!sata) { - printf("alloc the sata device struct failed\n\r"); - return -1; - } - /* Zero all of the device driver struct */ - memset((void *)sata, 0, sizeof(fsl_sata_t)); - - /* Save the private struct to block device struct */ - sata_dev_desc[dev].priv = (void *)sata; - - snprintf(sata->name, 12, "SATA%d", dev); - - /* Set the controller register base address to device struct */ - reg = (fsl_sata_reg_t *)(fsl_sata_info[dev].sata_reg_base); - sata->reg_base = reg; - - /* Allocate the command header table, 4 bytes aligned */ - length = sizeof(struct cmd_hdr_tbl); - align = SATA_HC_CMD_HDR_TBL_ALIGN; - sata->cmd_hdr_tbl_offset = (void *)malloc(length + align); - if (!sata->cmd_hdr_tbl_offset) { - printf("alloc the command header failed\n\r"); - return -1; - } - - cmd_hdr = (cmd_hdr_tbl_t *)(((u32)sata->cmd_hdr_tbl_offset + align) - & ~(align - 1)); - sata->cmd_hdr = cmd_hdr; - - /* Zero all of the command header table */ - memset((void *)sata->cmd_hdr_tbl_offset, 0, length + align); - - /* Allocate command descriptor for all command */ - length = sizeof(struct cmd_desc) * SATA_HC_MAX_CMD; - align = SATA_HC_CMD_DESC_ALIGN; - sata->cmd_desc_offset = (void *)malloc(length + align); - if (!sata->cmd_desc_offset) { - printf("alloc the command descriptor failed\n\r"); - return -1; - } - sata->cmd_desc = (cmd_desc_t *)(((u32)sata->cmd_desc_offset + align) - & ~(align - 1)); - /* Zero all of command descriptor */ - memset((void *)sata->cmd_desc_offset, 0, length + align); - - /* Link the command descriptor to command header */ - for (i = 0; i < SATA_HC_MAX_CMD; i++) { - cda = ((u32)sata->cmd_desc + SATA_HC_CMD_DESC_SIZE * i) - & ~(CMD_HDR_CDA_ALIGN - 1); - cmd_hdr->cmd_slot[i].cda = cpu_to_le32(cda); - } - - /* To have safe state, force the controller offline */ - val32 = in_le32(®->hcontrol); - val32 &= ~HCONTROL_ONOFF; - val32 |= HCONTROL_FORCE_OFFLINE; - out_le32(®->hcontrol, val32); - - /* Wait the controller offline */ - ata_wait_register(®->hstatus, HSTATUS_ONOFF, 0, 1000); - - /* Set the command header base address to CHBA register to tell DMA */ - out_le32(®->chba, (u32)cmd_hdr & ~0x3); - - /* Snoop for the command header */ - val32 = in_le32(®->hcontrol); - val32 |= HCONTROL_HDR_SNOOP; - out_le32(®->hcontrol, val32); - - /* Disable all of interrupts */ - val32 = in_le32(®->hcontrol); - val32 &= ~HCONTROL_INT_EN_ALL; - out_le32(®->hcontrol, val32); - - /* Clear all of interrupts */ - val32 = in_le32(®->hstatus); - out_le32(®->hstatus, val32); - - /* Set the ICC, no interrupt coalescing */ - out_le32(®->icc, 0x01000000); - - /* No PM attatched, the SATA device direct connect */ - out_le32(®->cqpmp, 0); - - /* Clear SError register */ - val32 = in_le32(®->serror); - out_le32(®->serror, val32); - - /* Clear CER register */ - val32 = in_le32(®->cer); - out_le32(®->cer, val32); - - /* Clear DER register */ - val32 = in_le32(®->der); - out_le32(®->der, val32); - - /* No device detection or initialization action requested */ - out_le32(®->scontrol, 0x00000300); - - /* Configure the transport layer, default value */ - out_le32(®->transcfg, 0x08000016); - - /* Configure the link layer, default value */ - out_le32(®->linkcfg, 0x0000ff34); - - /* Bring the controller online */ - val32 = in_le32(®->hcontrol); - val32 |= HCONTROL_ONOFF; - out_le32(®->hcontrol, val32); - - mdelay(100); - - /* print sata device name */ - if (!dev) - printf("%s ", sata->name); - else - printf(" %s ", sata->name); - - /* Wait PHY RDY signal changed for 500ms */ - ata_wait_register(®->hstatus, HSTATUS_PHY_RDY, - HSTATUS_PHY_RDY, 500); - - /* Check PHYRDY */ - val32 = in_le32(®->hstatus); - if (val32 & HSTATUS_PHY_RDY) { - sata->link = 1; - } else { - sata->link = 0; - printf("(No RDY)\n\r"); - return -1; - } - - /* Wait for signature updated, which is 1st D2H */ - ata_wait_register(®->hstatus, HSTATUS_SIGNATURE, - HSTATUS_SIGNATURE, 10000); - - if (val32 & HSTATUS_SIGNATURE) { - sig = in_le32(®->sig); - debug("Signature updated, the sig =%08x\n\r", sig); - sata->ata_device_type = ata_dev_classify(sig); - } - - /* Check the speed */ - val32 = in_le32(®->sstatus); - if ((val32 & SSTATUS_SPD_MASK) == SSTATUS_SPD_GEN1) - printf("(1.5 Gbps)\n\r"); - else if ((val32 & SSTATUS_SPD_MASK) == SSTATUS_SPD_GEN2) - printf("(3 Gbps)\n\r"); - - return 0; -} - -int reset_sata(int dev) -{ - return 0; -} - -static void fsl_sata_dump_regs(fsl_sata_reg_t __iomem *reg) -{ - printf("\n\rSATA: %08x\n\r", (u32)reg); - printf("CQR: %08x\n\r", in_le32(®->cqr)); - printf("CAR: %08x\n\r", in_le32(®->car)); - printf("CCR: %08x\n\r", in_le32(®->ccr)); - printf("CER: %08x\n\r", in_le32(®->cer)); - printf("CQR: %08x\n\r", in_le32(®->cqr)); - printf("DER: %08x\n\r", in_le32(®->der)); - printf("CHBA: %08x\n\r", in_le32(®->chba)); - printf("HStatus: %08x\n\r", in_le32(®->hstatus)); - printf("HControl: %08x\n\r", in_le32(®->hcontrol)); - printf("CQPMP: %08x\n\r", in_le32(®->cqpmp)); - printf("SIG: %08x\n\r", in_le32(®->sig)); - printf("ICC: %08x\n\r", in_le32(®->icc)); - printf("SStatus: %08x\n\r", in_le32(®->sstatus)); - printf("SError: %08x\n\r", in_le32(®->serror)); - printf("SControl: %08x\n\r", in_le32(®->scontrol)); - printf("SNotification: %08x\n\r", in_le32(®->snotification)); - printf("TransCfg: %08x\n\r", in_le32(®->transcfg)); - printf("TransStatus: %08x\n\r", in_le32(®->transstatus)); - printf("LinkCfg: %08x\n\r", in_le32(®->linkcfg)); - printf("LinkCfg1: %08x\n\r", in_le32(®->linkcfg1)); - printf("LinkCfg2: %08x\n\r", in_le32(®->linkcfg2)); - printf("LinkStatus: %08x\n\r", in_le32(®->linkstatus)); - printf("LinkStatus1: %08x\n\r", in_le32(®->linkstatus1)); - printf("PhyCtrlCfg: %08x\n\r", in_le32(®->phyctrlcfg)); - printf("SYSPR: %08x\n\r", in_be32(®->syspr)); -} - -static int fsl_ata_exec_ata_cmd(struct fsl_sata *sata, struct sata_fis_h2d *cfis, - int is_ncq, int tag, u8 *buffer, u32 len) -{ - cmd_hdr_entry_t *cmd_hdr; - cmd_desc_t *cmd_desc; - sata_fis_h2d_t *h2d; - prd_entry_t *prde; - u32 ext_c_ddc; - u32 prde_count; - u32 val32; - u32 ttl; - fsl_sata_reg_t __iomem *reg = sata->reg_base; - int i; - - /* Check xfer length */ - if (len > SATA_HC_MAX_XFER_LEN) { - printf("max transfer length is 64MB\n\r"); - return 0; - } - - /* Setup the command descriptor */ - cmd_desc = sata->cmd_desc + tag; - - /* Get the pointer cfis of command descriptor */ - h2d = (sata_fis_h2d_t *)cmd_desc->cfis; - - /* Zero the cfis of command descriptor */ - memset((void *)h2d, 0, SATA_HC_CMD_DESC_CFIS_SIZE); - - /* Copy the cfis from user to command descriptor */ - h2d->fis_type = cfis->fis_type; - h2d->pm_port_c = cfis->pm_port_c; - h2d->command = cfis->command; - - h2d->features = cfis->features; - h2d->features_exp = cfis->features_exp; - - h2d->lba_low = cfis->lba_low; - h2d->lba_mid = cfis->lba_mid; - h2d->lba_high = cfis->lba_high; - h2d->lba_low_exp = cfis->lba_low_exp; - h2d->lba_mid_exp = cfis->lba_mid_exp; - h2d->lba_high_exp = cfis->lba_high_exp; - - if (!is_ncq) { - h2d->sector_count = cfis->sector_count; - h2d->sector_count_exp = cfis->sector_count_exp; - } else { /* NCQ */ - h2d->sector_count = (u8)(tag << 3); - } - - h2d->device = cfis->device; - h2d->control = cfis->control; - - /* Setup the PRD table */ - prde = (prd_entry_t *)cmd_desc->prdt; - memset((void *)prde, 0, sizeof(struct prdt)); - - prde_count = 0; - ttl = len; - for (i = 0; i < SATA_HC_MAX_PRD_DIRECT; i++) { - if (!len) - break; - prde->dba = cpu_to_le32((u32)buffer & ~0x3); - debug("dba = %08x\n\r", (u32)buffer); - - if (len < PRD_ENTRY_MAX_XFER_SZ) { - ext_c_ddc = PRD_ENTRY_DATA_SNOOP | len; - debug("ext_c_ddc1 = %08x, len = %08x\n\r", ext_c_ddc, len); - prde->ext_c_ddc = cpu_to_le32(ext_c_ddc); - prde_count++; - prde++; - break; - } else { - ext_c_ddc = PRD_ENTRY_DATA_SNOOP; /* 4M bytes */ - debug("ext_c_ddc2 = %08x, len = %08x\n\r", ext_c_ddc, len); - prde->ext_c_ddc = cpu_to_le32(ext_c_ddc); - buffer += PRD_ENTRY_MAX_XFER_SZ; - len -= PRD_ENTRY_MAX_XFER_SZ; - prde_count++; - prde++; - } - } - - /* Setup the command slot of cmd hdr */ - cmd_hdr = (cmd_hdr_entry_t *)&sata->cmd_hdr->cmd_slot[tag]; - - cmd_hdr->cda = cpu_to_le32((u32)cmd_desc & ~0x3); - - val32 = prde_count << CMD_HDR_PRD_ENTRY_SHIFT; - val32 |= sizeof(sata_fis_h2d_t); - cmd_hdr->prde_fis_len = cpu_to_le32(val32); - - cmd_hdr->ttl = cpu_to_le32(ttl); - - if (!is_ncq) { - val32 = CMD_HDR_ATTR_RES | CMD_HDR_ATTR_SNOOP; - } else { - val32 = CMD_HDR_ATTR_RES | CMD_HDR_ATTR_SNOOP | CMD_HDR_ATTR_FPDMA; - } - - tag &= CMD_HDR_ATTR_TAG; - val32 |= tag; - - debug("attribute = %08x\n\r", val32); - cmd_hdr->attribute = cpu_to_le32(val32); - - /* Make sure cmd desc and cmd slot valid before command issue */ - sync(); - - /* PMP*/ - val32 = (u32)(h2d->pm_port_c & 0x0f); - out_le32(®->cqpmp, val32); - - /* Wait no active */ - if (ata_wait_register(®->car, (1 << tag), 0, 10000)) - printf("Wait no active time out\n\r"); - - /* Issue command */ - if (!(in_le32(®->cqr) & (1 << tag))) { - val32 = 1 << tag; - out_le32(®->cqr, val32); - } - - /* Wait command completed for 10s */ - if (ata_wait_register(®->ccr, (1 << tag), (1 << tag), 10000)) { - if (!is_ncq) - printf("Non-NCQ command time out\n\r"); - else - printf("NCQ command time out\n\r"); - } - - val32 = in_le32(®->cer); - - if (val32) { - u32 der; - fsl_sata_dump_sfis((struct sata_fis_d2h *)cmd_desc->sfis); - printf("CE at device\n\r"); - fsl_sata_dump_regs(reg); - der = in_le32(®->der); - out_le32(®->cer, val32); - out_le32(®->der, der); - } - - /* Clear complete flags */ - val32 = in_le32(®->ccr); - out_le32(®->ccr, val32); - - return len; -} - -static int fsl_ata_exec_reset_cmd(struct fsl_sata *sata, struct sata_fis_h2d *cfis, - int tag, u8 *buffer, u32 len) -{ - return 0; -} - -static int fsl_sata_exec_cmd(struct fsl_sata *sata, struct sata_fis_h2d *cfis, - enum cmd_type command_type, int tag, u8 *buffer, u32 len) -{ - int rc; - - if (tag > SATA_HC_MAX_CMD || tag < 0) { - printf("tag is out of range, tag=%d\n\r", tag); - return -1; - } - - switch (command_type) { - case CMD_ATA: - rc = fsl_ata_exec_ata_cmd(sata, cfis, 0, tag, buffer, len); - return rc; - case CMD_RESET: - rc = fsl_ata_exec_reset_cmd(sata, cfis, tag, buffer, len); - return rc; - case CMD_NCQ: - rc = fsl_ata_exec_ata_cmd(sata, cfis, 1, tag, buffer, len); - return rc; - case CMD_ATAPI: - case CMD_VENDOR_BIST: - case CMD_BIST: - printf("not support now\n\r"); - return -1; - default: - break; - } - - return -1; -} - -static void fsl_sata_identify(int dev, u16 *id) -{ - fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - struct sata_fis_h2d h2d, *cfis = &h2d; - - memset(cfis, 0, sizeof(struct sata_fis_h2d)); - - cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; - cfis->pm_port_c = 0x80; /* is command */ - cfis->command = ATA_CMD_ID_ATA; - - fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, (u8 *)id, ATA_ID_WORDS * 2); - ata_swap_buf_le16(id, ATA_ID_WORDS); -} - -static void fsl_sata_xfer_mode(int dev, u16 *id) -{ - fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - - sata->pio = id[ATA_ID_PIO_MODES]; - sata->mwdma = id[ATA_ID_MWDMA_MODES]; - sata->udma = id[ATA_ID_UDMA_MODES]; - debug("pio %04x, mwdma %04x, udma %04x\n\r", sata->pio, sata->mwdma, sata->udma); -} - -static void fsl_sata_set_features(int dev) -{ - fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - struct sata_fis_h2d h2d, *cfis = &h2d; - u8 udma_cap; - - memset(cfis, 0, sizeof(struct sata_fis_h2d)); - - cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; - cfis->pm_port_c = 0x80; /* is command */ - cfis->command = ATA_CMD_SET_FEATURES; - cfis->features = SETFEATURES_XFER; - - /* First check the device capablity */ - udma_cap = (u8)(sata->udma & 0xff); - debug("udma_cap %02x\n\r", udma_cap); - - if (udma_cap == ATA_UDMA6) - cfis->sector_count = XFER_UDMA_6; - if (udma_cap == ATA_UDMA5) - cfis->sector_count = XFER_UDMA_5; - if (udma_cap == ATA_UDMA4) - cfis->sector_count = XFER_UDMA_4; - if (udma_cap == ATA_UDMA3) - cfis->sector_count = XFER_UDMA_3; - - fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, NULL, 0); -} - -static u32 fsl_sata_rw_cmd(int dev, u32 start, u32 blkcnt, u8 *buffer, int is_write) -{ - fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - struct sata_fis_h2d h2d, *cfis = &h2d; - u32 block; - - block = start; - - memset(cfis, 0, sizeof(struct sata_fis_h2d)); - - cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; - cfis->pm_port_c = 0x80; /* is command */ - cfis->command = (is_write) ? ATA_CMD_WRITE : ATA_CMD_READ; - cfis->device = ATA_LBA; - - cfis->device |= (block >> 24) & 0xf; - cfis->lba_high = (block >> 16) & 0xff; - cfis->lba_mid = (block >> 8) & 0xff; - cfis->lba_low = block & 0xff; - cfis->sector_count = (u8)(blkcnt & 0xff); - - fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, buffer, ATA_SECT_SIZE * blkcnt); - return blkcnt; -} - -static void fsl_sata_flush_cache(int dev) -{ - fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - struct sata_fis_h2d h2d, *cfis = &h2d; - - memset(cfis, 0, sizeof(struct sata_fis_h2d)); - - cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; - cfis->pm_port_c = 0x80; /* is command */ - cfis->command = ATA_CMD_FLUSH; - - fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, NULL, 0); -} - -static u32 fsl_sata_rw_cmd_ext(int dev, u32 start, u32 blkcnt, u8 *buffer, int is_write) -{ - fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - struct sata_fis_h2d h2d, *cfis = &h2d; - u64 block; - - block = (u64)start; - - memset(cfis, 0, sizeof(struct sata_fis_h2d)); - - cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; - cfis->pm_port_c = 0x80; /* is command */ - - cfis->command = (is_write) ? ATA_CMD_WRITE_EXT - : ATA_CMD_READ_EXT; - - cfis->lba_high_exp = (block >> 40) & 0xff; - cfis->lba_mid_exp = (block >> 32) & 0xff; - cfis->lba_low_exp = (block >> 24) & 0xff; - cfis->lba_high = (block >> 16) & 0xff; - cfis->lba_mid = (block >> 8) & 0xff; - cfis->lba_low = block & 0xff; - cfis->device = ATA_LBA; - cfis->sector_count_exp = (blkcnt >> 8) & 0xff; - cfis->sector_count = blkcnt & 0xff; - - fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, buffer, ATA_SECT_SIZE * blkcnt); - return blkcnt; -} - -static u32 fsl_sata_rw_ncq_cmd(int dev, u32 start, u32 blkcnt, u8 *buffer, - int is_write) -{ - fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - struct sata_fis_h2d h2d, *cfis = &h2d; - int ncq_channel; - u64 block; - - if (sata->lba48 != 1) { - printf("execute FPDMA command on non-LBA48 hard disk\n\r"); - return -1; - } - - block = (u64)start; - - memset(cfis, 0, sizeof(struct sata_fis_h2d)); - - cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; - cfis->pm_port_c = 0x80; /* is command */ - - cfis->command = (is_write) ? ATA_CMD_FPDMA_WRITE - : ATA_CMD_FPDMA_READ; - - cfis->lba_high_exp = (block >> 40) & 0xff; - cfis->lba_mid_exp = (block >> 32) & 0xff; - cfis->lba_low_exp = (block >> 24) & 0xff; - cfis->lba_high = (block >> 16) & 0xff; - cfis->lba_mid = (block >> 8) & 0xff; - cfis->lba_low = block & 0xff; - - cfis->device = ATA_LBA; - cfis->features_exp = (blkcnt >> 8) & 0xff; - cfis->features = blkcnt & 0xff; - - if (sata->queue_depth >= SATA_HC_MAX_CMD) - ncq_channel = SATA_HC_MAX_CMD - 1; - else - ncq_channel = sata->queue_depth - 1; - - /* Use the latest queue */ - fsl_sata_exec_cmd(sata, cfis, CMD_NCQ, ncq_channel, buffer, ATA_SECT_SIZE * blkcnt); - return blkcnt; -} - -static void fsl_sata_flush_cache_ext(int dev) -{ - fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - struct sata_fis_h2d h2d, *cfis = &h2d; - - memset(cfis, 0, sizeof(struct sata_fis_h2d)); - - cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; - cfis->pm_port_c = 0x80; /* is command */ - cfis->command = ATA_CMD_FLUSH_EXT; - - fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, NULL, 0); -} - -static void fsl_sata_init_wcache(int dev, u16 *id) -{ - fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - - if (ata_id_has_wcache(id) && ata_id_wcache_enabled(id)) - sata->wcache = 1; - if (ata_id_has_flush(id)) - sata->flush = 1; - if (ata_id_has_flush_ext(id)) - sata->flush_ext = 1; -} - -static int fsl_sata_get_wcache(int dev) -{ - fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - return sata->wcache; -} - -static int fsl_sata_get_flush(int dev) -{ - fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - return sata->flush; -} - -static int fsl_sata_get_flush_ext(int dev) -{ - fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - return sata->flush_ext; -} - -static u32 ata_low_level_rw_lba48(int dev, u32 blknr, lbaint_t blkcnt, - const void *buffer, int is_write) -{ - u32 start, blks; - u8 *addr; - int max_blks; - - start = blknr; - blks = blkcnt; - addr = (u8 *)buffer; - - max_blks = ATA_MAX_SECTORS_LBA48; - do { - if (blks > max_blks) { - if (fsl_sata_info[dev].flags != FLAGS_FPDMA) - fsl_sata_rw_cmd_ext(dev, start, max_blks, addr, is_write); - else - fsl_sata_rw_ncq_cmd(dev, start, max_blks, addr, is_write); - start += max_blks; - blks -= max_blks; - addr += ATA_SECT_SIZE * max_blks; - } else { - if (fsl_sata_info[dev].flags != FLAGS_FPDMA) - fsl_sata_rw_cmd_ext(dev, start, blks, addr, is_write); - else - fsl_sata_rw_ncq_cmd(dev, start, blks, addr, is_write); - start += blks; - blks = 0; - addr += ATA_SECT_SIZE * blks; - } - } while (blks != 0); - - return blkcnt; -} - -static u32 ata_low_level_rw_lba28(int dev, u32 blknr, u32 blkcnt, - const void *buffer, int is_write) -{ - u32 start, blks; - u8 *addr; - int max_blks; - - start = blknr; - blks = blkcnt; - addr = (u8 *)buffer; - - max_blks = ATA_MAX_SECTORS; - do { - if (blks > max_blks) { - fsl_sata_rw_cmd(dev, start, max_blks, addr, is_write); - start += max_blks; - blks -= max_blks; - addr += ATA_SECT_SIZE * max_blks; - } else { - fsl_sata_rw_cmd(dev, start, blks, addr, is_write); - start += blks; - blks = 0; - addr += ATA_SECT_SIZE * blks; - } - } while (blks != 0); - - return blkcnt; -} - -/* - * SATA interface between low level driver and command layer - */ -ulong sata_read(int dev, ulong blknr, lbaint_t blkcnt, void *buffer) -{ - u32 rc; - fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - - if (sata->lba48) - rc = ata_low_level_rw_lba48(dev, blknr, blkcnt, buffer, READ_CMD); - else - rc = ata_low_level_rw_lba28(dev, blknr, blkcnt, buffer, READ_CMD); - return rc; -} - -ulong sata_write(int dev, ulong blknr, lbaint_t blkcnt, const void *buffer) -{ - u32 rc; - fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - - if (sata->lba48) { - rc = ata_low_level_rw_lba48(dev, blknr, blkcnt, buffer, WRITE_CMD); - if (fsl_sata_get_wcache(dev) && fsl_sata_get_flush_ext(dev)) - fsl_sata_flush_cache_ext(dev); - } else { - rc = ata_low_level_rw_lba28(dev, blknr, blkcnt, buffer, WRITE_CMD); - if (fsl_sata_get_wcache(dev) && fsl_sata_get_flush(dev)) - fsl_sata_flush_cache(dev); - } - return rc; -} - -int scan_sata(int dev) -{ - fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - unsigned char serial[ATA_ID_SERNO_LEN + 1]; - unsigned char firmware[ATA_ID_FW_REV_LEN + 1]; - unsigned char product[ATA_ID_PROD_LEN + 1]; - u16 *id; - u64 n_sectors; - - /* if no detected link */ - if (!sata->link) - return -1; - - id = (u16 *)malloc(ATA_ID_WORDS * 2); - if (!id) { - printf("id malloc failed\n\r"); - return -1; - } - - /* Identify device to get information */ - fsl_sata_identify(dev, id); - - /* Serial number */ - ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial)); - memcpy(sata_dev_desc[dev].product, serial, sizeof(serial)); - - /* Firmware version */ - ata_id_c_string(id, firmware, ATA_ID_FW_REV, sizeof(firmware)); - memcpy(sata_dev_desc[dev].revision, firmware, sizeof(firmware)); - - /* Product model */ - ata_id_c_string(id, product, ATA_ID_PROD, sizeof(product)); - memcpy(sata_dev_desc[dev].vendor, product, sizeof(product)); - - /* Totoal sectors */ - n_sectors = ata_id_n_sectors(id); - sata_dev_desc[dev].lba = (u32)n_sectors; - -#ifdef CONFIG_LBA48 - /* Check if support LBA48 */ - if (ata_id_has_lba48(id)) { - sata->lba48 = 1; - debug("Device support LBA48\n\r"); - } else - debug("Device supports LBA28\n\r"); -#endif - - /* Get the NCQ queue depth from device */ - sata->queue_depth = ata_id_queue_depth(id); - - /* Get the xfer mode from device */ - fsl_sata_xfer_mode(dev, id); - - /* Get the write cache status from device */ - fsl_sata_init_wcache(dev, id); - - /* Set the xfer mode to highest speed */ - fsl_sata_set_features(dev); -#ifdef DEBUG - fsl_sata_identify(dev, id); - ata_dump_id(id); -#endif - free((void *)id); - return 0; -} diff --git a/drivers/block/fsl_sata.h b/drivers/block/fsl_sata.h deleted file mode 100644 index 18d679e..0000000 --- a/drivers/block/fsl_sata.h +++ /dev/null @@ -1,321 +0,0 @@ -/* - * Copyright (C) 2007-2008 Freescale Semiconductor, Inc. - * Dave Liu - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#ifndef __FSL_SATA_H__ -#define __FSL_SATA_H__ - -#define SATA_HC_MAX_NUM 4 /* Max host controller numbers */ -#define SATA_HC_MAX_CMD 16 /* Max command queue depth per host controller */ -#define SATA_HC_MAX_PORT 16 /* Max port number per host controller */ - -/* -* SATA Host Controller Registers -*/ -typedef struct fsl_sata_reg { - /* SATA command registers */ - u32 cqr; /* Command queue register */ - u8 res1[0x4]; - u32 car; /* Command active register */ - u8 res2[0x4]; - u32 ccr; /* Command completed register */ - u8 res3[0x4]; - u32 cer; /* Command error register */ - u8 res4[0x4]; - u32 der; /* Device error register */ - u32 chba; /* Command header base address */ - u32 hstatus; /* Host status register */ - u32 hcontrol; /* Host control register */ - u32 cqpmp; /* Port number queue register */ - u32 sig; /* Signature register */ - u32 icc; /* Interrupt coalescing control register */ - u8 res5[0xc4]; - - /* SATA supperset registers */ - u32 sstatus; /* SATA interface status register */ - u32 serror; /* SATA interface error register */ - u32 scontrol; /* SATA interface control register */ - u32 snotification; /* SATA interface notification register */ - u8 res6[0x30]; - - /* SATA control status registers */ - u32 transcfg; /* Transport layer configuration */ - u32 transstatus; /* Transport layer status */ - u32 linkcfg; /* Link layer configuration */ - u32 linkcfg1; /* Link layer configuration1 */ - u32 linkcfg2; /* Link layer configuration2 */ - u32 linkstatus; /* Link layer status */ - u32 linkstatus1; /* Link layer status1 */ - u32 phyctrlcfg; /* PHY control configuration */ - u8 res7[0x2b0]; - - /* SATA system control registers */ - u32 syspr; /* System priority register - big endian */ - u8 res8[0xbec]; -} __attribute__ ((packed)) fsl_sata_reg_t; - -/* HStatus register -*/ -#define HSTATUS_ONOFF 0x80000000 /* Online/offline status */ -#define HSTATUS_FORCE_OFFLINE 0x40000000 /* In process going offline */ -#define HSTATUS_BIST_ERR 0x20000000 - -/* Fatal error */ -#define HSTATUS_MASTER_ERR 0x00004000 -#define HSTATUS_DATA_UNDERRUN 0x00002000 -#define HSTATUS_DATA_OVERRUN 0x00001000 -#define HSTATUS_CRC_ERR_TX 0x00000800 -#define HSTATUS_CRC_ERR_RX 0x00000400 -#define HSTATUS_FIFO_OVERFLOW_TX 0x00000200 -#define HSTATUS_FIFO_OVERFLOW_RX 0x00000100 -#define HSTATUS_FATAL_ERR_ALL (HSTATUS_MASTER_ERR | \ - HSTATUS_DATA_UNDERRUN | \ - HSTATUS_DATA_OVERRUN | \ - HSTATUS_CRC_ERR_TX | \ - HSTATUS_CRC_ERR_RX | \ - HSTATUS_FIFO_OVERFLOW_TX | \ - HSTATUS_FIFO_OVERFLOW_RX) -/* Interrupt status */ -#define HSTATUS_FATAL_ERR 0x00000020 -#define HSTATUS_PHY_RDY 0x00000010 -#define HSTATUS_SIGNATURE 0x00000008 -#define HSTATUS_SNOTIFY 0x00000004 -#define HSTATUS_DEVICE_ERR 0x00000002 -#define HSTATUS_CMD_COMPLETE 0x00000001 - -/* HControl register -*/ -#define HCONTROL_ONOFF 0x80000000 /* Online or offline request */ -#define HCONTROL_FORCE_OFFLINE 0x40000000 /* Force offline request */ -#define HCONTROL_ENTERPRISE_EN 0x10000000 /* Enterprise mode enabled */ -#define HCONTROL_HDR_SNOOP 0x00000400 /* Command header snoop */ -#define HCONTROL_PMP_ATTACHED 0x00000200 /* Port multiplier attached */ - -/* Interrupt enable */ -#define HCONTROL_FATAL_ERR 0x00000020 -#define HCONTROL_PHY_RDY 0x00000010 -#define HCONTROL_SIGNATURE 0x00000008 -#define HCONTROL_SNOTIFY 0x00000004 -#define HCONTROL_DEVICE_ERR 0x00000002 -#define HCONTROL_CMD_COMPLETE 0x00000001 - -#define HCONTROL_INT_EN_ALL (HCONTROL_FATAL_ERR | \ - HCONTROL_PHY_RDY | \ - HCONTROL_SIGNATURE | \ - HCONTROL_SNOTIFY | \ - HCONTROL_DEVICE_ERR | \ - HCONTROL_CMD_COMPLETE) - -/* SStatus register -*/ -#define SSTATUS_IPM_MASK 0x00000780 -#define SSTATUS_IPM_NOPRESENT 0x00000000 -#define SSTATUS_IPM_ACTIVE 0x00000080 -#define SSTATUS_IPM_PATIAL 0x00000100 -#define SSTATUS_IPM_SLUMBER 0x00000300 - -#define SSTATUS_SPD_MASK 0x000000f0 -#define SSTATUS_SPD_GEN1 0x00000010 -#define SSTATUS_SPD_GEN2 0x00000020 - -#define SSTATUS_DET_MASK 0x0000000f -#define SSTATUS_DET_NODEVICE 0x00000000 -#define SSTATUS_DET_DISCONNECT 0x00000001 -#define SSTATUS_DET_CONNECT 0x00000003 -#define SSTATUS_DET_PHY_OFFLINE 0x00000004 - -/* SControl register -*/ -#define SCONTROL_SPM_MASK 0x0000f000 -#define SCONTROL_SPM_GO_PARTIAL 0x00001000 -#define SCONTROL_SPM_GO_SLUMBER 0x00002000 -#define SCONTROL_SPM_GO_ACTIVE 0x00004000 - -#define SCONTROL_IPM_MASK 0x00000f00 -#define SCONTROL_IPM_NO_RESTRICT 0x00000000 -#define SCONTROL_IPM_PARTIAL 0x00000100 -#define SCONTROL_IPM_SLUMBER 0x00000200 -#define SCONTROL_IPM_PART_SLUM 0x00000300 - -#define SCONTROL_SPD_MASK 0x000000f0 -#define SCONTROL_SPD_NO_RESTRICT 0x00000000 -#define SCONTROL_SPD_GEN1 0x00000010 -#define SCONTROL_SPD_GEN2 0x00000020 - -#define SCONTROL_DET_MASK 0x0000000f -#define SCONTROL_DET_HRESET 0x00000001 -#define SCONTROL_DET_DISABLE 0x00000004 - -/* TransCfg register -*/ -#define TRANSCFG_DFIS_SIZE_SHIFT 16 -#define TRANSCFG_RX_WATER_MARK_MASK 0x0000001f - -/* PhyCtrlCfg register -*/ -#define PHYCTRLCFG_FPRFTI_MASK 0x00000018 -#define PHYCTRLCFG_LOOPBACK_MASK 0x0000000e - -/* -* Command Header Entry -*/ -typedef struct cmd_hdr_entry { - __le32 cda; /* Command Descriptor Address, - 4 bytes aligned */ - __le32 prde_fis_len; /* Number of PRD entries and FIS length */ - __le32 ttl; /* Total transfer length */ - __le32 attribute; /* the attribute of command */ -} __attribute__ ((packed)) cmd_hdr_entry_t; - -#define SATA_HC_CMD_HDR_ENTRY_SIZE sizeof(struct cmd_hdr_entry) - -/* cda -*/ -#define CMD_HDR_CDA_ALIGN 4 - -/* prde_fis_len -*/ -#define CMD_HDR_PRD_ENTRY_SHIFT 16 -#define CMD_HDR_PRD_ENTRY_MASK 0x003f0000 -#define CMD_HDR_FIS_LEN_SHIFT 2 - -/* attribute -*/ -#define CMD_HDR_ATTR_RES 0x00000800 /* Reserved bit, should be 1 */ -#define CMD_HDR_ATTR_VBIST 0x00000400 /* Vendor BIST */ -#define CMD_HDR_ATTR_SNOOP 0x00000200 /* Snoop enable for all descriptor */ -#define CMD_HDR_ATTR_FPDMA 0x00000100 /* FPDMA queued command */ -#define CMD_HDR_ATTR_RESET 0x00000080 /* Reset - a SRST or device reset */ -#define CMD_HDR_ATTR_BIST 0x00000040 /* BIST - require the host to enter BIST mode */ -#define CMD_HDR_ATTR_ATAPI 0x00000020 /* ATAPI command */ -#define CMD_HDR_ATTR_TAG 0x0000001f /* TAG mask */ - -/* command type -*/ -enum cmd_type { - CMD_VENDOR_BIST, - CMD_BIST, - CMD_RESET, /* SRST or device reset */ - CMD_ATAPI, - CMD_NCQ, - CMD_ATA, /* None of all above */ -}; - -/* -* Command Header Table -*/ -typedef struct cmd_hdr_tbl { - cmd_hdr_entry_t cmd_slot[SATA_HC_MAX_CMD]; -} __attribute__ ((packed)) cmd_hdr_tbl_t; - -#define SATA_HC_CMD_HDR_TBL_SIZE sizeof(struct cmd_hdr_tbl) -#define SATA_HC_CMD_HDR_TBL_ALIGN 4 - -/* -* PRD entry - Physical Region Descriptor entry -*/ -typedef struct prd_entry { - __le32 dba; /* Data base address, 4 bytes aligned */ - u32 res1; - u32 res2; - __le32 ext_c_ddc; /* Indirect PRD flags, snoop and data word count */ -} __attribute__ ((packed)) prd_entry_t; - -#define SATA_HC_CMD_DESC_PRD_SIZE sizeof(struct prd_entry) - -/* dba -*/ -#define PRD_ENTRY_DBA_ALIGN 4 - -/* ext_c_ddc -*/ -#define PRD_ENTRY_EXT 0x80000000 /* extension flag */ -#ifdef CONFIG_FSL_SATA_V2 -#define PRD_ENTRY_DATA_SNOOP 0x10000000 /* Data snoop enable */ -#else -#define PRD_ENTRY_DATA_SNOOP 0x00400000 /* Data snoop enable */ -#endif -#define PRD_ENTRY_LEN_MASK 0x003fffff /* Data word count */ - -#define PRD_ENTRY_MAX_XFER_SZ (PRD_ENTRY_LEN_MASK + 1) - -/* - * This SATA host controller supports a max of 16 direct PRD entries, but if use - * chained indirect PRD entries, then the contollers supports upto a max of 63 - * entries including direct and indirect PRD entries. - * The PRDT is an array of 63 PRD entries contigiously, but the PRD entries#15 - * will be setup as an indirect descriptor, pointing to it's next (contigious) - * PRD entries#16. - */ -#define SATA_HC_MAX_PRD 63 /* Max PRD entry numbers per command */ -#define SATA_HC_MAX_PRD_DIRECT 16 /* Direct PRDT entries */ -#define SATA_HC_MAX_PRD_USABLE (SATA_HC_MAX_PRD - 1) -#define SATA_HC_MAX_XFER_LEN 0x4000000 - -/* -* PRDT - Physical Region Descriptor Table -*/ -typedef struct prdt { - prd_entry_t prdt[SATA_HC_MAX_PRD]; -} __attribute__ ((packed)) prdt_t; - -/* -* Command Descriptor -*/ -#define SATA_HC_CMD_DESC_CFIS_SIZE 32 /* bytes */ -#define SATA_HC_CMD_DESC_SFIS_SIZE 32 /* bytes */ -#define SATA_HC_CMD_DESC_ACMD_SIZE 16 /* bytes */ -#define SATA_HC_CMD_DESC_RES 16 /* bytes */ - -typedef struct cmd_desc { - u8 cfis[SATA_HC_CMD_DESC_CFIS_SIZE]; - u8 sfis[SATA_HC_CMD_DESC_SFIS_SIZE]; - u8 acmd[SATA_HC_CMD_DESC_ACMD_SIZE]; - u8 res[SATA_HC_CMD_DESC_RES]; - prd_entry_t prdt[SATA_HC_MAX_PRD]; -} __attribute__ ((packed)) cmd_desc_t; - -#define SATA_HC_CMD_DESC_SIZE sizeof(struct cmd_desc) -#define SATA_HC_CMD_DESC_ALIGN 4 - -/* - * SATA device driver info - */ -typedef struct fsl_sata_info { - u32 sata_reg_base; - u32 flags; -} fsl_sata_info_t; - -#define FLAGS_DMA 0x00000000 -#define FLAGS_FPDMA 0x00000001 - -/* - * SATA device driver struct - */ -typedef struct fsl_sata { - char name[12]; - fsl_sata_reg_t *reg_base; /* the base address of controller register */ - void *cmd_hdr_tbl_offset; /* alloc address of command header table */ - cmd_hdr_tbl_t *cmd_hdr; /* aligned address of command header table */ - void *cmd_desc_offset; /* alloc address of command descriptor */ - cmd_desc_t *cmd_desc; /* aligned address of command descriptor */ - int link; /* PHY link status */ - /* device attribute */ - int ata_device_type; /* device type */ - int lba48; - int queue_depth; /* Max NCQ queue depth */ - u16 pio; - u16 mwdma; - u16 udma; - int wcache; - int flush; - int flush_ext; -} fsl_sata_t; - -#define READ_CMD 0 -#define WRITE_CMD 1 - -#endif /* __FSL_SATA_H__ */ diff --git a/drivers/block/libata.c b/drivers/block/libata.c deleted file mode 100644 index d684270..0000000 --- a/drivers/block/libata.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (C) 2008 Freescale Semiconductor, Inc. - * Dave Liu - * port from the libata of linux kernel - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include - -u64 ata_id_n_sectors(u16 *id) -{ - if (ata_id_has_lba(id)) { - if (ata_id_has_lba48(id)) - return ata_id_u64(id, ATA_ID_LBA48_SECTORS); - else - return ata_id_u32(id, ATA_ID_LBA_SECTORS); - } else { - return 0; - } -} - -u32 ata_dev_classify(u32 sig) -{ - u8 lbam, lbah; - - lbam = (sig >> 16) & 0xff; - lbah = (sig >> 24) & 0xff; - - if (((lbam == 0) && (lbah == 0)) || - ((lbam == 0x3c) && (lbah == 0xc3))) - return ATA_DEV_ATA; - - if ((lbam == 0x14) && (lbah == 0xeb)) - return ATA_DEV_ATAPI; - - if ((lbam == 0x69) && (lbah == 0x96)) - return ATA_DEV_PMP; - - return ATA_DEV_UNKNOWN; -} - -static void ata_id_string(const u16 *id, unsigned char *s, - unsigned int ofs, unsigned int len) -{ - unsigned int c; - - while (len > 0) { - c = id[ofs] >> 8; - *s = c; - s++; - - c = id[ofs] & 0xff; - *s = c; - s++; - - ofs++; - len -= 2; - } -} - -void ata_id_c_string(const u16 *id, unsigned char *s, - unsigned int ofs, unsigned int len) -{ - unsigned char *p; - - ata_id_string(id, s, ofs, len - 1); - - p = s + strnlen((char *)s, len - 1); - while (p > s && p[-1] == ' ') - p--; - *p = '\0'; -} - -void ata_dump_id(u16 *id) -{ - unsigned char serial[ATA_ID_SERNO_LEN + 1]; - unsigned char firmware[ATA_ID_FW_REV_LEN + 1]; - unsigned char product[ATA_ID_PROD_LEN + 1]; - u64 n_sectors; - - /* Serial number */ - ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial)); - printf("S/N: %s\n\r", serial); - - /* Firmware version */ - ata_id_c_string(id, firmware, ATA_ID_FW_REV, sizeof(firmware)); - printf("Firmware version: %s\n\r", firmware); - - /* Product model */ - ata_id_c_string(id, product, ATA_ID_PROD, sizeof(product)); - printf("Product model number: %s\n\r", product); - - /* Total sectors of device */ - n_sectors = ata_id_n_sectors(id); - printf("Capablity: %lld sectors\n\r", n_sectors); - - printf ("id[49]: capabilities = 0x%04x\n" - "id[53]: field valid = 0x%04x\n" - "id[63]: mwdma = 0x%04x\n" - "id[64]: pio = 0x%04x\n" - "id[75]: queue depth = 0x%04x\n", - id[49], - id[53], - id[63], - id[64], - id[75]); - - printf ("id[76]: sata capablity = 0x%04x\n" - "id[78]: sata features supported = 0x%04x\n" - "id[79]: sata features enable = 0x%04x\n", - id[76], - id[78], - id[79]); - - printf ("id[80]: major version = 0x%04x\n" - "id[81]: minor version = 0x%04x\n" - "id[82]: command set supported 1 = 0x%04x\n" - "id[83]: command set supported 2 = 0x%04x\n" - "id[84]: command set extension = 0x%04x\n", - id[80], - id[81], - id[82], - id[83], - id[84]); - printf ("id[85]: command set enable 1 = 0x%04x\n" - "id[86]: command set enable 2 = 0x%04x\n" - "id[87]: command set default = 0x%04x\n" - "id[88]: udma = 0x%04x\n" - "id[93]: hardware reset result = 0x%04x\n", - id[85], - id[86], - id[87], - id[88], - id[93]); -} - -void ata_swap_buf_le16(u16 *buf, unsigned int buf_words) -{ - unsigned int i; - - for (i = 0; i < buf_words; i++) - buf[i] = le16_to_cpu(buf[i]); -} diff --git a/drivers/block/mvsata_ide.c b/drivers/block/mvsata_ide.c deleted file mode 100644 index 7b6a155..0000000 --- a/drivers/block/mvsata_ide.c +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright (C) 2010 Albert ARIBAUD - * - * Written-by: Albert ARIBAUD - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include - -#if defined(CONFIG_ORION5X) -#include -#elif defined(CONFIG_KIRKWOOD) -#include -#elif defined(CONFIG_ARCH_MVEBU) -#include -#endif - -/* SATA port registers */ -struct mvsata_port_registers { - u32 reserved0[10]; - u32 edma_cmd; - u32 reserved1[181]; - /* offset 0x300 : ATA Interface registers */ - u32 sstatus; - u32 serror; - u32 scontrol; - u32 ltmode; - u32 phymode3; - u32 phymode4; - u32 reserved2[5]; - u32 phymode1; - u32 phymode2; - u32 bist_cr; - u32 bist_dw1; - u32 bist_dw2; - u32 serrorintrmask; -}; - -/* - * Sanity checks: - * - to compile at all, we need CONFIG_SYS_ATA_BASE_ADDR. - * - for ide_preinit to make sense, we need at least one of - * CONFIG_SYS_ATA_IDE0_OFFSET or CONFIG_SYS_ATA_IDE1_OFFSET; - * - for ide_preinit to be called, we need CONFIG_IDE_PREINIT. - * Fail with an explanation message if these conditions are not met. - * This is particularly important for CONFIG_IDE_PREINIT, because - * its lack would not cause a build error. - */ - -#if !defined(CONFIG_SYS_ATA_BASE_ADDR) -#error CONFIG_SYS_ATA_BASE_ADDR must be defined -#elif !defined(CONFIG_SYS_ATA_IDE0_OFFSET) \ - && !defined(CONFIG_SYS_ATA_IDE1_OFFSET) -#error CONFIG_SYS_ATA_IDE0_OFFSET or CONFIG_SYS_ATA_IDE1_OFFSET \ - must be defined -#elif !defined(CONFIG_IDE_PREINIT) -#error CONFIG_IDE_PREINIT must be defined -#endif - -/* - * Masks and values for SControl DETection and Interface Power Management, - * and for SStatus DETection. - */ - -#define MVSATA_EDMA_CMD_ATA_RST 0x00000004 -#define MVSATA_SCONTROL_DET_MASK 0x0000000F -#define MVSATA_SCONTROL_DET_NONE 0x00000000 -#define MVSATA_SCONTROL_DET_INIT 0x00000001 -#define MVSATA_SCONTROL_IPM_MASK 0x00000F00 -#define MVSATA_SCONTROL_IPM_NO_LP_ALLOWED 0x00000300 -#define MVSATA_SCONTROL_MASK \ - (MVSATA_SCONTROL_DET_MASK|MVSATA_SCONTROL_IPM_MASK) -#define MVSATA_PORT_INIT \ - (MVSATA_SCONTROL_DET_INIT|MVSATA_SCONTROL_IPM_NO_LP_ALLOWED) -#define MVSATA_PORT_USE \ - (MVSATA_SCONTROL_DET_NONE|MVSATA_SCONTROL_IPM_NO_LP_ALLOWED) -#define MVSATA_SSTATUS_DET_MASK 0x0000000F -#define MVSATA_SSTATUS_DET_DEVCOMM 0x00000003 - -/* - * Status codes to return to client callers. Currently, callers ignore - * exact value and only care for zero or nonzero, so no need to make this - * public, it is only #define'd for clarity. - * If/when standard negative codes are implemented in U-Boot, then these - * #defines should be moved to, or replaced by ones from, the common list - * of status codes. - */ - -#define MVSATA_STATUS_OK 0 -#define MVSATA_STATUS_TIMEOUT -1 - -/* - * Registers for SATA MBUS memory windows - */ - -#define MVSATA_WIN_CONTROL(w) (MVEBU_AXP_SATA_BASE + 0x30 + ((w) << 4)) -#define MVSATA_WIN_BASE(w) (MVEBU_AXP_SATA_BASE + 0x34 + ((w) << 4)) - -/* - * Initialize SATA memory windows for Armada XP - */ - -#ifdef CONFIG_ARCH_MVEBU -static void mvsata_ide_conf_mbus_windows(void) -{ - const struct mbus_dram_target_info *dram; - int i; - - dram = mvebu_mbus_dram_info(); - - /* Disable windows, Set Size/Base to 0 */ - for (i = 0; i < 4; i++) { - writel(0, MVSATA_WIN_CONTROL(i)); - writel(0, MVSATA_WIN_BASE(i)); - } - - for (i = 0; i < dram->num_cs; i++) { - const struct mbus_dram_window *cs = dram->cs + i; - writel(((cs->size - 1) & 0xffff0000) | (cs->mbus_attr << 8) | - (dram->mbus_dram_target_id << 4) | 1, - MVSATA_WIN_CONTROL(i)); - writel(cs->base & 0xffff0000, MVSATA_WIN_BASE(i)); - } -} -#endif - -/* - * Initialize one MVSATAHC port: set SControl's IPM to "always active" - * and DET to "reset", then wait for SStatus's DET to become "device and - * comm ok" (or time out after 50 us if no device), then set SControl's - * DET back to "no action". - */ - -static int mvsata_ide_initialize_port(struct mvsata_port_registers *port) -{ - u32 control; - u32 status; - u32 timeleft = 10000; /* wait at most 10 ms for SATA reset to complete */ - - /* Hard reset */ - writel(MVSATA_EDMA_CMD_ATA_RST, &port->edma_cmd); - udelay(25); /* taken from original marvell port */ - writel(0, &port->edma_cmd); - - /* Set control IPM to 3 (no low power) and DET to 1 (initialize) */ - control = readl(&port->scontrol); - control = (control & ~MVSATA_SCONTROL_MASK) | MVSATA_PORT_INIT; - writel(control, &port->scontrol); - /* Toggle control DET back to 0 (normal operation) */ - control = (control & ~MVSATA_SCONTROL_MASK) | MVSATA_PORT_USE; - writel(control, &port->scontrol); - /* wait for status DET to become 3 (device and communication OK) */ - while (--timeleft) { - status = readl(&port->sstatus) & MVSATA_SSTATUS_DET_MASK; - if (status == MVSATA_SSTATUS_DET_DEVCOMM) - break; - udelay(1); - } - /* return success or time-out error depending on time left */ - if (!timeleft) - return MVSATA_STATUS_TIMEOUT; - return MVSATA_STATUS_OK; -} - -/* - * ide_preinit() will be called by ide_init in cmd_ide.c and will - * reset the MVSTATHC ports needed by the board. - */ - -int ide_preinit(void) -{ - int ret = MVSATA_STATUS_TIMEOUT; - int status; - -#ifdef CONFIG_ARCH_MVEBU - mvsata_ide_conf_mbus_windows(); -#endif - - /* Enable ATA port 0 (could be SATA port 0 or 1) if declared */ -#if defined(CONFIG_SYS_ATA_IDE0_OFFSET) - status = mvsata_ide_initialize_port( - (struct mvsata_port_registers *) - (CONFIG_SYS_ATA_BASE_ADDR + CONFIG_SYS_ATA_IDE0_OFFSET)); - if (status == MVSATA_STATUS_OK) - ret = MVSATA_STATUS_OK; -#endif - /* Enable ATA port 1 (could be SATA port 0 or 1) if declared */ -#if defined(CONFIG_SYS_ATA_IDE1_OFFSET) - status = mvsata_ide_initialize_port( - (struct mvsata_port_registers *) - (CONFIG_SYS_ATA_BASE_ADDR + CONFIG_SYS_ATA_IDE1_OFFSET)); - if (status == MVSATA_STATUS_OK) - ret = MVSATA_STATUS_OK; -#endif - /* Return success if at least one port initialization succeeded */ - return ret; -} diff --git a/drivers/block/mxc_ata.c b/drivers/block/mxc_ata.c deleted file mode 100644 index 44bb406..0000000 --- a/drivers/block/mxc_ata.c +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Freescale iMX51 ATA driver - * - * Copyright (C) 2010 Marek Vasut - * - * Based on code by: - * Mahesh Mahadevan - * - * Based on code from original FSL ATA driver, which is - * part of eCos, the Embedded Configurable Operating System. - * Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include -#include -#include -#include - -#include -#include - -/* MXC ATA register offsets */ -struct mxc_ata_config_regs { - u8 time_off; /* 0x00 */ - u8 time_on; - u8 time_1; - u8 time_2w; - u8 time_2r; - u8 time_ax; - u8 time_pio_rdx; - u8 time_4; - u8 time_9; - u8 time_m; - u8 time_jn; - u8 time_d; - u8 time_k; - u8 time_ack; - u8 time_env; - u8 time_udma_rdx; - u8 time_zah; /* 0x10 */ - u8 time_mlix; - u8 time_dvh; - u8 time_dzfs; - u8 time_dvs; - u8 time_cvh; - u8 time_ss; - u8 time_cyc; - u32 fifo_data_32; /* 0x18 */ - u32 fifo_data_16; - u32 fifo_fill; - u32 ata_control; - u32 interrupt_pending; - u32 interrupt_enable; - u32 interrupt_clear; - u32 fifo_alarm; -}; - -struct mxc_data_hdd_regs { - u32 drive_data; /* 0xa0 */ - u32 drive_features; - u32 drive_sector_count; - u32 drive_sector_num; - u32 drive_cyl_low; - u32 drive_cyl_high; - u32 drive_dev_head; - u32 command; - u32 status; - u32 alt_status; -}; - -/* PIO timing table */ -#define NR_PIO_SPECS 5 -static uint16_t pio_t1[NR_PIO_SPECS] = { 70, 50, 30, 30, 25 }; -static uint16_t pio_t2_8[NR_PIO_SPECS] = { 290, 290, 290, 80, 70 }; -static uint16_t pio_t4[NR_PIO_SPECS] = { 30, 20, 15, 10, 10 }; -static uint16_t pio_t9[NR_PIO_SPECS] = { 20, 15, 10, 10, 10 }; -static uint16_t pio_tA[NR_PIO_SPECS] = { 50, 50, 50, 50, 50 }; - -#define REG2OFF(reg) ((((uint32_t)reg) & 0x3) * 8) -static void set_ata_bus_timing(unsigned char mode) -{ - uint32_t T = 1000000000 / mxc_get_clock(MXC_IPG_CLK); - - struct mxc_ata_config_regs *ata_regs; - ata_regs = (struct mxc_ata_config_regs *)CONFIG_SYS_ATA_BASE_ADDR; - - if (mode >= NR_PIO_SPECS) - return; - - /* Write TIME_OFF/ON/1/2W */ - writeb(3, &ata_regs->time_off); - writeb(3, &ata_regs->time_on); - writeb((pio_t1[mode] + T) / T, &ata_regs->time_1); - writeb((pio_t2_8[mode] + T) / T, &ata_regs->time_2w); - - /* Write TIME_2R/AX/RDX/4 */ - writeb((pio_t2_8[mode] + T) / T, &ata_regs->time_2r); - writeb((pio_tA[mode] + T) / T + 2, &ata_regs->time_ax); - writeb(1, &ata_regs->time_pio_rdx); - writeb((pio_t4[mode] + T) / T, &ata_regs->time_4); - - /* Write TIME_9 ; the rest of timing registers is irrelevant for PIO */ - writeb((pio_t9[mode] + T) / T, &ata_regs->time_9); -} - -int ide_preinit(void) -{ - struct mxc_ata_config_regs *ata_regs; - ata_regs = (struct mxc_ata_config_regs *)CONFIG_SYS_ATA_BASE_ADDR; - - /* 46.3.3.4 @ FSL iMX51 manual */ - /* FIFO normal op., drive reset */ - writel(0x80, &ata_regs->ata_control); - /* FIFO normal op., drive not reset */ - writel(0xc0, &ata_regs->ata_control); - - /* Configure the PIO timing */ - set_ata_bus_timing(CONFIG_MXC_ATA_PIO_MODE); - - /* 46.3.3.4 @ FSL iMX51 manual */ - /* Drive not reset, IORDY handshake */ - writel(0x41, &ata_regs->ata_control); - - return 0; -} diff --git a/drivers/block/sata_ceva.c b/drivers/block/sata_ceva.c deleted file mode 100644 index 0c24fce..0000000 --- a/drivers/block/sata_ceva.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * (C) Copyright 2015 - 2016 Xilinx, Inc. - * Michal Simek - * - * SPDX-License-Identifier: GPL-2.0+ - */ -#include -#include -#include -#include -#include - -#include - -/* Vendor Specific Register Offsets */ -#define AHCI_VEND_PCFG 0xA4 -#define AHCI_VEND_PPCFG 0xA8 -#define AHCI_VEND_PP2C 0xAC -#define AHCI_VEND_PP3C 0xB0 -#define AHCI_VEND_PP4C 0xB4 -#define AHCI_VEND_PP5C 0xB8 -#define AHCI_VEND_PAXIC 0xC0 -#define AHCI_VEND_PTC 0xC8 - -/* Vendor Specific Register bit definitions */ -#define PAXIC_ADBW_BW64 0x1 -#define PAXIC_MAWIDD (1 << 8) -#define PAXIC_MARIDD (1 << 16) -#define PAXIC_OTL (0x4 << 20) - -#define PCFG_TPSS_VAL (0x32 << 16) -#define PCFG_TPRS_VAL (0x2 << 12) -#define PCFG_PAD_VAL 0x2 - -#define PPCFG_TTA 0x1FFFE -#define PPCFG_PSSO_EN (1 << 28) -#define PPCFG_PSS_EN (1 << 29) -#define PPCFG_ESDF_EN (1 << 31) - -#define PP2C_CIBGMN 0x0F -#define PP2C_CIBGMX (0x25 << 8) -#define PP2C_CIBGN (0x18 << 16) -#define PP2C_CINMP (0x29 << 24) - -#define PP3C_CWBGMN 0x04 -#define PP3C_CWBGMX (0x0B << 8) -#define PP3C_CWBGN (0x08 << 16) -#define PP3C_CWNMP (0x0F << 24) - -#define PP4C_BMX 0x0a -#define PP4C_BNM (0x08 << 8) -#define PP4C_SFD (0x4a << 16) -#define PP4C_PTST (0x06 << 24) - -#define PP5C_RIT 0x60216 -#define PP5C_RCT (0x7f0 << 20) - -#define PTC_RX_WM_VAL 0x40 -#define PTC_RSVD (1 << 27) - -#define PORT0_BASE 0x100 -#define PORT1_BASE 0x180 - -/* Port Control Register Bit Definitions */ -#define PORT_SCTL_SPD_GEN3 (0x3 << 4) -#define PORT_SCTL_SPD_GEN2 (0x2 << 4) -#define PORT_SCTL_SPD_GEN1 (0x1 << 4) -#define PORT_SCTL_IPM (0x3 << 8) - -#define PORT_BASE 0x100 -#define PORT_OFFSET 0x80 -#define NR_PORTS 2 -#define DRV_NAME "ahci-ceva" -#define CEVA_FLAG_BROKEN_GEN2 1 - -static int ceva_init_sata(ulong mmio) -{ - ulong tmp; - int i; - - /* - * AXI Data bus width to 64 - * Set Mem Addr Read, Write ID for data transfers - * Transfer limit to 72 DWord - */ - tmp = PAXIC_ADBW_BW64 | PAXIC_MAWIDD | PAXIC_MARIDD | PAXIC_OTL; - writel(tmp, mmio + AHCI_VEND_PAXIC); - - /* Set AHCI Enable */ - tmp = readl(mmio + HOST_CTL); - tmp |= HOST_AHCI_EN; - writel(tmp, mmio + HOST_CTL); - - for (i = 0; i < NR_PORTS; i++) { - /* TPSS TPRS scalars, CISE and Port Addr */ - tmp = PCFG_TPSS_VAL | PCFG_TPRS_VAL | (PCFG_PAD_VAL + i); - writel(tmp, mmio + AHCI_VEND_PCFG); - - /* Port Phy Cfg register enables */ - tmp = PPCFG_TTA | PPCFG_PSS_EN | PPCFG_ESDF_EN; - writel(tmp, mmio + AHCI_VEND_PPCFG); - - /* Rx Watermark setting */ - tmp = PTC_RX_WM_VAL | PTC_RSVD; - writel(tmp, mmio + AHCI_VEND_PTC); - - /* Default to Gen 2 Speed and Gen 1 if Gen2 is broken */ - tmp = PORT_SCTL_SPD_GEN3 | PORT_SCTL_IPM; - writel(tmp, mmio + PORT_SCR_CTL + PORT_BASE + PORT_OFFSET * i); - } - return 0; -} - -static int sata_ceva_probe(struct udevice *dev) -{ - struct scsi_platdata *plat = dev_get_platdata(dev); - - ceva_init_sata(plat->base); - return 0; -} - -static const struct udevice_id sata_ceva_ids[] = { - { .compatible = "ceva,ahci-1v84" }, - { } -}; - -static int sata_ceva_ofdata_to_platdata(struct udevice *dev) -{ - struct scsi_platdata *plat = dev_get_platdata(dev); - - plat->base = devfdt_get_addr(dev); - if (plat->base == FDT_ADDR_T_NONE) - return -EINVAL; - - /* Hardcode number for ceva sata controller */ - plat->max_lun = 1; /* Actually two but untested */ - plat->max_id = 2; - - return 0; -} - -U_BOOT_DRIVER(ceva_host_blk) = { - .name = "ceva_sata", - .id = UCLASS_SCSI, - .of_match = sata_ceva_ids, - .probe = sata_ceva_probe, - .ofdata_to_platdata = sata_ceva_ofdata_to_platdata, - .platdata_auto_alloc_size = sizeof(struct scsi_platdata), -}; diff --git a/drivers/block/sata_dwc.c b/drivers/block/sata_dwc.c deleted file mode 100644 index a226ca2..0000000 --- a/drivers/block/sata_dwc.c +++ /dev/null @@ -1,2076 +0,0 @@ -/* - * sata_dwc.c - * - * Synopsys DesignWare Cores (DWC) SATA host driver - * - * Author: Mark Miesfeld - * - * Ported from 2.6.19.2 to 2.6.25/26 by Stefan Roese - * Copyright 2008 DENX Software Engineering - * - * Based on versions provided by AMCC and Synopsys which are: - * Copyright 2006 Applied Micro Circuits Corporation - * COPYRIGHT (C) 2005 SYNOPSYS, INC. ALL RIGHTS RESERVED - * - * SPDX-License-Identifier: GPL-2.0+ - */ -/* - * SATA support based on the chip canyonlands. - * - * 04-17-2009 - * The local version of this driver for the canyonlands board - * does not use interrupts but polls the chip instead. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "sata_dwc.h" - -#define DMA_NUM_CHANS 1 -#define DMA_NUM_CHAN_REGS 8 - -#define AHB_DMA_BRST_DFLT 16 - -struct dmareg { - u32 low; - u32 high; -}; - -struct dma_chan_regs { - struct dmareg sar; - struct dmareg dar; - struct dmareg llp; - struct dmareg ctl; - struct dmareg sstat; - struct dmareg dstat; - struct dmareg sstatar; - struct dmareg dstatar; - struct dmareg cfg; - struct dmareg sgr; - struct dmareg dsr; -}; - -struct dma_interrupt_regs { - struct dmareg tfr; - struct dmareg block; - struct dmareg srctran; - struct dmareg dsttran; - struct dmareg error; -}; - -struct ahb_dma_regs { - struct dma_chan_regs chan_regs[DMA_NUM_CHAN_REGS]; - struct dma_interrupt_regs interrupt_raw; - struct dma_interrupt_regs interrupt_status; - struct dma_interrupt_regs interrupt_mask; - struct dma_interrupt_regs interrupt_clear; - struct dmareg statusInt; - struct dmareg rq_srcreg; - struct dmareg rq_dstreg; - struct dmareg rq_sgl_srcreg; - struct dmareg rq_sgl_dstreg; - struct dmareg rq_lst_srcreg; - struct dmareg rq_lst_dstreg; - struct dmareg dma_cfg; - struct dmareg dma_chan_en; - struct dmareg dma_id; - struct dmareg dma_test; - struct dmareg res1; - struct dmareg res2; - /* DMA Comp Params - * Param 6 = dma_param[0], Param 5 = dma_param[1], - * Param 4 = dma_param[2] ... - */ - struct dmareg dma_params[6]; -}; - -#define DMA_EN 0x00000001 -#define DMA_DI 0x00000000 -#define DMA_CHANNEL(ch) (0x00000001 << (ch)) -#define DMA_ENABLE_CHAN(ch) ((0x00000001 << (ch)) | \ - ((0x000000001 << (ch)) << 8)) -#define DMA_DISABLE_CHAN(ch) (0x00000000 | \ - ((0x000000001 << (ch)) << 8)) - -#define SATA_DWC_MAX_PORTS 1 -#define SATA_DWC_SCR_OFFSET 0x24 -#define SATA_DWC_REG_OFFSET 0x64 - -struct sata_dwc_regs { - u32 fptagr; - u32 fpbor; - u32 fptcr; - u32 dmacr; - u32 dbtsr; - u32 intpr; - u32 intmr; - u32 errmr; - u32 llcr; - u32 phycr; - u32 physr; - u32 rxbistpd; - u32 rxbistpd1; - u32 rxbistpd2; - u32 txbistpd; - u32 txbistpd1; - u32 txbistpd2; - u32 bistcr; - u32 bistfctr; - u32 bistsr; - u32 bistdecr; - u32 res[15]; - u32 testr; - u32 versionr; - u32 idr; - u32 unimpl[192]; - u32 dmadr[256]; -}; - -#define SATA_DWC_TXFIFO_DEPTH 0x01FF -#define SATA_DWC_RXFIFO_DEPTH 0x01FF - -#define SATA_DWC_DBTSR_MWR(size) ((size / 4) & SATA_DWC_TXFIFO_DEPTH) -#define SATA_DWC_DBTSR_MRD(size) (((size / 4) & \ - SATA_DWC_RXFIFO_DEPTH) << 16) -#define SATA_DWC_INTPR_DMAT 0x00000001 -#define SATA_DWC_INTPR_NEWFP 0x00000002 -#define SATA_DWC_INTPR_PMABRT 0x00000004 -#define SATA_DWC_INTPR_ERR 0x00000008 -#define SATA_DWC_INTPR_NEWBIST 0x00000010 -#define SATA_DWC_INTPR_IPF 0x10000000 -#define SATA_DWC_INTMR_DMATM 0x00000001 -#define SATA_DWC_INTMR_NEWFPM 0x00000002 -#define SATA_DWC_INTMR_PMABRTM 0x00000004 -#define SATA_DWC_INTMR_ERRM 0x00000008 -#define SATA_DWC_INTMR_NEWBISTM 0x00000010 - -#define SATA_DWC_DMACR_TMOD_TXCHEN 0x00000004 -#define SATA_DWC_DMACR_TXRXCH_CLEAR SATA_DWC_DMACR_TMOD_TXCHEN - -#define SATA_DWC_QCMD_MAX 32 - -#define SATA_DWC_SERROR_ERR_BITS 0x0FFF0F03 - -#define HSDEVP_FROM_AP(ap) (struct sata_dwc_device_port*) \ - (ap)->private_data - -struct sata_dwc_device { - struct device *dev; - struct ata_probe_ent *pe; - struct ata_host *host; - u8 *reg_base; - struct sata_dwc_regs *sata_dwc_regs; - int irq_dma; -}; - -struct sata_dwc_device_port { - struct sata_dwc_device *hsdev; - int cmd_issued[SATA_DWC_QCMD_MAX]; - u32 dma_chan[SATA_DWC_QCMD_MAX]; - int dma_pending[SATA_DWC_QCMD_MAX]; -}; - -enum { - SATA_DWC_CMD_ISSUED_NOT = 0, - SATA_DWC_CMD_ISSUED_PEND = 1, - SATA_DWC_CMD_ISSUED_EXEC = 2, - SATA_DWC_CMD_ISSUED_NODATA = 3, - - SATA_DWC_DMA_PENDING_NONE = 0, - SATA_DWC_DMA_PENDING_TX = 1, - SATA_DWC_DMA_PENDING_RX = 2, -}; - -#define msleep(a) udelay(a * 1000) -#define ssleep(a) msleep(a * 1000) - -static int ata_probe_timeout = (ATA_TMOUT_INTERNAL / 100); - -enum sata_dev_state { - SATA_INIT = 0, - SATA_READY = 1, - SATA_NODEVICE = 2, - SATA_ERROR = 3, -}; -enum sata_dev_state dev_state = SATA_INIT; - -static struct ahb_dma_regs *sata_dma_regs = 0; -static struct ata_host *phost; -static struct ata_port ap; -static struct ata_port *pap = ≈ -static struct ata_device ata_device; -static struct sata_dwc_device_port dwc_devp; - -static void *scr_addr_sstatus; -static u32 temp_n_block = 0; - -static unsigned ata_exec_internal(struct ata_device *dev, - struct ata_taskfile *tf, const u8 *cdb, - int dma_dir, unsigned int buflen, - unsigned long timeout); -static unsigned int ata_dev_set_feature(struct ata_device *dev, - u8 enable,u8 feature); -static unsigned int ata_dev_init_params(struct ata_device *dev, - u16 heads, u16 sectors); -static u8 ata_irq_on(struct ata_port *ap); -static struct ata_queued_cmd *__ata_qc_from_tag(struct ata_port *ap, - unsigned int tag); -static int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, - u8 status, int in_wq); -static void ata_tf_to_host(struct ata_port *ap, - const struct ata_taskfile *tf); -static void ata_exec_command(struct ata_port *ap, - const struct ata_taskfile *tf); -static unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc); -static u8 ata_check_altstatus(struct ata_port *ap); -static u8 ata_check_status(struct ata_port *ap); -static void ata_dev_select(struct ata_port *ap, unsigned int device, - unsigned int wait, unsigned int can_sleep); -static void ata_qc_issue(struct ata_queued_cmd *qc); -static void ata_tf_load(struct ata_port *ap, - const struct ata_taskfile *tf); -static int ata_dev_read_sectors(unsigned char* pdata, - unsigned long datalen, u32 block, u32 n_block); -static int ata_dev_write_sectors(unsigned char* pdata, - unsigned long datalen , u32 block, u32 n_block); -static void ata_std_dev_select(struct ata_port *ap, unsigned int device); -static void ata_qc_complete(struct ata_queued_cmd *qc); -static void __ata_qc_complete(struct ata_queued_cmd *qc); -static void fill_result_tf(struct ata_queued_cmd *qc); -static void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf); -static void ata_mmio_data_xfer(struct ata_device *dev, - unsigned char *buf, - unsigned int buflen,int do_write); -static void ata_pio_task(struct ata_port *arg_ap); -static void __ata_port_freeze(struct ata_port *ap); -static int ata_port_freeze(struct ata_port *ap); -static void ata_qc_free(struct ata_queued_cmd *qc); -static void ata_pio_sectors(struct ata_queued_cmd *qc); -static void ata_pio_sector(struct ata_queued_cmd *qc); -static void ata_pio_queue_task(struct ata_port *ap, - void *data,unsigned long delay); -static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq); -static int sata_dwc_softreset(struct ata_port *ap); -static int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, - unsigned int flags, u16 *id); -static int check_sata_dev_state(void); - -static const struct ata_port_info sata_dwc_port_info[] = { - { - .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING | - ATA_FLAG_SRST | ATA_FLAG_NCQ, - .pio_mask = 0x1f, - .mwdma_mask = 0x07, - .udma_mask = 0x7f, - }, -}; - -int init_sata(int dev) -{ - struct sata_dwc_device hsdev; - struct ata_host host; - struct ata_port_info pi = sata_dwc_port_info[0]; - struct ata_link *link; - struct sata_dwc_device_port hsdevp = dwc_devp; - u8 *base = 0; - u8 *sata_dma_regs_addr = 0; - u8 status; - unsigned long base_addr = 0; - int chan = 0; - int rc; - int i; - - phost = &host; - - base = (u8*)SATA_BASE_ADDR; - - hsdev.sata_dwc_regs = (void *__iomem)(base + SATA_DWC_REG_OFFSET); - - host.n_ports = SATA_DWC_MAX_PORTS; - - for (i = 0; i < SATA_DWC_MAX_PORTS; i++) { - ap.pflags |= ATA_PFLAG_INITIALIZING; - ap.flags = ATA_FLAG_DISABLED; - ap.print_id = -1; - ap.ctl = ATA_DEVCTL_OBS; - ap.host = &host; - ap.last_ctl = 0xFF; - - link = &ap.link; - link->ap = ≈ - link->pmp = 0; - link->active_tag = ATA_TAG_POISON; - link->hw_sata_spd_limit = 0; - - ap.port_no = i; - host.ports[i] = ≈ - } - - ap.pio_mask = pi.pio_mask; - ap.mwdma_mask = pi.mwdma_mask; - ap.udma_mask = pi.udma_mask; - ap.flags |= pi.flags; - ap.link.flags |= pi.link_flags; - - host.ports[0]->ioaddr.cmd_addr = base; - host.ports[0]->ioaddr.scr_addr = base + SATA_DWC_SCR_OFFSET; - scr_addr_sstatus = base + SATA_DWC_SCR_OFFSET; - - base_addr = (unsigned long)base; - - host.ports[0]->ioaddr.cmd_addr = (void *)base_addr + 0x00; - host.ports[0]->ioaddr.data_addr = (void *)base_addr + 0x00; - - host.ports[0]->ioaddr.error_addr = (void *)base_addr + 0x04; - host.ports[0]->ioaddr.feature_addr = (void *)base_addr + 0x04; - - host.ports[0]->ioaddr.nsect_addr = (void *)base_addr + 0x08; - - host.ports[0]->ioaddr.lbal_addr = (void *)base_addr + 0x0c; - host.ports[0]->ioaddr.lbam_addr = (void *)base_addr + 0x10; - host.ports[0]->ioaddr.lbah_addr = (void *)base_addr + 0x14; - - host.ports[0]->ioaddr.device_addr = (void *)base_addr + 0x18; - host.ports[0]->ioaddr.command_addr = (void *)base_addr + 0x1c; - host.ports[0]->ioaddr.status_addr = (void *)base_addr + 0x1c; - - host.ports[0]->ioaddr.altstatus_addr = (void *)base_addr + 0x20; - host.ports[0]->ioaddr.ctl_addr = (void *)base_addr + 0x20; - - sata_dma_regs_addr = (u8*)SATA_DMA_REG_ADDR; - sata_dma_regs = (void *__iomem)sata_dma_regs_addr; - - status = ata_check_altstatus(&ap); - - if (status == 0x7f) { - printf("Hard Disk not found.\n"); - dev_state = SATA_NODEVICE; - rc = false; - return rc; - } - - printf("Waiting for device..."); - i = 0; - while (1) { - udelay(10000); - - status = ata_check_altstatus(&ap); - - if ((status & ATA_BUSY) == 0) { - printf("\n"); - break; - } - - i++; - if (i > (ATA_RESET_TIME * 100)) { - printf("** TimeOUT **\n"); - - dev_state = SATA_NODEVICE; - rc = false; - return rc; - } - if ((i >= 100) && ((i % 100) == 0)) - printf("."); - } - - rc = sata_dwc_softreset(&ap); - - if (rc) { - printf("sata_dwc : error. soft reset failed\n"); - return rc; - } - - for (chan = 0; chan < DMA_NUM_CHANS; chan++) { - out_le32(&(sata_dma_regs->interrupt_mask.error.low), - DMA_DISABLE_CHAN(chan)); - - out_le32(&(sata_dma_regs->interrupt_mask.tfr.low), - DMA_DISABLE_CHAN(chan)); - } - - out_le32(&(sata_dma_regs->dma_cfg.low), DMA_DI); - - out_le32(&hsdev.sata_dwc_regs->intmr, - SATA_DWC_INTMR_ERRM | - SATA_DWC_INTMR_PMABRTM); - - /* Unmask the error bits that should trigger - * an error interrupt by setting the error mask register. - */ - out_le32(&hsdev.sata_dwc_regs->errmr, SATA_DWC_SERROR_ERR_BITS); - - hsdev.host = ap.host; - memset(&hsdevp, 0, sizeof(hsdevp)); - hsdevp.hsdev = &hsdev; - - for (i = 0; i < SATA_DWC_QCMD_MAX; i++) - hsdevp.cmd_issued[i] = SATA_DWC_CMD_ISSUED_NOT; - - out_le32((void __iomem *)scr_addr_sstatus + 4, - in_le32((void __iomem *)scr_addr_sstatus + 4)); - - rc = 0; - return rc; -} - -int reset_sata(int dev) -{ - return 0; -} - -static u8 ata_check_altstatus(struct ata_port *ap) -{ - u8 val = 0; - val = readb(ap->ioaddr.altstatus_addr); - return val; -} - -static int sata_dwc_softreset(struct ata_port *ap) -{ - u8 nsect,lbal = 0; - u8 tmp = 0; - struct ata_ioports *ioaddr = &ap->ioaddr; - - in_le32((void *)ap->ioaddr.scr_addr + (SCR_ERROR * 4)); - - writeb(0x55, ioaddr->nsect_addr); - writeb(0xaa, ioaddr->lbal_addr); - writeb(0xaa, ioaddr->nsect_addr); - writeb(0x55, ioaddr->lbal_addr); - writeb(0x55, ioaddr->nsect_addr); - writeb(0xaa, ioaddr->lbal_addr); - - nsect = readb(ioaddr->nsect_addr); - lbal = readb(ioaddr->lbal_addr); - - if ((nsect == 0x55) && (lbal == 0xaa)) { - printf("Device found\n"); - } else { - printf("No device found\n"); - dev_state = SATA_NODEVICE; - return false; - } - - tmp = ATA_DEVICE_OBS; - writeb(tmp, ioaddr->device_addr); - writeb(ap->ctl, ioaddr->ctl_addr); - - udelay(200); - - writeb(ap->ctl | ATA_SRST, ioaddr->ctl_addr); - - udelay(200); - writeb(ap->ctl, ioaddr->ctl_addr); - - msleep(150); - ata_check_status(ap); - - msleep(50); - ata_check_status(ap); - - while (1) { - u8 status = ata_check_status(ap); - - if (!(status & ATA_BUSY)) - break; - - printf("Hard Disk status is BUSY.\n"); - msleep(50); - } - - tmp = ATA_DEVICE_OBS; - writeb(tmp, ioaddr->device_addr); - - nsect = readb(ioaddr->nsect_addr); - lbal = readb(ioaddr->lbal_addr); - - return 0; -} - -static u8 ata_check_status(struct ata_port *ap) -{ - u8 val = 0; - val = readb(ap->ioaddr.status_addr); - return val; -} - -static int ata_id_has_hipm(const u16 *id) -{ - u16 val = id[76]; - - if (val == 0 || val == 0xffff) - return -1; - - return val & (1 << 9); -} - -static int ata_id_has_dipm(const u16 *id) -{ - u16 val = id[78]; - - if (val == 0 || val == 0xffff) - return -1; - - return val & (1 << 3); -} - -int scan_sata(int dev) -{ - int i; - int rc; - u8 status; - const u16 *id; - struct ata_device *ata_dev = &ata_device; - unsigned long pio_mask, mwdma_mask; - char revbuf[7]; - u16 iobuf[ATA_SECTOR_WORDS]; - - memset(iobuf, 0, sizeof(iobuf)); - - if (dev_state == SATA_NODEVICE) - return 1; - - printf("Waiting for device..."); - i = 0; - while (1) { - udelay(10000); - - status = ata_check_altstatus(&ap); - - if ((status & ATA_BUSY) == 0) { - printf("\n"); - break; - } - - i++; - if (i > (ATA_RESET_TIME * 100)) { - printf("** TimeOUT **\n"); - - dev_state = SATA_NODEVICE; - return 1; - } - if ((i >= 100) && ((i % 100) == 0)) - printf("."); - } - - udelay(1000); - - rc = ata_dev_read_id(ata_dev, &ata_dev->class, - ATA_READID_POSTRESET,ata_dev->id); - if (rc) { - printf("sata_dwc : error. failed sata scan\n"); - return 1; - } - - /* SATA drives indicate we have a bridge. We don't know which - * end of the link the bridge is which is a problem - */ - if (ata_id_is_sata(ata_dev->id)) - ap.cbl = ATA_CBL_SATA; - - id = ata_dev->id; - - ata_dev->flags &= ~ATA_DFLAG_CFG_MASK; - ata_dev->max_sectors = 0; - ata_dev->cdb_len = 0; - ata_dev->n_sectors = 0; - ata_dev->cylinders = 0; - ata_dev->heads = 0; - ata_dev->sectors = 0; - - if (id[ATA_ID_FIELD_VALID] & (1 << 1)) { - pio_mask = id[ATA_ID_PIO_MODES] & 0x03; - pio_mask <<= 3; - pio_mask |= 0x7; - } else { - /* If word 64 isn't valid then Word 51 high byte holds - * the PIO timing number for the maximum. Turn it into - * a mask. - */ - u8 mode = (id[ATA_ID_OLD_PIO_MODES] >> 8) & 0xFF; - if (mode < 5) { - pio_mask = (2 << mode) - 1; - } else { - pio_mask = 1; - } - } - - mwdma_mask = id[ATA_ID_MWDMA_MODES] & 0x07; - - if (ata_id_is_cfa(id)) { - int pio = id[163] & 0x7; - int dma = (id[163] >> 3) & 7; - - if (pio) - pio_mask |= (1 << 5); - if (pio > 1) - pio_mask |= (1 << 6); - if (dma) - mwdma_mask |= (1 << 3); - if (dma > 1) - mwdma_mask |= (1 << 4); - } - - if (ata_dev->class == ATA_DEV_ATA) { - if (ata_id_is_cfa(id)) { - if (id[162] & 1) - printf("supports DRM functions and may " - "not be fully accessable.\n"); - strcpy(revbuf, "CFA"); - } else { - if (ata_id_has_tpm(id)) - printf("supports DRM functions and may " - "not be fully accessable.\n"); - } - - ata_dev->n_sectors = ata_id_n_sectors((u16*)id); - - if (ata_dev->id[59] & 0x100) - ata_dev->multi_count = ata_dev->id[59] & 0xff; - - if (ata_id_has_lba(id)) { - char ncq_desc[20]; - - ata_dev->flags |= ATA_DFLAG_LBA; - if (ata_id_has_lba48(id)) { - ata_dev->flags |= ATA_DFLAG_LBA48; - - if (ata_dev->n_sectors >= (1UL << 28) && - ata_id_has_flush_ext(id)) - ata_dev->flags |= ATA_DFLAG_FLUSH_EXT; - } - if (!ata_id_has_ncq(ata_dev->id)) - ncq_desc[0] = '\0'; - - if (ata_dev->horkage & ATA_HORKAGE_NONCQ) - strcpy(ncq_desc, "NCQ (not used)"); - - if (ap.flags & ATA_FLAG_NCQ) - ata_dev->flags |= ATA_DFLAG_NCQ; - } - ata_dev->cdb_len = 16; - } - ata_dev->max_sectors = ATA_MAX_SECTORS; - if (ata_dev->flags & ATA_DFLAG_LBA48) - ata_dev->max_sectors = ATA_MAX_SECTORS_LBA48; - - if (!(ata_dev->horkage & ATA_HORKAGE_IPM)) { - if (ata_id_has_hipm(ata_dev->id)) - ata_dev->flags |= ATA_DFLAG_HIPM; - if (ata_id_has_dipm(ata_dev->id)) - ata_dev->flags |= ATA_DFLAG_DIPM; - } - - if ((ap.cbl == ATA_CBL_SATA) && (!ata_id_is_sata(ata_dev->id))) { - ata_dev->udma_mask &= ATA_UDMA5; - ata_dev->max_sectors = ATA_MAX_SECTORS; - } - - if (ata_dev->horkage & ATA_HORKAGE_DIAGNOSTIC) { - printf("Drive reports diagnostics failure." - "This may indicate a drive\n"); - printf("fault or invalid emulation." - "Contact drive vendor for information.\n"); - } - - rc = check_sata_dev_state(); - - ata_id_c_string(ata_dev->id, - (unsigned char *)sata_dev_desc[dev].revision, - ATA_ID_FW_REV, sizeof(sata_dev_desc[dev].revision)); - ata_id_c_string(ata_dev->id, - (unsigned char *)sata_dev_desc[dev].vendor, - ATA_ID_PROD, sizeof(sata_dev_desc[dev].vendor)); - ata_id_c_string(ata_dev->id, - (unsigned char *)sata_dev_desc[dev].product, - ATA_ID_SERNO, sizeof(sata_dev_desc[dev].product)); - - sata_dev_desc[dev].lba = (u32) ata_dev->n_sectors; - -#ifdef CONFIG_LBA48 - if (ata_dev->id[83] & (1 << 10)) { - sata_dev_desc[dev].lba48 = 1; - } else { - sata_dev_desc[dev].lba48 = 0; - } -#endif - - return 0; -} - -static u8 ata_busy_wait(struct ata_port *ap, - unsigned int bits,unsigned int max) -{ - u8 status; - - do { - udelay(10); - status = ata_check_status(ap); - max--; - } while (status != 0xff && (status & bits) && (max > 0)); - - return status; -} - -static int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, - unsigned int flags, u16 *id) -{ - struct ata_port *ap = pap; - unsigned int class = *p_class; - struct ata_taskfile tf; - unsigned int err_mask = 0; - const char *reason; - int may_fallback = 1, tried_spinup = 0; - u8 status; - int rc; - - status = ata_busy_wait(ap, ATA_BUSY, 30000); - if (status & ATA_BUSY) { - printf("BSY = 0 check. timeout.\n"); - rc = false; - return rc; - } - - ata_dev_select(ap, dev->devno, 1, 1); - -retry: - memset(&tf, 0, sizeof(tf)); - ap->print_id = 1; - ap->flags &= ~ATA_FLAG_DISABLED; - tf.ctl = ap->ctl; - tf.device = ATA_DEVICE_OBS; - tf.command = ATA_CMD_ID_ATA; - tf.protocol = ATA_PROT_PIO; - - /* Some devices choke if TF registers contain garbage. Make - * sure those are properly initialized. - */ - tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; - - /* Device presence detection is unreliable on some - * controllers. Always poll IDENTIFY if available. - */ - tf.flags |= ATA_TFLAG_POLLING; - - temp_n_block = 1; - - err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, - sizeof(id[0]) * ATA_ID_WORDS, 0); - - if (err_mask) { - if (err_mask & AC_ERR_NODEV_HINT) { - printf("NODEV after polling detection\n"); - return -ENOENT; - } - - if ((err_mask == AC_ERR_DEV) && (tf.feature & ATA_ABORTED)) { - /* Device or controller might have reported - * the wrong device class. Give a shot at the - * other IDENTIFY if the current one is - * aborted by the device. - */ - if (may_fallback) { - may_fallback = 0; - - if (class == ATA_DEV_ATA) { - class = ATA_DEV_ATAPI; - } else { - class = ATA_DEV_ATA; - } - goto retry; - } - /* Control reaches here iff the device aborted - * both flavors of IDENTIFYs which happens - * sometimes with phantom devices. - */ - printf("both IDENTIFYs aborted, assuming NODEV\n"); - return -ENOENT; - } - rc = -EIO; - reason = "I/O error"; - goto err_out; - } - - /* Falling back doesn't make sense if ID data was read - * successfully at least once. - */ - may_fallback = 0; - - unsigned int id_cnt; - - for (id_cnt = 0; id_cnt < ATA_ID_WORDS; id_cnt++) - id[id_cnt] = le16_to_cpu(id[id_cnt]); - - - rc = -EINVAL; - reason = "device reports invalid type"; - - if (class == ATA_DEV_ATA) { - if (!ata_id_is_ata(id) && !ata_id_is_cfa(id)) - goto err_out; - } else { - if (ata_id_is_ata(id)) - goto err_out; - } - if (!tried_spinup && (id[2] == 0x37c8 || id[2] == 0x738c)) { - tried_spinup = 1; - /* - * Drive powered-up in standby mode, and requires a specific - * SET_FEATURES spin-up subcommand before it will accept - * anything other than the original IDENTIFY command. - */ - err_mask = ata_dev_set_feature(dev, SETFEATURES_SPINUP, 0); - if (err_mask && id[2] != 0x738c) { - rc = -EIO; - reason = "SPINUP failed"; - goto err_out; - } - /* - * If the drive initially returned incomplete IDENTIFY info, - * we now must reissue the IDENTIFY command. - */ - if (id[2] == 0x37c8) - goto retry; - } - - if ((flags & ATA_READID_POSTRESET) && class == ATA_DEV_ATA) { - /* - * The exact sequence expected by certain pre-ATA4 drives is: - * SRST RESET - * IDENTIFY (optional in early ATA) - * INITIALIZE DEVICE PARAMETERS (later IDE and ATA) - * anything else.. - * Some drives were very specific about that exact sequence. - * - * Note that ATA4 says lba is mandatory so the second check - * shoud never trigger. - */ - if (ata_id_major_version(id) < 4 || !ata_id_has_lba(id)) { - err_mask = ata_dev_init_params(dev, id[3], id[6]); - if (err_mask) { - rc = -EIO; - reason = "INIT_DEV_PARAMS failed"; - goto err_out; - } - - /* current CHS translation info (id[53-58]) might be - * changed. reread the identify device info. - */ - flags &= ~ATA_READID_POSTRESET; - goto retry; - } - } - - *p_class = class; - return 0; - -err_out: - printf("failed to READ ID (%s, err_mask=0x%x)\n", reason, err_mask); - return rc; -} - -static u8 ata_wait_idle(struct ata_port *ap) -{ - u8 status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); - return status; -} - -static void ata_dev_select(struct ata_port *ap, unsigned int device, - unsigned int wait, unsigned int can_sleep) -{ - if (wait) - ata_wait_idle(ap); - - ata_std_dev_select(ap, device); - - if (wait) - ata_wait_idle(ap); -} - -static void ata_std_dev_select(struct ata_port *ap, unsigned int device) -{ - u8 tmp; - - if (device == 0) { - tmp = ATA_DEVICE_OBS; - } else { - tmp = ATA_DEVICE_OBS | ATA_DEV1; - } - - writeb(tmp, ap->ioaddr.device_addr); - - readb(ap->ioaddr.altstatus_addr); - - udelay(1); -} - -static int waiting_for_reg_state(volatile u8 *offset, - int timeout_msec, - u32 sign) -{ - int i; - u32 status; - - for (i = 0; i < timeout_msec; i++) { - status = readl(offset); - if ((status & sign) != 0) - break; - msleep(1); - } - - return (i < timeout_msec) ? 0 : -1; -} - -static void ata_qc_reinit(struct ata_queued_cmd *qc) -{ - qc->dma_dir = DMA_NONE; - qc->flags = 0; - qc->nbytes = qc->extrabytes = qc->curbytes = 0; - qc->n_elem = 0; - qc->err_mask = 0; - qc->sect_size = ATA_SECT_SIZE; - qc->nbytes = ATA_SECT_SIZE * temp_n_block; - - memset(&qc->tf, 0, sizeof(qc->tf)); - qc->tf.ctl = 0; - qc->tf.device = ATA_DEVICE_OBS; - - qc->result_tf.command = ATA_DRDY; - qc->result_tf.feature = 0; -} - -struct ata_queued_cmd *__ata_qc_from_tag(struct ata_port *ap, - unsigned int tag) -{ - if (tag < ATA_MAX_QUEUE) - return &ap->qcmd[tag]; - return NULL; -} - -static void __ata_port_freeze(struct ata_port *ap) -{ - printf("set port freeze.\n"); - ap->pflags |= ATA_PFLAG_FROZEN; -} - -static int ata_port_freeze(struct ata_port *ap) -{ - __ata_port_freeze(ap); - return 0; -} - -unsigned ata_exec_internal(struct ata_device *dev, - struct ata_taskfile *tf, const u8 *cdb, - int dma_dir, unsigned int buflen, - unsigned long timeout) -{ - struct ata_link *link = dev->link; - struct ata_port *ap = pap; - struct ata_queued_cmd *qc; - unsigned int tag, preempted_tag; - u32 preempted_sactive, preempted_qc_active; - int preempted_nr_active_links; - unsigned int err_mask; - int rc = 0; - u8 status; - - status = ata_busy_wait(ap, ATA_BUSY, 300000); - if (status & ATA_BUSY) { - printf("BSY = 0 check. timeout.\n"); - rc = false; - return rc; - } - - if (ap->pflags & ATA_PFLAG_FROZEN) - return AC_ERR_SYSTEM; - - tag = ATA_TAG_INTERNAL; - - if (test_and_set_bit(tag, &ap->qc_allocated)) { - rc = false; - return rc; - } - - qc = __ata_qc_from_tag(ap, tag); - qc->tag = tag; - qc->ap = ap; - qc->dev = dev; - - ata_qc_reinit(qc); - - preempted_tag = link->active_tag; - preempted_sactive = link->sactive; - preempted_qc_active = ap->qc_active; - preempted_nr_active_links = ap->nr_active_links; - link->active_tag = ATA_TAG_POISON; - link->sactive = 0; - ap->qc_active = 0; - ap->nr_active_links = 0; - - qc->tf = *tf; - if (cdb) - memcpy(qc->cdb, cdb, ATAPI_CDB_LEN); - qc->flags |= ATA_QCFLAG_RESULT_TF; - qc->dma_dir = dma_dir; - qc->private_data = 0; - - ata_qc_issue(qc); - - if (!timeout) - timeout = ata_probe_timeout * 1000 / HZ; - - status = ata_busy_wait(ap, ATA_BUSY, 30000); - if (status & ATA_BUSY) { - printf("BSY = 0 check. timeout.\n"); - printf("altstatus = 0x%x.\n", status); - qc->err_mask |= AC_ERR_OTHER; - return qc->err_mask; - } - - if (waiting_for_reg_state(ap->ioaddr.altstatus_addr, 1000, 0x8)) { - u8 status = 0; - u8 errorStatus = 0; - - status = readb(ap->ioaddr.altstatus_addr); - if ((status & 0x01) != 0) { - errorStatus = readb(ap->ioaddr.feature_addr); - if (errorStatus == 0x04 && - qc->tf.command == ATA_CMD_PIO_READ_EXT){ - printf("Hard Disk doesn't support LBA48\n"); - dev_state = SATA_ERROR; - qc->err_mask |= AC_ERR_OTHER; - return qc->err_mask; - } - } - qc->err_mask |= AC_ERR_OTHER; - return qc->err_mask; - } - - status = ata_busy_wait(ap, ATA_BUSY, 10); - if (status & ATA_BUSY) { - printf("BSY = 0 check. timeout.\n"); - qc->err_mask |= AC_ERR_OTHER; - return qc->err_mask; - } - - ata_pio_task(ap); - - if (!rc) { - if (qc->flags & ATA_QCFLAG_ACTIVE) { - qc->err_mask |= AC_ERR_TIMEOUT; - ata_port_freeze(ap); - } - } - - if (qc->flags & ATA_QCFLAG_FAILED) { - if (qc->result_tf.command & (ATA_ERR | ATA_DF)) - qc->err_mask |= AC_ERR_DEV; - - if (!qc->err_mask) - qc->err_mask |= AC_ERR_OTHER; - - if (qc->err_mask & ~AC_ERR_OTHER) - qc->err_mask &= ~AC_ERR_OTHER; - } - - *tf = qc->result_tf; - err_mask = qc->err_mask; - ata_qc_free(qc); - link->active_tag = preempted_tag; - link->sactive = preempted_sactive; - ap->qc_active = preempted_qc_active; - ap->nr_active_links = preempted_nr_active_links; - - if (ap->flags & ATA_FLAG_DISABLED) { - err_mask |= AC_ERR_SYSTEM; - ap->flags &= ~ATA_FLAG_DISABLED; - } - - return err_mask; -} - -static void ata_qc_issue(struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - struct ata_link *link = qc->dev->link; - u8 prot = qc->tf.protocol; - - if (ata_is_ncq(prot)) { - if (!link->sactive) - ap->nr_active_links++; - link->sactive |= 1 << qc->tag; - } else { - ap->nr_active_links++; - link->active_tag = qc->tag; - } - - qc->flags |= ATA_QCFLAG_ACTIVE; - ap->qc_active |= 1 << qc->tag; - - if (qc->dev->flags & ATA_DFLAG_SLEEPING) { - msleep(1); - return; - } - - qc->err_mask |= ata_qc_issue_prot(qc); - if (qc->err_mask) - goto err; - - return; -err: - ata_qc_complete(qc); -} - -static unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - - if (ap->flags & ATA_FLAG_PIO_POLLING) { - switch (qc->tf.protocol) { - case ATA_PROT_PIO: - case ATA_PROT_NODATA: - case ATAPI_PROT_PIO: - case ATAPI_PROT_NODATA: - qc->tf.flags |= ATA_TFLAG_POLLING; - break; - default: - break; - } - } - - ata_dev_select(ap, qc->dev->devno, 1, 0); - - switch (qc->tf.protocol) { - case ATA_PROT_PIO: - if (qc->tf.flags & ATA_TFLAG_POLLING) - qc->tf.ctl |= ATA_NIEN; - - ata_tf_to_host(ap, &qc->tf); - - ap->hsm_task_state = HSM_ST; - - if (qc->tf.flags & ATA_TFLAG_POLLING) - ata_pio_queue_task(ap, qc, 0); - - break; - - default: - return AC_ERR_SYSTEM; - } - - return 0; -} - -static void ata_tf_to_host(struct ata_port *ap, - const struct ata_taskfile *tf) -{ - ata_tf_load(ap, tf); - ata_exec_command(ap, tf); -} - -static void ata_tf_load(struct ata_port *ap, - const struct ata_taskfile *tf) -{ - struct ata_ioports *ioaddr = &ap->ioaddr; - unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; - - if (tf->ctl != ap->last_ctl) { - if (ioaddr->ctl_addr) - writeb(tf->ctl, ioaddr->ctl_addr); - ap->last_ctl = tf->ctl; - ata_wait_idle(ap); - } - - if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { - writeb(tf->hob_feature, ioaddr->feature_addr); - writeb(tf->hob_nsect, ioaddr->nsect_addr); - writeb(tf->hob_lbal, ioaddr->lbal_addr); - writeb(tf->hob_lbam, ioaddr->lbam_addr); - writeb(tf->hob_lbah, ioaddr->lbah_addr); - } - - if (is_addr) { - writeb(tf->feature, ioaddr->feature_addr); - writeb(tf->nsect, ioaddr->nsect_addr); - writeb(tf->lbal, ioaddr->lbal_addr); - writeb(tf->lbam, ioaddr->lbam_addr); - writeb(tf->lbah, ioaddr->lbah_addr); - } - - if (tf->flags & ATA_TFLAG_DEVICE) - writeb(tf->device, ioaddr->device_addr); - - ata_wait_idle(ap); -} - -static void ata_exec_command(struct ata_port *ap, - const struct ata_taskfile *tf) -{ - writeb(tf->command, ap->ioaddr.command_addr); - - readb(ap->ioaddr.altstatus_addr); - - udelay(1); -} - -static void ata_pio_queue_task(struct ata_port *ap, - void *data,unsigned long delay) -{ - ap->port_task_data = data; -} - -static unsigned int ac_err_mask(u8 status) -{ - if (status & (ATA_BUSY | ATA_DRQ)) - return AC_ERR_HSM; - if (status & (ATA_ERR | ATA_DF)) - return AC_ERR_DEV; - return 0; -} - -static unsigned int __ac_err_mask(u8 status) -{ - unsigned int mask = ac_err_mask(status); - if (mask == 0) - return AC_ERR_OTHER; - return mask; -} - -static void ata_pio_task(struct ata_port *arg_ap) -{ - struct ata_port *ap = arg_ap; - struct ata_queued_cmd *qc = ap->port_task_data; - u8 status; - int poll_next; - -fsm_start: - /* - * This is purely heuristic. This is a fast path. - * Sometimes when we enter, BSY will be cleared in - * a chk-status or two. If not, the drive is probably seeking - * or something. Snooze for a couple msecs, then - * chk-status again. If still busy, queue delayed work. - */ - status = ata_busy_wait(ap, ATA_BUSY, 5); - if (status & ATA_BUSY) { - msleep(2); - status = ata_busy_wait(ap, ATA_BUSY, 10); - if (status & ATA_BUSY) { - ata_pio_queue_task(ap, qc, ATA_SHORT_PAUSE); - return; - } - } - - poll_next = ata_hsm_move(ap, qc, status, 1); - - /* another command or interrupt handler - * may be running at this point. - */ - if (poll_next) - goto fsm_start; -} - -static int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, - u8 status, int in_wq) -{ - int poll_next; - -fsm_start: - switch (ap->hsm_task_state) { - case HSM_ST_FIRST: - poll_next = (qc->tf.flags & ATA_TFLAG_POLLING); - - if ((status & ATA_DRQ) == 0) { - if (status & (ATA_ERR | ATA_DF)) { - qc->err_mask |= AC_ERR_DEV; - } else { - qc->err_mask |= AC_ERR_HSM; - } - ap->hsm_task_state = HSM_ST_ERR; - goto fsm_start; - } - - /* Device should not ask for data transfer (DRQ=1) - * when it finds something wrong. - * We ignore DRQ here and stop the HSM by - * changing hsm_task_state to HSM_ST_ERR and - * let the EH abort the command or reset the device. - */ - if (status & (ATA_ERR | ATA_DF)) { - if (!(qc->dev->horkage & ATA_HORKAGE_STUCK_ERR)) { - printf("DRQ=1 with device error, " - "dev_stat 0x%X\n", status); - qc->err_mask |= AC_ERR_HSM; - ap->hsm_task_state = HSM_ST_ERR; - goto fsm_start; - } - } - - if (qc->tf.protocol == ATA_PROT_PIO) { - /* PIO data out protocol. - * send first data block. - */ - /* ata_pio_sectors() might change the state - * to HSM_ST_LAST. so, the state is changed here - * before ata_pio_sectors(). - */ - ap->hsm_task_state = HSM_ST; - ata_pio_sectors(qc); - } else { - printf("protocol is not ATA_PROT_PIO \n"); - } - break; - - case HSM_ST: - if ((status & ATA_DRQ) == 0) { - if (status & (ATA_ERR | ATA_DF)) { - qc->err_mask |= AC_ERR_DEV; - } else { - /* HSM violation. Let EH handle this. - * Phantom devices also trigger this - * condition. Mark hint. - */ - qc->err_mask |= AC_ERR_HSM | AC_ERR_NODEV_HINT; - } - - ap->hsm_task_state = HSM_ST_ERR; - goto fsm_start; - } - /* For PIO reads, some devices may ask for - * data transfer (DRQ=1) alone with ERR=1. - * We respect DRQ here and transfer one - * block of junk data before changing the - * hsm_task_state to HSM_ST_ERR. - * - * For PIO writes, ERR=1 DRQ=1 doesn't make - * sense since the data block has been - * transferred to the device. - */ - if (status & (ATA_ERR | ATA_DF)) { - qc->err_mask |= AC_ERR_DEV; - - if (!(qc->tf.flags & ATA_TFLAG_WRITE)) { - ata_pio_sectors(qc); - status = ata_wait_idle(ap); - } - - if (status & (ATA_BUSY | ATA_DRQ)) - qc->err_mask |= AC_ERR_HSM; - - /* ata_pio_sectors() might change the - * state to HSM_ST_LAST. so, the state - * is changed after ata_pio_sectors(). - */ - ap->hsm_task_state = HSM_ST_ERR; - goto fsm_start; - } - - ata_pio_sectors(qc); - if (ap->hsm_task_state == HSM_ST_LAST && - (!(qc->tf.flags & ATA_TFLAG_WRITE))) { - status = ata_wait_idle(ap); - goto fsm_start; - } - - poll_next = 1; - break; - - case HSM_ST_LAST: - if (!ata_ok(status)) { - qc->err_mask |= __ac_err_mask(status); - ap->hsm_task_state = HSM_ST_ERR; - goto fsm_start; - } - - ap->hsm_task_state = HSM_ST_IDLE; - - ata_hsm_qc_complete(qc, in_wq); - - poll_next = 0; - break; - - case HSM_ST_ERR: - /* make sure qc->err_mask is available to - * know what's wrong and recover - */ - ap->hsm_task_state = HSM_ST_IDLE; - - ata_hsm_qc_complete(qc, in_wq); - - poll_next = 0; - break; - default: - poll_next = 0; - } - - return poll_next; -} - -static void ata_pio_sectors(struct ata_queued_cmd *qc) -{ - struct ata_port *ap; - ap = pap; - qc->pdata = ap->pdata; - - ata_pio_sector(qc); - - readb(qc->ap->ioaddr.altstatus_addr); - udelay(1); -} - -static void ata_pio_sector(struct ata_queued_cmd *qc) -{ - int do_write = (qc->tf.flags & ATA_TFLAG_WRITE); - struct ata_port *ap = qc->ap; - unsigned int offset; - unsigned char *buf; - char temp_data_buf[512]; - - if (qc->curbytes == qc->nbytes - qc->sect_size) - ap->hsm_task_state = HSM_ST_LAST; - - offset = qc->curbytes; - - switch (qc->tf.command) { - case ATA_CMD_ID_ATA: - buf = (unsigned char *)&ata_device.id[0]; - break; - case ATA_CMD_PIO_READ_EXT: - case ATA_CMD_PIO_READ: - case ATA_CMD_PIO_WRITE_EXT: - case ATA_CMD_PIO_WRITE: - buf = qc->pdata + offset; - break; - default: - buf = (unsigned char *)&temp_data_buf[0]; - } - - ata_mmio_data_xfer(qc->dev, buf, qc->sect_size, do_write); - - qc->curbytes += qc->sect_size; - -} - -static void ata_mmio_data_xfer(struct ata_device *dev, unsigned char *buf, - unsigned int buflen, int do_write) -{ - struct ata_port *ap = pap; - void __iomem *data_addr = ap->ioaddr.data_addr; - unsigned int words = buflen >> 1; - u16 *buf16 = (u16 *)buf; - unsigned int i = 0; - - udelay(100); - if (do_write) { - for (i = 0; i < words; i++) - writew(le16_to_cpu(buf16[i]), data_addr); - } else { - for (i = 0; i < words; i++) - buf16[i] = cpu_to_le16(readw(data_addr)); - } - - if (buflen & 0x01) { - __le16 align_buf[1] = { 0 }; - unsigned char *trailing_buf = buf + buflen - 1; - - if (do_write) { - memcpy(align_buf, trailing_buf, 1); - writew(le16_to_cpu(align_buf[0]), data_addr); - } else { - align_buf[0] = cpu_to_le16(readw(data_addr)); - memcpy(trailing_buf, align_buf, 1); - } - } -} - -static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq) -{ - struct ata_port *ap = qc->ap; - - if (in_wq) { - /* EH might have kicked in while host lock is - * released. - */ - qc = &ap->qcmd[qc->tag]; - if (qc) { - if (!(qc->err_mask & AC_ERR_HSM)) { - ata_irq_on(ap); - ata_qc_complete(qc); - } else { - ata_port_freeze(ap); - } - } - } else { - if (!(qc->err_mask & AC_ERR_HSM)) { - ata_qc_complete(qc); - } else { - ata_port_freeze(ap); - } - } -} - -static u8 ata_irq_on(struct ata_port *ap) -{ - struct ata_ioports *ioaddr = &ap->ioaddr; - u8 tmp; - - ap->ctl &= ~ATA_NIEN; - ap->last_ctl = ap->ctl; - - if (ioaddr->ctl_addr) - writeb(ap->ctl, ioaddr->ctl_addr); - - tmp = ata_wait_idle(ap); - - return tmp; -} - -static unsigned int ata_tag_internal(unsigned int tag) -{ - return tag == ATA_MAX_QUEUE - 1; -} - -static void ata_qc_complete(struct ata_queued_cmd *qc) -{ - struct ata_device *dev = qc->dev; - if (qc->err_mask) - qc->flags |= ATA_QCFLAG_FAILED; - - if (qc->flags & ATA_QCFLAG_FAILED) { - if (!ata_tag_internal(qc->tag)) { - fill_result_tf(qc); - return; - } - } - if (qc->flags & ATA_QCFLAG_RESULT_TF) - fill_result_tf(qc); - - /* Some commands need post-processing after successful - * completion. - */ - switch (qc->tf.command) { - case ATA_CMD_SET_FEATURES: - if (qc->tf.feature != SETFEATURES_WC_ON && - qc->tf.feature != SETFEATURES_WC_OFF) - break; - case ATA_CMD_INIT_DEV_PARAMS: - case ATA_CMD_SET_MULTI: - break; - - case ATA_CMD_SLEEP: - dev->flags |= ATA_DFLAG_SLEEPING; - break; - } - - __ata_qc_complete(qc); -} - -static void fill_result_tf(struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - - qc->result_tf.flags = qc->tf.flags; - ata_tf_read(ap, &qc->result_tf); -} - -static void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) -{ - struct ata_ioports *ioaddr = &ap->ioaddr; - - tf->command = ata_check_status(ap); - tf->feature = readb(ioaddr->error_addr); - tf->nsect = readb(ioaddr->nsect_addr); - tf->lbal = readb(ioaddr->lbal_addr); - tf->lbam = readb(ioaddr->lbam_addr); - tf->lbah = readb(ioaddr->lbah_addr); - tf->device = readb(ioaddr->device_addr); - - if (tf->flags & ATA_TFLAG_LBA48) { - if (ioaddr->ctl_addr) { - writeb(tf->ctl | ATA_HOB, ioaddr->ctl_addr); - - tf->hob_feature = readb(ioaddr->error_addr); - tf->hob_nsect = readb(ioaddr->nsect_addr); - tf->hob_lbal = readb(ioaddr->lbal_addr); - tf->hob_lbam = readb(ioaddr->lbam_addr); - tf->hob_lbah = readb(ioaddr->lbah_addr); - - writeb(tf->ctl, ioaddr->ctl_addr); - ap->last_ctl = tf->ctl; - } else { - printf("sata_dwc warnning register read.\n"); - } - } -} - -static void __ata_qc_complete(struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - struct ata_link *link = qc->dev->link; - - link->active_tag = ATA_TAG_POISON; - ap->nr_active_links--; - - if (qc->flags & ATA_QCFLAG_CLEAR_EXCL && ap->excl_link == link) - ap->excl_link = NULL; - - qc->flags &= ~ATA_QCFLAG_ACTIVE; - ap->qc_active &= ~(1 << qc->tag); -} - -static void ata_qc_free(struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - unsigned int tag; - qc->flags = 0; - tag = qc->tag; - if (tag < ATA_MAX_QUEUE) { - qc->tag = ATA_TAG_POISON; - clear_bit(tag, &ap->qc_allocated); - } -} - -static int check_sata_dev_state(void) -{ - unsigned long datalen; - unsigned char *pdata; - int ret = 0; - int i = 0; - char temp_data_buf[512]; - - while (1) { - udelay(10000); - - pdata = (unsigned char*)&temp_data_buf[0]; - datalen = 512; - - ret = ata_dev_read_sectors(pdata, datalen, 0, 1); - - if (ret == true) - break; - - i++; - if (i > (ATA_RESET_TIME * 100)) { - printf("** TimeOUT **\n"); - dev_state = SATA_NODEVICE; - return false; - } - - if ((i >= 100) && ((i % 100) == 0)) - printf("."); - } - - dev_state = SATA_READY; - - return true; -} - -static unsigned int ata_dev_set_feature(struct ata_device *dev, - u8 enable, u8 feature) -{ - struct ata_taskfile tf; - struct ata_port *ap; - ap = pap; - unsigned int err_mask; - - memset(&tf, 0, sizeof(tf)); - tf.ctl = ap->ctl; - - tf.device = ATA_DEVICE_OBS; - tf.command = ATA_CMD_SET_FEATURES; - tf.feature = enable; - tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; - tf.protocol = ATA_PROT_NODATA; - tf.nsect = feature; - - err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, 0, 0); - - return err_mask; -} - -static unsigned int ata_dev_init_params(struct ata_device *dev, - u16 heads, u16 sectors) -{ - struct ata_taskfile tf; - struct ata_port *ap; - ap = pap; - unsigned int err_mask; - - if (sectors < 1 || sectors > 255 || heads < 1 || heads > 16) - return AC_ERR_INVALID; - - memset(&tf, 0, sizeof(tf)); - tf.ctl = ap->ctl; - tf.device = ATA_DEVICE_OBS; - tf.command = ATA_CMD_INIT_DEV_PARAMS; - tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; - tf.protocol = ATA_PROT_NODATA; - tf.nsect = sectors; - tf.device |= (heads - 1) & 0x0f; - - err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, 0, 0); - - if (err_mask == AC_ERR_DEV && (tf.feature & ATA_ABORTED)) - err_mask = 0; - - return err_mask; -} - -#if defined(CONFIG_SATA_DWC) && !defined(CONFIG_LBA48) -#define SATA_MAX_READ_BLK 0xFF -#else -#define SATA_MAX_READ_BLK 0xFFFF -#endif - -ulong sata_read(int device, ulong blknr, lbaint_t blkcnt, void *buffer) -{ - ulong start,blks, buf_addr; - unsigned short smallblks; - unsigned long datalen; - unsigned char *pdata; - device &= 0xff; - - u32 block = 0; - u32 n_block = 0; - - if (dev_state != SATA_READY) - return 0; - - buf_addr = (unsigned long)buffer; - start = blknr; - blks = blkcnt; - do { - pdata = (unsigned char *)buf_addr; - if (blks > SATA_MAX_READ_BLK) { - datalen = sata_dev_desc[device].blksz * SATA_MAX_READ_BLK; - smallblks = SATA_MAX_READ_BLK; - - block = (u32)start; - n_block = (u32)smallblks; - - start += SATA_MAX_READ_BLK; - blks -= SATA_MAX_READ_BLK; - } else { - datalen = sata_dev_desc[device].blksz * SATA_MAX_READ_BLK; - datalen = sata_dev_desc[device].blksz * blks; - smallblks = (unsigned short)blks; - - block = (u32)start; - n_block = (u32)smallblks; - - start += blks; - blks = 0; - } - - if (ata_dev_read_sectors(pdata, datalen, block, n_block) != true) { - printf("sata_dwc : Hard disk read error.\n"); - blkcnt -= blks; - break; - } - buf_addr += datalen; - } while (blks != 0); - - return (blkcnt); -} - -static int ata_dev_read_sectors(unsigned char *pdata, unsigned long datalen, - u32 block, u32 n_block) -{ - struct ata_port *ap = pap; - struct ata_device *dev = &ata_device; - struct ata_taskfile tf; - unsigned int class = ATA_DEV_ATA; - unsigned int err_mask = 0; - const char *reason; - int may_fallback = 1; - - if (dev_state == SATA_ERROR) - return false; - - ata_dev_select(ap, dev->devno, 1, 1); - -retry: - memset(&tf, 0, sizeof(tf)); - tf.ctl = ap->ctl; - ap->print_id = 1; - ap->flags &= ~ATA_FLAG_DISABLED; - - ap->pdata = pdata; - - tf.device = ATA_DEVICE_OBS; - - temp_n_block = n_block; - -#ifdef CONFIG_LBA48 - tf.command = ATA_CMD_PIO_READ_EXT; - tf.flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48; - - tf.hob_feature = 31; - tf.feature = 31; - tf.hob_nsect = (n_block >> 8) & 0xff; - tf.nsect = n_block & 0xff; - - tf.hob_lbah = 0x0; - tf.hob_lbam = 0x0; - tf.hob_lbal = (block >> 24) & 0xff; - tf.lbah = (block >> 16) & 0xff; - tf.lbam = (block >> 8) & 0xff; - tf.lbal = block & 0xff; - - tf.device = 1 << 6; - if (tf.flags & ATA_TFLAG_FUA) - tf.device |= 1 << 7; -#else - tf.command = ATA_CMD_PIO_READ; - tf.flags |= ATA_TFLAG_LBA ; - - tf.feature = 31; - tf.nsect = n_block & 0xff; - - tf.lbah = (block >> 16) & 0xff; - tf.lbam = (block >> 8) & 0xff; - tf.lbal = block & 0xff; - - tf.device = (block >> 24) & 0xf; - - tf.device |= 1 << 6; - if (tf.flags & ATA_TFLAG_FUA) - tf.device |= 1 << 7; - -#endif - - tf.protocol = ATA_PROT_PIO; - - /* Some devices choke if TF registers contain garbage. Make - * sure those are properly initialized. - */ - tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; - tf.flags |= ATA_TFLAG_POLLING; - - err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, 0, 0); - - if (err_mask) { - if (err_mask & AC_ERR_NODEV_HINT) { - printf("READ_SECTORS NODEV after polling detection\n"); - return -ENOENT; - } - - if ((err_mask == AC_ERR_DEV) && (tf.feature & ATA_ABORTED)) { - /* Device or controller might have reported - * the wrong device class. Give a shot at the - * other IDENTIFY if the current one is - * aborted by the device. - */ - if (may_fallback) { - may_fallback = 0; - - if (class == ATA_DEV_ATA) { - class = ATA_DEV_ATAPI; - } else { - class = ATA_DEV_ATA; - } - goto retry; - } - /* Control reaches here iff the device aborted - * both flavors of IDENTIFYs which happens - * sometimes with phantom devices. - */ - printf("both IDENTIFYs aborted, assuming NODEV\n"); - return -ENOENT; - } - - reason = "I/O error"; - goto err_out; - } - - return true; - -err_out: - printf("failed to READ SECTORS (%s, err_mask=0x%x)\n", reason, err_mask); - return false; -} - -#if defined(CONFIG_SATA_DWC) && !defined(CONFIG_LBA48) -#define SATA_MAX_WRITE_BLK 0xFF -#else -#define SATA_MAX_WRITE_BLK 0xFFFF -#endif - -ulong sata_write(int device, ulong blknr, lbaint_t blkcnt, const void *buffer) -{ - ulong start,blks, buf_addr; - unsigned short smallblks; - unsigned long datalen; - unsigned char *pdata; - device &= 0xff; - - - u32 block = 0; - u32 n_block = 0; - - if (dev_state != SATA_READY) - return 0; - - buf_addr = (unsigned long)buffer; - start = blknr; - blks = blkcnt; - do { - pdata = (unsigned char *)buf_addr; - if (blks > SATA_MAX_WRITE_BLK) { - datalen = sata_dev_desc[device].blksz * SATA_MAX_WRITE_BLK; - smallblks = SATA_MAX_WRITE_BLK; - - block = (u32)start; - n_block = (u32)smallblks; - - start += SATA_MAX_WRITE_BLK; - blks -= SATA_MAX_WRITE_BLK; - } else { - datalen = sata_dev_desc[device].blksz * blks; - smallblks = (unsigned short)blks; - - block = (u32)start; - n_block = (u32)smallblks; - - start += blks; - blks = 0; - } - - if (ata_dev_write_sectors(pdata, datalen, block, n_block) != true) { - printf("sata_dwc : Hard disk read error.\n"); - blkcnt -= blks; - break; - } - buf_addr += datalen; - } while (blks != 0); - - return (blkcnt); -} - -static int ata_dev_write_sectors(unsigned char* pdata, unsigned long datalen, - u32 block, u32 n_block) -{ - struct ata_port *ap = pap; - struct ata_device *dev = &ata_device; - struct ata_taskfile tf; - unsigned int class = ATA_DEV_ATA; - unsigned int err_mask = 0; - const char *reason; - int may_fallback = 1; - - if (dev_state == SATA_ERROR) - return false; - - ata_dev_select(ap, dev->devno, 1, 1); - -retry: - memset(&tf, 0, sizeof(tf)); - tf.ctl = ap->ctl; - ap->print_id = 1; - ap->flags &= ~ATA_FLAG_DISABLED; - - ap->pdata = pdata; - - tf.device = ATA_DEVICE_OBS; - - temp_n_block = n_block; - - -#ifdef CONFIG_LBA48 - tf.command = ATA_CMD_PIO_WRITE_EXT; - tf.flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48 | ATA_TFLAG_WRITE; - - tf.hob_feature = 31; - tf.feature = 31; - tf.hob_nsect = (n_block >> 8) & 0xff; - tf.nsect = n_block & 0xff; - - tf.hob_lbah = 0x0; - tf.hob_lbam = 0x0; - tf.hob_lbal = (block >> 24) & 0xff; - tf.lbah = (block >> 16) & 0xff; - tf.lbam = (block >> 8) & 0xff; - tf.lbal = block & 0xff; - - tf.device = 1 << 6; - if (tf.flags & ATA_TFLAG_FUA) - tf.device |= 1 << 7; -#else - tf.command = ATA_CMD_PIO_WRITE; - tf.flags |= ATA_TFLAG_LBA | ATA_TFLAG_WRITE; - - tf.feature = 31; - tf.nsect = n_block & 0xff; - - tf.lbah = (block >> 16) & 0xff; - tf.lbam = (block >> 8) & 0xff; - tf.lbal = block & 0xff; - - tf.device = (block >> 24) & 0xf; - - tf.device |= 1 << 6; - if (tf.flags & ATA_TFLAG_FUA) - tf.device |= 1 << 7; - -#endif - - tf.protocol = ATA_PROT_PIO; - - /* Some devices choke if TF registers contain garbage. Make - * sure those are properly initialized. - */ - tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; - tf.flags |= ATA_TFLAG_POLLING; - - err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, 0, 0); - - if (err_mask) { - if (err_mask & AC_ERR_NODEV_HINT) { - printf("READ_SECTORS NODEV after polling detection\n"); - return -ENOENT; - } - - if ((err_mask == AC_ERR_DEV) && (tf.feature & ATA_ABORTED)) { - /* Device or controller might have reported - * the wrong device class. Give a shot at the - * other IDENTIFY if the current one is - * aborted by the device. - */ - if (may_fallback) { - may_fallback = 0; - - if (class == ATA_DEV_ATA) { - class = ATA_DEV_ATAPI; - } else { - class = ATA_DEV_ATA; - } - goto retry; - } - /* Control reaches here iff the device aborted - * both flavors of IDENTIFYs which happens - * sometimes with phantom devices. - */ - printf("both IDENTIFYs aborted, assuming NODEV\n"); - return -ENOENT; - } - - reason = "I/O error"; - goto err_out; - } - - return true; - -err_out: - printf("failed to WRITE SECTORS (%s, err_mask=0x%x)\n", reason, err_mask); - return false; -} diff --git a/drivers/block/sata_dwc.h b/drivers/block/sata_dwc.h deleted file mode 100644 index e2d9e0c..0000000 --- a/drivers/block/sata_dwc.h +++ /dev/null @@ -1,465 +0,0 @@ -/* - * sata_dwc.h - * - * Synopsys DesignWare Cores (DWC) SATA host driver - * - * Author: Mark Miesfeld - * - * Ported from 2.6.19.2 to 2.6.25/26 by Stefan Roese - * Copyright 2008 DENX Software Engineering - * - * Based on versions provided by AMCC and Synopsys which are: - * Copyright 2006 Applied Micro Circuits Corporation - * COPYRIGHT (C) 2005 SYNOPSYS, INC. ALL RIGHTS RESERVED - * - * SPDX-License-Identifier: GPL-2.0+ - */ -/* - * SATA support based on the chip canyonlands. - * - * 04-17-2009 - * The local version of this driver for the canyonlands board - * does not use interrupts but polls the chip instead. - */ - - -#ifndef _SATA_DWC_H_ -#define _SATA_DWC_H_ - -#define __U_BOOT__ - -#define HZ 100 -#define READ 0 -#define WRITE 1 - -enum { - ATA_READID_POSTRESET = (1 << 0), - - ATA_DNXFER_PIO = 0, - ATA_DNXFER_DMA = 1, - ATA_DNXFER_40C = 2, - ATA_DNXFER_FORCE_PIO = 3, - ATA_DNXFER_FORCE_PIO0 = 4, - - ATA_DNXFER_QUIET = (1 << 31), -}; - -enum hsm_task_states { - HSM_ST_IDLE, - HSM_ST_FIRST, - HSM_ST, - HSM_ST_LAST, - HSM_ST_ERR, -}; - -#define ATA_SHORT_PAUSE ((HZ >> 6) + 1) - -struct ata_queued_cmd { - struct ata_port *ap; - struct ata_device *dev; - - struct ata_taskfile tf; - u8 cdb[ATAPI_CDB_LEN]; - unsigned long flags; - unsigned int tag; - unsigned int n_elem; - - int dma_dir; - unsigned int sect_size; - - unsigned int nbytes; - unsigned int extrabytes; - unsigned int curbytes; - - unsigned int err_mask; - struct ata_taskfile result_tf; - - void *private_data; -#ifndef __U_BOOT__ - void *lldd_task; -#endif - unsigned char *pdata; -}; - -typedef void (*ata_qc_cb_t) (struct ata_queued_cmd *qc); - -#define ATA_TAG_POISON 0xfafbfcfdU - -enum { - LIBATA_MAX_PRD = ATA_MAX_PRD / 2, - LIBATA_DUMB_MAX_PRD = ATA_MAX_PRD / 4, - ATA_MAX_PORTS = 8, - ATA_DEF_QUEUE = 1, - ATA_MAX_QUEUE = 32, - ATA_TAG_INTERNAL = ATA_MAX_QUEUE - 1, - ATA_MAX_BUS = 2, - ATA_DEF_BUSY_WAIT = 10000, - - ATAPI_MAX_DRAIN = 16 << 10, - - ATA_SHT_EMULATED = 1, - ATA_SHT_CMD_PER_LUN = 1, - ATA_SHT_THIS_ID = -1, - ATA_SHT_USE_CLUSTERING = 1, - - ATA_DFLAG_LBA = (1 << 0), - ATA_DFLAG_LBA48 = (1 << 1), - ATA_DFLAG_CDB_INTR = (1 << 2), - ATA_DFLAG_NCQ = (1 << 3), - ATA_DFLAG_FLUSH_EXT = (1 << 4), - ATA_DFLAG_ACPI_PENDING = (1 << 5), - ATA_DFLAG_ACPI_FAILED = (1 << 6), - ATA_DFLAG_AN = (1 << 7), - ATA_DFLAG_HIPM = (1 << 8), - ATA_DFLAG_DIPM = (1 << 9), - ATA_DFLAG_DMADIR = (1 << 10), - ATA_DFLAG_CFG_MASK = (1 << 12) - 1, - - ATA_DFLAG_PIO = (1 << 12), - ATA_DFLAG_NCQ_OFF = (1 << 13), - ATA_DFLAG_SPUNDOWN = (1 << 14), - ATA_DFLAG_SLEEPING = (1 << 15), - ATA_DFLAG_DUBIOUS_XFER = (1 << 16), - ATA_DFLAG_INIT_MASK = (1 << 24) - 1, - - ATA_DFLAG_DETACH = (1 << 24), - ATA_DFLAG_DETACHED = (1 << 25), - - ATA_LFLAG_HRST_TO_RESUME = (1 << 0), - ATA_LFLAG_SKIP_D2H_BSY = (1 << 1), - ATA_LFLAG_NO_SRST = (1 << 2), - ATA_LFLAG_ASSUME_ATA = (1 << 3), - ATA_LFLAG_ASSUME_SEMB = (1 << 4), - ATA_LFLAG_ASSUME_CLASS = ATA_LFLAG_ASSUME_ATA | ATA_LFLAG_ASSUME_SEMB, - ATA_LFLAG_NO_RETRY = (1 << 5), - ATA_LFLAG_DISABLED = (1 << 6), - - ATA_FLAG_SLAVE_POSS = (1 << 0), - ATA_FLAG_SATA = (1 << 1), - ATA_FLAG_NO_LEGACY = (1 << 2), - ATA_FLAG_MMIO = (1 << 3), - ATA_FLAG_SRST = (1 << 4), - ATA_FLAG_SATA_RESET = (1 << 5), - ATA_FLAG_NO_ATAPI = (1 << 6), - ATA_FLAG_PIO_DMA = (1 << 7), - ATA_FLAG_PIO_LBA48 = (1 << 8), - ATA_FLAG_PIO_POLLING = (1 << 9), - ATA_FLAG_NCQ = (1 << 10), - ATA_FLAG_DEBUGMSG = (1 << 13), - ATA_FLAG_IGN_SIMPLEX = (1 << 15), - ATA_FLAG_NO_IORDY = (1 << 16), - ATA_FLAG_ACPI_SATA = (1 << 17), - ATA_FLAG_AN = (1 << 18), - ATA_FLAG_PMP = (1 << 19), - ATA_FLAG_IPM = (1 << 20), - - ATA_FLAG_DISABLED = (1 << 23), - - ATA_PFLAG_EH_PENDING = (1 << 0), - ATA_PFLAG_EH_IN_PROGRESS = (1 << 1), - ATA_PFLAG_FROZEN = (1 << 2), - ATA_PFLAG_RECOVERED = (1 << 3), - ATA_PFLAG_LOADING = (1 << 4), - ATA_PFLAG_UNLOADING = (1 << 5), - ATA_PFLAG_SCSI_HOTPLUG = (1 << 6), - ATA_PFLAG_INITIALIZING = (1 << 7), - ATA_PFLAG_RESETTING = (1 << 8), - ATA_PFLAG_SUSPENDED = (1 << 17), - ATA_PFLAG_PM_PENDING = (1 << 18), - - ATA_QCFLAG_ACTIVE = (1 << 0), - ATA_QCFLAG_DMAMAP = (1 << 1), - ATA_QCFLAG_IO = (1 << 3), - ATA_QCFLAG_RESULT_TF = (1 << 4), - ATA_QCFLAG_CLEAR_EXCL = (1 << 5), - ATA_QCFLAG_QUIET = (1 << 6), - - ATA_QCFLAG_FAILED = (1 << 16), - ATA_QCFLAG_SENSE_VALID = (1 << 17), - ATA_QCFLAG_EH_SCHEDULED = (1 << 18), - - ATA_HOST_SIMPLEX = (1 << 0), - ATA_HOST_STARTED = (1 << 1), - - ATA_TMOUT_BOOT = 30 * 100, - ATA_TMOUT_BOOT_QUICK = 7 * 100, - ATA_TMOUT_INTERNAL = 30 * 100, - ATA_TMOUT_INTERNAL_QUICK = 5 * 100, - - /* FIXME: GoVault needs 2s but we can't afford that without - * parallel probing. 800ms is enough for iVDR disk - * HHD424020F7SV00. Increase to 2secs when parallel probing - * is in place. - */ - ATA_TMOUT_FF_WAIT = 4 * 100 / 5, - - BUS_UNKNOWN = 0, - BUS_DMA = 1, - BUS_IDLE = 2, - BUS_NOINTR = 3, - BUS_NODATA = 4, - BUS_TIMER = 5, - BUS_PIO = 6, - BUS_EDD = 7, - BUS_IDENTIFY = 8, - BUS_PACKET = 9, - - PORT_UNKNOWN = 0, - PORT_ENABLED = 1, - PORT_DISABLED = 2, - - /* encoding various smaller bitmaps into a single - * unsigned long bitmap - */ - ATA_NR_PIO_MODES = 7, - ATA_NR_MWDMA_MODES = 5, - ATA_NR_UDMA_MODES = 8, - - ATA_SHIFT_PIO = 0, - ATA_SHIFT_MWDMA = ATA_SHIFT_PIO + ATA_NR_PIO_MODES, - ATA_SHIFT_UDMA = ATA_SHIFT_MWDMA + ATA_NR_MWDMA_MODES, - - ATA_DMA_PAD_SZ = 4, - - ATA_ERING_SIZE = 32, - - ATA_DEFER_LINK = 1, - ATA_DEFER_PORT = 2, - - ATA_EH_DESC_LEN = 80, - - ATA_EH_REVALIDATE = (1 << 0), - ATA_EH_SOFTRESET = (1 << 1), - ATA_EH_HARDRESET = (1 << 2), - ATA_EH_ENABLE_LINK = (1 << 3), - ATA_EH_LPM = (1 << 4), - - ATA_EH_RESET_MASK = ATA_EH_SOFTRESET | ATA_EH_HARDRESET, - ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE, - - ATA_EHI_HOTPLUGGED = (1 << 0), - ATA_EHI_RESUME_LINK = (1 << 1), - ATA_EHI_NO_AUTOPSY = (1 << 2), - ATA_EHI_QUIET = (1 << 3), - - ATA_EHI_DID_SOFTRESET = (1 << 16), - ATA_EHI_DID_HARDRESET = (1 << 17), - ATA_EHI_PRINTINFO = (1 << 18), - ATA_EHI_SETMODE = (1 << 19), - ATA_EHI_POST_SETMODE = (1 << 20), - - ATA_EHI_DID_RESET = ATA_EHI_DID_SOFTRESET | ATA_EHI_DID_HARDRESET, - ATA_EHI_RESET_MODIFIER_MASK = ATA_EHI_RESUME_LINK, - - ATA_EH_MAX_TRIES = 5, - - ATA_PROBE_MAX_TRIES = 3, - ATA_EH_DEV_TRIES = 3, - ATA_EH_PMP_TRIES = 5, - ATA_EH_PMP_LINK_TRIES = 3, - - SATA_PMP_SCR_TIMEOUT = 250, - - /* Horkage types. May be set by libata or controller on drives - (some horkage may be drive/controller pair dependant */ - - ATA_HORKAGE_DIAGNOSTIC = (1 << 0), - ATA_HORKAGE_NODMA = (1 << 1), - ATA_HORKAGE_NONCQ = (1 << 2), - ATA_HORKAGE_MAX_SEC_128 = (1 << 3), - ATA_HORKAGE_BROKEN_HPA = (1 << 4), - ATA_HORKAGE_SKIP_PM = (1 << 5), - ATA_HORKAGE_HPA_SIZE = (1 << 6), - ATA_HORKAGE_IPM = (1 << 7), - ATA_HORKAGE_IVB = (1 << 8), - ATA_HORKAGE_STUCK_ERR = (1 << 9), - - ATA_DMA_MASK_ATA = (1 << 0), - ATA_DMA_MASK_ATAPI = (1 << 1), - ATA_DMA_MASK_CFA = (1 << 2), - - ATAPI_READ = 0, - ATAPI_WRITE = 1, - ATAPI_READ_CD = 2, - ATAPI_PASS_THRU = 3, - ATAPI_MISC = 4, -}; - -enum ata_completion_errors { - AC_ERR_DEV = (1 << 0), - AC_ERR_HSM = (1 << 1), - AC_ERR_TIMEOUT = (1 << 2), - AC_ERR_MEDIA = (1 << 3), - AC_ERR_ATA_BUS = (1 << 4), - AC_ERR_HOST_BUS = (1 << 5), - AC_ERR_SYSTEM = (1 << 6), - AC_ERR_INVALID = (1 << 7), - AC_ERR_OTHER = (1 << 8), - AC_ERR_NODEV_HINT = (1 << 9), - AC_ERR_NCQ = (1 << 10), -}; - -enum ata_xfer_mask { - ATA_MASK_PIO = ((1LU << ATA_NR_PIO_MODES) - 1) << ATA_SHIFT_PIO, - ATA_MASK_MWDMA = ((1LU << ATA_NR_MWDMA_MODES) - 1) << ATA_SHIFT_MWDMA, - ATA_MASK_UDMA = ((1LU << ATA_NR_UDMA_MODES) - 1) << ATA_SHIFT_UDMA, -}; - -struct ata_port_info { -#ifndef __U_BOOT__ - struct scsi_host_template *sht; -#endif - unsigned long flags; - unsigned long link_flags; - unsigned long pio_mask; - unsigned long mwdma_mask; - unsigned long udma_mask; -#ifndef __U_BOOT__ - const struct ata_port_operations *port_ops; - void *private_data; -#endif -}; - -struct ata_ioports { - void __iomem *cmd_addr; - void __iomem *data_addr; - void __iomem *error_addr; - void __iomem *feature_addr; - void __iomem *nsect_addr; - void __iomem *lbal_addr; - void __iomem *lbam_addr; - void __iomem *lbah_addr; - void __iomem *device_addr; - void __iomem *status_addr; - void __iomem *command_addr; - void __iomem *altstatus_addr; - void __iomem *ctl_addr; -#ifndef __U_BOOT__ - void __iomem *bmdma_addr; -#endif - void __iomem *scr_addr; -}; - -struct ata_host { -#ifndef __U_BOOT__ - void __iomem * const *iomap; - void *private_data; - const struct ata_port_operations *ops; - unsigned long flags; - struct ata_port *simplex_claimed; -#endif - unsigned int n_ports; - struct ata_port *ports[0]; -}; - -#ifndef __U_BOOT__ -struct ata_port_stats { - unsigned long unhandled_irq; - unsigned long idle_irq; - unsigned long rw_reqbuf; -}; -#endif - -struct ata_device { - struct ata_link *link; - unsigned int devno; - unsigned long flags; - unsigned int horkage; -#ifndef __U_BOOT__ - struct scsi_device *sdev; -#ifdef CONFIG_ATA_ACPI - acpi_handle acpi_handle; - union acpi_object *gtf_cache; -#endif -#endif - u64 n_sectors; - unsigned int class; - - union { - u16 id[ATA_ID_WORDS]; - u32 gscr[SATA_PMP_GSCR_DWORDS]; - }; -#ifndef __U_BOOT__ - u8 pio_mode; - u8 dma_mode; - u8 xfer_mode; - unsigned int xfer_shift; -#endif - unsigned int multi_count; - unsigned int max_sectors; - unsigned int cdb_len; -#ifndef __U_BOOT__ - unsigned long pio_mask; - unsigned long mwdma_mask; -#endif - unsigned long udma_mask; - u16 cylinders; - u16 heads; - u16 sectors; -#ifndef __U_BOOT__ - int spdn_cnt; -#endif -}; - -enum dma_data_direction { - DMA_BIDIRECTIONAL = 0, - DMA_TO_DEVICE = 1, - DMA_FROM_DEVICE = 2, - DMA_NONE = 3, -}; - -struct ata_link { - struct ata_port *ap; - int pmp; - unsigned int active_tag; - u32 sactive; - unsigned int flags; - unsigned int hw_sata_spd_limit; -#ifndef __U_BOOT__ - unsigned int sata_spd_limit; - unsigned int sata_spd; - struct ata_device device[2]; -#endif -}; - -struct ata_port { - unsigned long flags; - unsigned int pflags; - unsigned int print_id; - unsigned int port_no; - - struct ata_ioports ioaddr; - - u8 ctl; - u8 last_ctl; - unsigned int pio_mask; - unsigned int mwdma_mask; - unsigned int udma_mask; - unsigned int cbl; - - struct ata_queued_cmd qcmd[ATA_MAX_QUEUE]; - unsigned long qc_allocated; - unsigned int qc_active; - int nr_active_links; - - struct ata_link link; -#ifndef __U_BOOT__ - int nr_pmp_links; - struct ata_link *pmp_link; -#endif - struct ata_link *excl_link; - int nr_pmp_links; -#ifndef __U_BOOT__ - struct ata_port_stats stats; - struct device *dev; - u32 msg_enable; -#endif - struct ata_host *host; - void *port_task_data; - - unsigned int hsm_task_state; - void *private_data; - unsigned char *pdata; -}; - -#endif diff --git a/drivers/block/sata_mv.c b/drivers/block/sata_mv.c deleted file mode 100644 index 78e3da4..0000000 --- a/drivers/block/sata_mv.c +++ /dev/null @@ -1,1051 +0,0 @@ -/* - * Copyright (C) Excito Elektronik i SkÃ¥ne AB, 2010. - * Author: Tor Krill - * - * Copyright (C) 2015 Stefan Roese - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -/* - * This driver supports the SATA controller of some Mavell SoC's. - * Here a (most likely incomplete) list of the supported SoC's: - * - Kirkwood - * - Armada 370 - * - Armada XP - * - * This driver implementation is an alternative to the already available - * driver via the "ide" commands interface (drivers/block/mvsata_ide.c). - * But this driver only supports PIO mode and as this new driver also - * supports transfer via DMA, its much faster. - * - * Please note, that the newer SoC's (e.g. Armada 38x) are not supported - * by this driver. As they have an AHCI compatible SATA controller - * integrated. - */ - -/* - * TODO: - * Better error recovery - * No support for using PRDs (Thus max 64KB transfers) - * No NCQ support - * No port multiplier support - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(CONFIG_KIRKWOOD) -#include -#define SATAHC_BASE KW_SATA_BASE -#else -#include -#define SATAHC_BASE MVEBU_AXP_SATA_BASE -#endif - -#define SATA0_BASE (SATAHC_BASE + 0x2000) -#define SATA1_BASE (SATAHC_BASE + 0x4000) - -/* EDMA registers */ -#define EDMA_CFG 0x000 -#define EDMA_CFG_NCQ (1 << 5) -#define EDMA_CFG_EQUE (1 << 9) -#define EDMA_TIMER 0x004 -#define EDMA_IECR 0x008 -#define EDMA_IEMR 0x00c -#define EDMA_RQBA_HI 0x010 -#define EDMA_RQIPR 0x014 -#define EDMA_RQIPR_IPMASK (0x1f << 5) -#define EDMA_RQIPR_IPSHIFT 5 -#define EDMA_RQOPR 0x018 -#define EDMA_RQOPR_OPMASK (0x1f << 5) -#define EDMA_RQOPR_OPSHIFT 5 -#define EDMA_RSBA_HI 0x01c -#define EDMA_RSIPR 0x020 -#define EDMA_RSIPR_IPMASK (0x1f << 3) -#define EDMA_RSIPR_IPSHIFT 3 -#define EDMA_RSOPR 0x024 -#define EDMA_RSOPR_OPMASK (0x1f << 3) -#define EDMA_RSOPR_OPSHIFT 3 -#define EDMA_CMD 0x028 -#define EDMA_CMD_ENEDMA (0x01 << 0) -#define EDMA_CMD_DISEDMA (0x01 << 1) -#define EDMA_CMD_ATARST (0x01 << 2) -#define EDMA_CMD_FREEZE (0x01 << 4) -#define EDMA_TEST_CTL 0x02c -#define EDMA_STATUS 0x030 -#define EDMA_IORTO 0x034 -#define EDMA_CDTR 0x040 -#define EDMA_HLTCND 0x060 -#define EDMA_NTSR 0x094 - -/* Basic DMA registers */ -#define BDMA_CMD 0x224 -#define BDMA_STATUS 0x228 -#define BDMA_DTLB 0x22c -#define BDMA_DTHB 0x230 -#define BDMA_DRL 0x234 -#define BDMA_DRH 0x238 - -/* SATA Interface registers */ -#define SIR_ICFG 0x050 -#define SIR_CFG_GEN2EN (0x1 << 7) -#define SIR_PLL_CFG 0x054 -#define SIR_SSTATUS 0x300 -#define SSTATUS_DET_MASK (0x0f << 0) -#define SIR_SERROR 0x304 -#define SIR_SCONTROL 0x308 -#define SIR_SCONTROL_DETEN (0x01 << 0) -#define SIR_LTMODE 0x30c -#define SIR_LTMODE_NELBE (0x01 << 7) -#define SIR_PHYMODE3 0x310 -#define SIR_PHYMODE4 0x314 -#define SIR_PHYMODE1 0x32c -#define SIR_PHYMODE2 0x330 -#define SIR_BIST_CTRL 0x334 -#define SIR_BIST_DW1 0x338 -#define SIR_BIST_DW2 0x33c -#define SIR_SERR_IRQ_MASK 0x340 -#define SIR_SATA_IFCTRL 0x344 -#define SIR_SATA_TESTCTRL 0x348 -#define SIR_SATA_IFSTATUS 0x34c -#define SIR_VEND_UNIQ 0x35c -#define SIR_FIS_CFG 0x360 -#define SIR_FIS_IRQ_CAUSE 0x364 -#define SIR_FIS_IRQ_MASK 0x368 -#define SIR_FIS_DWORD0 0x370 -#define SIR_FIS_DWORD1 0x374 -#define SIR_FIS_DWORD2 0x378 -#define SIR_FIS_DWORD3 0x37c -#define SIR_FIS_DWORD4 0x380 -#define SIR_FIS_DWORD5 0x384 -#define SIR_FIS_DWORD6 0x388 -#define SIR_PHYM9_GEN2 0x398 -#define SIR_PHYM9_GEN1 0x39c -#define SIR_PHY_CFG 0x3a0 -#define SIR_PHYCTL 0x3a4 -#define SIR_PHYM10 0x3a8 -#define SIR_PHYM12 0x3b0 - -/* Shadow registers */ -#define PIO_DATA 0x100 -#define PIO_ERR_FEATURES 0x104 -#define PIO_SECTOR_COUNT 0x108 -#define PIO_LBA_LOW 0x10c -#define PIO_LBA_MID 0x110 -#define PIO_LBA_HI 0x114 -#define PIO_DEVICE 0x118 -#define PIO_CMD_STATUS 0x11c -#define PIO_STATUS_ERR (0x01 << 0) -#define PIO_STATUS_DRQ (0x01 << 3) -#define PIO_STATUS_DF (0x01 << 5) -#define PIO_STATUS_DRDY (0x01 << 6) -#define PIO_STATUS_BSY (0x01 << 7) -#define PIO_CTRL_ALTSTAT 0x120 - -/* SATAHC arbiter registers */ -#define SATAHC_CFG 0x000 -#define SATAHC_RQOP 0x004 -#define SATAHC_RQIP 0x008 -#define SATAHC_ICT 0x00c -#define SATAHC_ITT 0x010 -#define SATAHC_ICR 0x014 -#define SATAHC_ICR_PORT0 (0x01 << 0) -#define SATAHC_ICR_PORT1 (0x01 << 1) -#define SATAHC_MIC 0x020 -#define SATAHC_MIM 0x024 -#define SATAHC_LED_CFG 0x02c - -#define REQUEST_QUEUE_SIZE 32 -#define RESPONSE_QUEUE_SIZE REQUEST_QUEUE_SIZE - -struct crqb { - u32 dtb_low; /* DW0 */ - u32 dtb_high; /* DW1 */ - u32 control_flags; /* DW2 */ - u32 drb_count; /* DW3 */ - u32 ata_cmd_feat; /* DW4 */ - u32 ata_addr; /* DW5 */ - u32 ata_addr_exp; /* DW6 */ - u32 ata_sect_count; /* DW7 */ -}; - -#define CRQB_ALIGN 0x400 - -#define CRQB_CNTRLFLAGS_DIR (0x01 << 0) -#define CRQB_CNTRLFLAGS_DQTAGMASK (0x1f << 1) -#define CRQB_CNTRLFLAGS_DQTAGSHIFT 1 -#define CRQB_CNTRLFLAGS_PMPORTMASK (0x0f << 12) -#define CRQB_CNTRLFLAGS_PMPORTSHIFT 12 -#define CRQB_CNTRLFLAGS_PRDMODE (0x01 << 16) -#define CRQB_CNTRLFLAGS_HQTAGMASK (0x1f << 17) -#define CRQB_CNTRLFLAGS_HQTAGSHIFT 17 - -#define CRQB_CMDFEAT_CMDMASK (0xff << 16) -#define CRQB_CMDFEAT_CMDSHIFT 16 -#define CRQB_CMDFEAT_FEATMASK (0xff << 16) -#define CRQB_CMDFEAT_FEATSHIFT 24 - -#define CRQB_ADDR_LBA_LOWMASK (0xff << 0) -#define CRQB_ADDR_LBA_LOWSHIFT 0 -#define CRQB_ADDR_LBA_MIDMASK (0xff << 8) -#define CRQB_ADDR_LBA_MIDSHIFT 8 -#define CRQB_ADDR_LBA_HIGHMASK (0xff << 16) -#define CRQB_ADDR_LBA_HIGHSHIFT 16 -#define CRQB_ADDR_DEVICE_MASK (0xff << 24) -#define CRQB_ADDR_DEVICE_SHIFT 24 - -#define CRQB_ADDR_LBA_LOW_EXP_MASK (0xff << 0) -#define CRQB_ADDR_LBA_LOW_EXP_SHIFT 0 -#define CRQB_ADDR_LBA_MID_EXP_MASK (0xff << 8) -#define CRQB_ADDR_LBA_MID_EXP_SHIFT 8 -#define CRQB_ADDR_LBA_HIGH_EXP_MASK (0xff << 16) -#define CRQB_ADDR_LBA_HIGH_EXP_SHIFT 16 -#define CRQB_ADDR_FEATURE_EXP_MASK (0xff << 24) -#define CRQB_ADDR_FEATURE_EXP_SHIFT 24 - -#define CRQB_SECTCOUNT_COUNT_MASK (0xff << 0) -#define CRQB_SECTCOUNT_COUNT_SHIFT 0 -#define CRQB_SECTCOUNT_COUNT_EXP_MASK (0xff << 8) -#define CRQB_SECTCOUNT_COUNT_EXP_SHIFT 8 - -#define MVSATA_WIN_CONTROL(w) (MVEBU_AXP_SATA_BASE + 0x30 + ((w) << 4)) -#define MVSATA_WIN_BASE(w) (MVEBU_AXP_SATA_BASE + 0x34 + ((w) << 4)) - -struct eprd { - u32 phyaddr_low; - u32 bytecount_eot; - u32 phyaddr_hi; - u32 reserved; -}; - -#define EPRD_PHYADDR_MASK 0xfffffffe -#define EPRD_BYTECOUNT_MASK 0x0000ffff -#define EPRD_EOT (0x01 << 31) - -struct crpb { - u32 id; - u32 flags; - u32 timestamp; -}; - -#define CRPB_ALIGN 0x100 - -#define READ_CMD 0 -#define WRITE_CMD 1 - -/* - * Since we don't use PRDs yet max transfer size - * is 64KB - */ -#define MV_ATA_MAX_SECTORS (65535 / ATA_SECT_SIZE) - -/* Keep track if hw is initialized or not */ -static u32 hw_init; - -struct mv_priv { - char name[12]; - u32 link; - u32 regbase; - u32 queue_depth; - u16 pio; - u16 mwdma; - u16 udma; - - void *crqb_alloc; - struct crqb *request; - - void *crpb_alloc; - struct crpb *response; -}; - -static int ata_wait_register(u32 *addr, u32 mask, u32 val, u32 timeout_msec) -{ - ulong start; - - start = get_timer(0); - do { - if ((in_le32(addr) & mask) == val) - return 0; - } while (get_timer(start) < timeout_msec); - - return -ETIMEDOUT; -} - -/* Cut from sata_mv in linux kernel */ -static int mv_stop_edma_engine(int port) -{ - struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; - int i; - - /* Disable eDMA. The disable bit auto clears. */ - out_le32(priv->regbase + EDMA_CMD, EDMA_CMD_DISEDMA); - - /* Wait for the chip to confirm eDMA is off. */ - for (i = 10000; i > 0; i--) { - u32 reg = in_le32(priv->regbase + EDMA_CMD); - if (!(reg & EDMA_CMD_ENEDMA)) { - debug("EDMA stop on port %d succesful\n", port); - return 0; - } - udelay(10); - } - debug("EDMA stop on port %d failed\n", port); - return -1; -} - -static int mv_start_edma_engine(int port) -{ - struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; - u32 tmp; - - /* Check preconditions */ - tmp = in_le32(priv->regbase + SIR_SSTATUS); - if ((tmp & SSTATUS_DET_MASK) != 0x03) { - printf("Device error on port: %d\n", port); - return -1; - } - - tmp = in_le32(priv->regbase + PIO_CMD_STATUS); - if (tmp & (ATA_BUSY | ATA_DRQ)) { - printf("Device not ready on port: %d\n", port); - return -1; - } - - /* Clear interrupt cause */ - out_le32(priv->regbase + EDMA_IECR, 0x0); - - tmp = in_le32(SATAHC_BASE + SATAHC_ICR); - tmp &= ~(port == 0 ? SATAHC_ICR_PORT0 : SATAHC_ICR_PORT1); - out_le32(SATAHC_BASE + SATAHC_ICR, tmp); - - /* Configure edma operation */ - tmp = in_le32(priv->regbase + EDMA_CFG); - tmp &= ~EDMA_CFG_NCQ; /* No NCQ */ - tmp &= ~EDMA_CFG_EQUE; /* Dont queue operations */ - out_le32(priv->regbase + EDMA_CFG, tmp); - - out_le32(priv->regbase + SIR_FIS_IRQ_CAUSE, 0x0); - - /* Configure fis, set all to no-wait for now */ - out_le32(priv->regbase + SIR_FIS_CFG, 0x0); - - /* Setup request queue */ - out_le32(priv->regbase + EDMA_RQBA_HI, 0x0); - out_le32(priv->regbase + EDMA_RQIPR, priv->request); - out_le32(priv->regbase + EDMA_RQOPR, 0x0); - - /* Setup response queue */ - out_le32(priv->regbase + EDMA_RSBA_HI, 0x0); - out_le32(priv->regbase + EDMA_RSOPR, priv->response); - out_le32(priv->regbase + EDMA_RSIPR, 0x0); - - /* Start edma */ - out_le32(priv->regbase + EDMA_CMD, EDMA_CMD_ENEDMA); - - return 0; -} - -static int mv_reset_channel(int port) -{ - struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; - - /* Make sure edma is stopped */ - mv_stop_edma_engine(port); - - out_le32(priv->regbase + EDMA_CMD, EDMA_CMD_ATARST); - udelay(25); /* allow reset propagation */ - out_le32(priv->regbase + EDMA_CMD, 0); - mdelay(10); - - return 0; -} - -static void mv_reset_port(int port) -{ - struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; - - mv_reset_channel(port); - - out_le32(priv->regbase + EDMA_CMD, 0x0); - out_le32(priv->regbase + EDMA_CFG, 0x101f); - out_le32(priv->regbase + EDMA_IECR, 0x0); - out_le32(priv->regbase + EDMA_IEMR, 0x0); - out_le32(priv->regbase + EDMA_RQBA_HI, 0x0); - out_le32(priv->regbase + EDMA_RQIPR, 0x0); - out_le32(priv->regbase + EDMA_RQOPR, 0x0); - out_le32(priv->regbase + EDMA_RSBA_HI, 0x0); - out_le32(priv->regbase + EDMA_RSIPR, 0x0); - out_le32(priv->regbase + EDMA_RSOPR, 0x0); - out_le32(priv->regbase + EDMA_IORTO, 0xfa); -} - -static void mv_reset_one_hc(void) -{ - out_le32(SATAHC_BASE + SATAHC_ICT, 0x00); - out_le32(SATAHC_BASE + SATAHC_ITT, 0x00); - out_le32(SATAHC_BASE + SATAHC_ICR, 0x00); -} - -static int probe_port(int port) -{ - struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; - int tries, tries2, set15 = 0; - u32 tmp; - - debug("Probe port: %d\n", port); - - for (tries = 0; tries < 2; tries++) { - /* Clear SError */ - out_le32(priv->regbase + SIR_SERROR, 0x0); - - /* trigger com-init */ - tmp = in_le32(priv->regbase + SIR_SCONTROL); - tmp = (tmp & 0x0f0) | 0x300 | SIR_SCONTROL_DETEN; - out_le32(priv->regbase + SIR_SCONTROL, tmp); - - mdelay(1); - - tmp = in_le32(priv->regbase + SIR_SCONTROL); - tries2 = 5; - do { - tmp = (tmp & 0x0f0) | 0x300; - out_le32(priv->regbase + SIR_SCONTROL, tmp); - mdelay(10); - tmp = in_le32(priv->regbase + SIR_SCONTROL); - } while ((tmp & 0xf0f) != 0x300 && tries2--); - - mdelay(10); - - for (tries2 = 0; tries2 < 200; tries2++) { - tmp = in_le32(priv->regbase + SIR_SSTATUS); - if ((tmp & SSTATUS_DET_MASK) == 0x03) { - debug("Found device on port\n"); - return 0; - } - mdelay(1); - } - - if ((tmp & SSTATUS_DET_MASK) == 0) { - debug("No device attached on port %d\n", port); - return -ENODEV; - } - - if (!set15) { - /* Try on 1.5Gb/S */ - debug("Try 1.5Gb link\n"); - set15 = 1; - out_le32(priv->regbase + SIR_SCONTROL, 0x304); - - tmp = in_le32(priv->regbase + SIR_ICFG); - tmp &= ~SIR_CFG_GEN2EN; - out_le32(priv->regbase + SIR_ICFG, tmp); - - mv_reset_channel(port); - } - } - - debug("Failed to probe port\n"); - return -1; -} - -/* Get request queue in pointer */ -static int get_reqip(int port) -{ - struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; - u32 tmp; - - tmp = in_le32(priv->regbase + EDMA_RQIPR) & EDMA_RQIPR_IPMASK; - tmp = tmp >> EDMA_RQIPR_IPSHIFT; - - return tmp; -} - -static void set_reqip(int port, int reqin) -{ - struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; - u32 tmp; - - tmp = in_le32(priv->regbase + EDMA_RQIPR) & ~EDMA_RQIPR_IPMASK; - tmp |= ((reqin << EDMA_RQIPR_IPSHIFT) & EDMA_RQIPR_IPMASK); - out_le32(priv->regbase + EDMA_RQIPR, tmp); -} - -/* Get next available slot, ignoring possible overwrite */ -static int get_next_reqip(int port) -{ - int slot = get_reqip(port); - slot = (slot + 1) % REQUEST_QUEUE_SIZE; - return slot; -} - -/* Get response queue in pointer */ -static int get_rspip(int port) -{ - struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; - u32 tmp; - - tmp = in_le32(priv->regbase + EDMA_RSIPR) & EDMA_RSIPR_IPMASK; - tmp = tmp >> EDMA_RSIPR_IPSHIFT; - - return tmp; -} - -/* Get response queue out pointer */ -static int get_rspop(int port) -{ - struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; - u32 tmp; - - tmp = in_le32(priv->regbase + EDMA_RSOPR) & EDMA_RSOPR_OPMASK; - tmp = tmp >> EDMA_RSOPR_OPSHIFT; - return tmp; -} - -/* Get next response queue pointer */ -static int get_next_rspop(int port) -{ - return (get_rspop(port) + 1) % RESPONSE_QUEUE_SIZE; -} - -/* Set response queue pointer */ -static void set_rspop(int port, int reqin) -{ - struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; - u32 tmp; - - tmp = in_le32(priv->regbase + EDMA_RSOPR) & ~EDMA_RSOPR_OPMASK; - tmp |= ((reqin << EDMA_RSOPR_OPSHIFT) & EDMA_RSOPR_OPMASK); - - out_le32(priv->regbase + EDMA_RSOPR, tmp); -} - -static int wait_dma_completion(int port, int index, u32 timeout_msec) -{ - u32 tmp, res; - - tmp = port == 0 ? SATAHC_ICR_PORT0 : SATAHC_ICR_PORT1; - res = ata_wait_register((u32 *)(SATAHC_BASE + SATAHC_ICR), tmp, - tmp, timeout_msec); - if (res) - printf("Failed to wait for completion on port %d\n", port); - - return res; -} - -static void process_responses(int port) -{ -#ifdef DEBUG - struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; -#endif - u32 tmp; - u32 outind = get_rspop(port); - - /* Ack interrupts */ - tmp = in_le32(SATAHC_BASE + SATAHC_ICR); - if (port == 0) - tmp &= ~(BIT(0) | BIT(8)); - else - tmp &= ~(BIT(1) | BIT(9)); - tmp &= ~(BIT(4)); - out_le32(SATAHC_BASE + SATAHC_ICR, tmp); - - while (get_rspip(port) != outind) { -#ifdef DEBUG - debug("Response index %d flags %08x on port %d\n", outind, - priv->response[outind].flags, port); -#endif - outind = get_next_rspop(port); - set_rspop(port, outind); - } -} - -static int mv_ata_exec_ata_cmd(int port, struct sata_fis_h2d *cfis, - u8 *buffer, u32 len, u32 iswrite) -{ - struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; - struct crqb *req; - int slot; - u32 start; - - if (len >= 64 * 1024) { - printf("We only support <64K transfers for now\n"); - return -1; - } - - /* Initialize request */ - slot = get_reqip(port); - memset(&priv->request[slot], 0, sizeof(struct crqb)); - req = &priv->request[slot]; - - req->dtb_low = (u32)buffer; - - /* Dont use PRDs */ - req->control_flags = CRQB_CNTRLFLAGS_PRDMODE; - req->control_flags |= iswrite ? 0 : CRQB_CNTRLFLAGS_DIR; - req->control_flags |= - ((cfis->pm_port_c << CRQB_CNTRLFLAGS_PMPORTSHIFT) - & CRQB_CNTRLFLAGS_PMPORTMASK); - - req->drb_count = len; - - req->ata_cmd_feat = (cfis->command << CRQB_CMDFEAT_CMDSHIFT) & - CRQB_CMDFEAT_CMDMASK; - req->ata_cmd_feat |= (cfis->features << CRQB_CMDFEAT_FEATSHIFT) & - CRQB_CMDFEAT_FEATMASK; - - req->ata_addr = (cfis->lba_low << CRQB_ADDR_LBA_LOWSHIFT) & - CRQB_ADDR_LBA_LOWMASK; - req->ata_addr |= (cfis->lba_mid << CRQB_ADDR_LBA_MIDSHIFT) & - CRQB_ADDR_LBA_MIDMASK; - req->ata_addr |= (cfis->lba_high << CRQB_ADDR_LBA_HIGHSHIFT) & - CRQB_ADDR_LBA_HIGHMASK; - req->ata_addr |= (cfis->device << CRQB_ADDR_DEVICE_SHIFT) & - CRQB_ADDR_DEVICE_MASK; - - req->ata_addr_exp = (cfis->lba_low_exp << CRQB_ADDR_LBA_LOW_EXP_SHIFT) & - CRQB_ADDR_LBA_LOW_EXP_MASK; - req->ata_addr_exp |= - (cfis->lba_mid_exp << CRQB_ADDR_LBA_MID_EXP_SHIFT) & - CRQB_ADDR_LBA_MID_EXP_MASK; - req->ata_addr_exp |= - (cfis->lba_high_exp << CRQB_ADDR_LBA_HIGH_EXP_SHIFT) & - CRQB_ADDR_LBA_HIGH_EXP_MASK; - req->ata_addr_exp |= - (cfis->features_exp << CRQB_ADDR_FEATURE_EXP_SHIFT) & - CRQB_ADDR_FEATURE_EXP_MASK; - - req->ata_sect_count = - (cfis->sector_count << CRQB_SECTCOUNT_COUNT_SHIFT) & - CRQB_SECTCOUNT_COUNT_MASK; - req->ata_sect_count |= - (cfis->sector_count_exp << CRQB_SECTCOUNT_COUNT_EXP_SHIFT) & - CRQB_SECTCOUNT_COUNT_EXP_MASK; - - /* Flush data */ - start = (u32)req & ~(ARCH_DMA_MINALIGN - 1); - flush_dcache_range(start, - start + ALIGN(sizeof(*req), ARCH_DMA_MINALIGN)); - - /* Trigger operation */ - slot = get_next_reqip(port); - set_reqip(port, slot); - - /* Wait for completion */ - if (wait_dma_completion(port, slot, 10000)) { - printf("ATA operation timed out\n"); - return -1; - } - - process_responses(port); - - /* Invalidate data on read */ - if (buffer && len) { - start = (u32)buffer & ~(ARCH_DMA_MINALIGN - 1); - invalidate_dcache_range(start, - start + ALIGN(len, ARCH_DMA_MINALIGN)); - } - - return len; -} - -static u32 mv_sata_rw_cmd_ext(int port, lbaint_t start, u32 blkcnt, - u8 *buffer, int is_write) -{ - struct sata_fis_h2d cfis; - u32 res; - u64 block; - - block = (u64)start; - - memset(&cfis, 0, sizeof(struct sata_fis_h2d)); - - cfis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; - cfis.command = (is_write) ? ATA_CMD_WRITE_EXT : ATA_CMD_READ_EXT; - - cfis.lba_high_exp = (block >> 40) & 0xff; - cfis.lba_mid_exp = (block >> 32) & 0xff; - cfis.lba_low_exp = (block >> 24) & 0xff; - cfis.lba_high = (block >> 16) & 0xff; - cfis.lba_mid = (block >> 8) & 0xff; - cfis.lba_low = block & 0xff; - cfis.device = ATA_LBA; - cfis.sector_count_exp = (blkcnt >> 8) & 0xff; - cfis.sector_count = blkcnt & 0xff; - - res = mv_ata_exec_ata_cmd(port, &cfis, buffer, ATA_SECT_SIZE * blkcnt, - is_write); - - return res >= 0 ? blkcnt : res; -} - -static u32 mv_sata_rw_cmd(int port, lbaint_t start, u32 blkcnt, u8 *buffer, - int is_write) -{ - struct sata_fis_h2d cfis; - lbaint_t block; - u32 res; - - block = start; - - memset(&cfis, 0, sizeof(struct sata_fis_h2d)); - - cfis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; - cfis.command = (is_write) ? ATA_CMD_WRITE : ATA_CMD_READ; - cfis.device = ATA_LBA; - - cfis.device |= (block >> 24) & 0xf; - cfis.lba_high = (block >> 16) & 0xff; - cfis.lba_mid = (block >> 8) & 0xff; - cfis.lba_low = block & 0xff; - cfis.sector_count = (u8)(blkcnt & 0xff); - - res = mv_ata_exec_ata_cmd(port, &cfis, buffer, ATA_SECT_SIZE * blkcnt, - is_write); - - return res >= 0 ? blkcnt : res; -} - -static u32 ata_low_level_rw(int dev, lbaint_t blknr, lbaint_t blkcnt, - void *buffer, int is_write) -{ - lbaint_t start, blks; - u8 *addr; - int max_blks; - - debug("%s: %ld %ld\n", __func__, blknr, blkcnt); - - start = blknr; - blks = blkcnt; - addr = (u8 *)buffer; - - max_blks = MV_ATA_MAX_SECTORS; - do { - if (blks > max_blks) { - if (sata_dev_desc[dev].lba48) { - mv_sata_rw_cmd_ext(dev, start, max_blks, addr, - is_write); - } else { - mv_sata_rw_cmd(dev, start, max_blks, addr, - is_write); - } - start += max_blks; - blks -= max_blks; - addr += ATA_SECT_SIZE * max_blks; - } else { - if (sata_dev_desc[dev].lba48) { - mv_sata_rw_cmd_ext(dev, start, blks, addr, - is_write); - } else { - mv_sata_rw_cmd(dev, start, blks, addr, - is_write); - } - start += blks; - blks = 0; - addr += ATA_SECT_SIZE * blks; - } - } while (blks != 0); - - return blkcnt; -} - -static int mv_ata_exec_ata_cmd_nondma(int port, - struct sata_fis_h2d *cfis, u8 *buffer, - u32 len, u32 iswrite) -{ - struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; - int i; - u16 *tp; - - debug("%s\n", __func__); - - out_le32(priv->regbase + PIO_SECTOR_COUNT, cfis->sector_count); - out_le32(priv->regbase + PIO_LBA_HI, cfis->lba_high); - out_le32(priv->regbase + PIO_LBA_MID, cfis->lba_mid); - out_le32(priv->regbase + PIO_LBA_LOW, cfis->lba_low); - out_le32(priv->regbase + PIO_ERR_FEATURES, cfis->features); - out_le32(priv->regbase + PIO_DEVICE, cfis->device); - out_le32(priv->regbase + PIO_CMD_STATUS, cfis->command); - - if (ata_wait_register((u32 *)(priv->regbase + PIO_CMD_STATUS), - ATA_BUSY, 0x0, 10000)) { - debug("Failed to wait for completion\n"); - return -1; - } - - if (len > 0) { - tp = (u16 *)buffer; - for (i = 0; i < len / 2; i++) { - if (iswrite) - out_le16(priv->regbase + PIO_DATA, *tp++); - else - *tp++ = in_le16(priv->regbase + PIO_DATA); - } - } - - return len; -} - -static int mv_sata_identify(int port, u16 *id) -{ - struct sata_fis_h2d h2d; - - memset(&h2d, 0, sizeof(struct sata_fis_h2d)); - - h2d.fis_type = SATA_FIS_TYPE_REGISTER_H2D; - h2d.command = ATA_CMD_ID_ATA; - - /* Give device time to get operational */ - mdelay(10); - - return mv_ata_exec_ata_cmd_nondma(port, &h2d, (u8 *)id, - ATA_ID_WORDS * 2, READ_CMD); -} - -static void mv_sata_xfer_mode(int port, u16 *id) -{ - struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; - - priv->pio = id[ATA_ID_PIO_MODES]; - priv->mwdma = id[ATA_ID_MWDMA_MODES]; - priv->udma = id[ATA_ID_UDMA_MODES]; - debug("pio %04x, mwdma %04x, udma %04x\n", priv->pio, priv->mwdma, - priv->udma); -} - -static void mv_sata_set_features(int port) -{ - struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; - struct sata_fis_h2d cfis; - u8 udma_cap; - - memset(&cfis, 0, sizeof(struct sata_fis_h2d)); - - cfis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; - cfis.command = ATA_CMD_SET_FEATURES; - cfis.features = SETFEATURES_XFER; - - /* First check the device capablity */ - udma_cap = (u8) (priv->udma & 0xff); - - if (udma_cap == ATA_UDMA6) - cfis.sector_count = XFER_UDMA_6; - if (udma_cap == ATA_UDMA5) - cfis.sector_count = XFER_UDMA_5; - if (udma_cap == ATA_UDMA4) - cfis.sector_count = XFER_UDMA_4; - if (udma_cap == ATA_UDMA3) - cfis.sector_count = XFER_UDMA_3; - - mv_ata_exec_ata_cmd_nondma(port, &cfis, NULL, 0, READ_CMD); -} - -int mv_sata_spin_down(int dev) -{ - struct sata_fis_h2d cfis; - struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[dev].priv; - - if (priv->link == 0) { - debug("No device on port: %d\n", dev); - return 1; - } - - memset(&cfis, 0, sizeof(struct sata_fis_h2d)); - - cfis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; - cfis.command = ATA_CMD_STANDBY; - - return mv_ata_exec_ata_cmd_nondma(dev, &cfis, NULL, 0, READ_CMD); -} - -int mv_sata_spin_up(int dev) -{ - struct sata_fis_h2d cfis; - struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[dev].priv; - - if (priv->link == 0) { - debug("No device on port: %d\n", dev); - return 1; - } - - memset(&cfis, 0, sizeof(struct sata_fis_h2d)); - - cfis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; - cfis.command = ATA_CMD_IDLE; - - return mv_ata_exec_ata_cmd_nondma(dev, &cfis, NULL, 0, READ_CMD); -} - -ulong sata_read(int dev, ulong blknr, lbaint_t blkcnt, void *buffer) -{ - return ata_low_level_rw(dev, blknr, blkcnt, buffer, READ_CMD); -} - -ulong sata_write(int dev, ulong blknr, lbaint_t blkcnt, const void *buffer) -{ - return ata_low_level_rw(dev, blknr, blkcnt, (void *)buffer, WRITE_CMD); -} - -/* - * Initialize SATA memory windows - */ -static void mvsata_ide_conf_mbus_windows(void) -{ - const struct mbus_dram_target_info *dram; - int i; - - dram = mvebu_mbus_dram_info(); - - /* Disable windows, Set Size/Base to 0 */ - for (i = 0; i < 4; i++) { - writel(0, MVSATA_WIN_CONTROL(i)); - writel(0, MVSATA_WIN_BASE(i)); - } - - for (i = 0; i < dram->num_cs; i++) { - const struct mbus_dram_window *cs = dram->cs + i; - writel(((cs->size - 1) & 0xffff0000) | (cs->mbus_attr << 8) | - (dram->mbus_dram_target_id << 4) | 1, - MVSATA_WIN_CONTROL(i)); - writel(cs->base & 0xffff0000, MVSATA_WIN_BASE(i)); - } -} - -int init_sata(int dev) -{ - struct mv_priv *priv; - - debug("Initialize sata dev: %d\n", dev); - - if (dev < 0 || dev >= CONFIG_SYS_SATA_MAX_DEVICE) { - printf("Invalid sata device %d\n", dev); - return -1; - } - - priv = (struct mv_priv *)malloc(sizeof(struct mv_priv)); - if (!priv) { - printf("Failed to allocate memory for private sata data\n"); - return -ENOMEM; - } - - memset((void *)priv, 0, sizeof(struct mv_priv)); - - /* Allocate and align request buffer */ - priv->crqb_alloc = malloc(sizeof(struct crqb) * REQUEST_QUEUE_SIZE + - CRQB_ALIGN); - if (!priv->crqb_alloc) { - printf("Unable to allocate memory for request queue\n"); - return -ENOMEM; - } - memset(priv->crqb_alloc, 0, - sizeof(struct crqb) * REQUEST_QUEUE_SIZE + CRQB_ALIGN); - priv->request = (struct crqb *)(((u32) priv->crqb_alloc + CRQB_ALIGN) & - ~(CRQB_ALIGN - 1)); - - /* Allocate and align response buffer */ - priv->crpb_alloc = malloc(sizeof(struct crpb) * REQUEST_QUEUE_SIZE + - CRPB_ALIGN); - if (!priv->crpb_alloc) { - printf("Unable to allocate memory for response queue\n"); - return -ENOMEM; - } - memset(priv->crpb_alloc, 0, - sizeof(struct crpb) * REQUEST_QUEUE_SIZE + CRPB_ALIGN); - priv->response = (struct crpb *)(((u32) priv->crpb_alloc + CRPB_ALIGN) & - ~(CRPB_ALIGN - 1)); - - sata_dev_desc[dev].priv = (void *)priv; - - sprintf(priv->name, "SATA%d", dev); - - priv->regbase = dev == 0 ? SATA0_BASE : SATA1_BASE; - - if (!hw_init) { - debug("Initialize sata hw\n"); - hw_init = 1; - mv_reset_one_hc(); - mvsata_ide_conf_mbus_windows(); - } - - mv_reset_port(dev); - - if (probe_port(dev)) { - priv->link = 0; - return -ENODEV; - } - priv->link = 1; - - return 0; -} - -int reset_sata(int dev) -{ - return 0; -} - -int scan_sata(int port) -{ - unsigned char serial[ATA_ID_SERNO_LEN + 1]; - unsigned char firmware[ATA_ID_FW_REV_LEN + 1]; - unsigned char product[ATA_ID_PROD_LEN + 1]; - u64 n_sectors; - u16 *id; - struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; - - if (!priv->link) - return -ENODEV; - - id = (u16 *)malloc(ATA_ID_WORDS * 2); - if (!id) { - printf("Failed to malloc id data\n"); - return -ENOMEM; - } - - mv_sata_identify(port, id); - ata_swap_buf_le16(id, ATA_ID_WORDS); -#ifdef DEBUG - ata_dump_id(id); -#endif - - /* Serial number */ - ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial)); - memcpy(sata_dev_desc[port].product, serial, sizeof(serial)); - - /* Firmware version */ - ata_id_c_string(id, firmware, ATA_ID_FW_REV, sizeof(firmware)); - memcpy(sata_dev_desc[port].revision, firmware, sizeof(firmware)); - - /* Product model */ - ata_id_c_string(id, product, ATA_ID_PROD, sizeof(product)); - memcpy(sata_dev_desc[port].vendor, product, sizeof(product)); - - /* Total sectors */ - n_sectors = ata_id_n_sectors(id); - sata_dev_desc[port].lba = n_sectors; - - /* Check if support LBA48 */ - if (ata_id_has_lba48(id)) { - sata_dev_desc[port].lba48 = 1; - debug("Device support LBA48\n"); - } - - /* Get the NCQ queue depth from device */ - priv->queue_depth = ata_id_queue_depth(id); - - /* Get the xfer mode from device */ - mv_sata_xfer_mode(port, id); - - /* Set the xfer mode to highest speed */ - mv_sata_set_features(port); - - /* Start up */ - mv_start_edma_engine(port); - - return 0; -} diff --git a/drivers/block/sata_sandbox.c b/drivers/block/sata_sandbox.c deleted file mode 100644 index bd967d2..0000000 --- a/drivers/block/sata_sandbox.c +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2015 Google, Inc - * Written by Simon Glass - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include - -int init_sata(int dev) -{ - return 0; -} - -int reset_sata(int dev) -{ - return 0; -} - -int scan_sata(int dev) -{ - return 0; -} - -ulong sata_read(int dev, ulong blknr, lbaint_t blkcnt, void *buffer) -{ - return 0; -} - -ulong sata_write(int dev, ulong blknr, lbaint_t blkcnt, const void *buffer) -{ - return 0; -} diff --git a/drivers/block/sata_sil.c b/drivers/block/sata_sil.c deleted file mode 100644 index daff7d4..0000000 --- a/drivers/block/sata_sil.c +++ /dev/null @@ -1,715 +0,0 @@ -/* - * Copyright (C) 2011 Freescale Semiconductor, Inc. - * Author: Tang Yuantian - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "sata_sil.h" - -/* Convert sectorsize to wordsize */ -#define ATA_SECTOR_WORDS (ATA_SECT_SIZE/2) -#define virt_to_bus(devno, v) pci_virt_to_mem(devno, (void *) (v)) - -static struct sata_info sata_info; - -static struct pci_device_id supported[] = { - {PCI_VENDOR_ID_SILICONIMAGE, PCI_DEVICE_ID_SIL3131}, - {PCI_VENDOR_ID_SILICONIMAGE, PCI_DEVICE_ID_SIL3132}, - {PCI_VENDOR_ID_SILICONIMAGE, PCI_DEVICE_ID_SIL3124}, - {} -}; - -static void sil_sata_dump_fis(struct sata_fis_d2h *s) -{ - printf("Status FIS dump:\n"); - printf("fis_type: %02x\n", s->fis_type); - printf("pm_port_i: %02x\n", s->pm_port_i); - printf("status: %02x\n", s->status); - printf("error: %02x\n", s->error); - printf("lba_low: %02x\n", s->lba_low); - printf("lba_mid: %02x\n", s->lba_mid); - printf("lba_high: %02x\n", s->lba_high); - printf("device: %02x\n", s->device); - printf("lba_low_exp: %02x\n", s->lba_low_exp); - printf("lba_mid_exp: %02x\n", s->lba_mid_exp); - printf("lba_high_exp: %02x\n", s->lba_high_exp); - printf("res1: %02x\n", s->res1); - printf("sector_count: %02x\n", s->sector_count); - printf("sector_count_exp: %02x\n", s->sector_count_exp); -} - -static const char *sata_spd_string(unsigned int speed) -{ - static const char * const spd_str[] = { - "1.5 Gbps", - "3.0 Gbps", - "6.0 Gbps", - }; - - if ((speed - 1) > 2) - return ""; - - return spd_str[speed - 1]; -} - -static u32 ata_wait_register(void *reg, u32 mask, - u32 val, int timeout_msec) -{ - u32 tmp; - - tmp = readl(reg); - while ((tmp & mask) == val && timeout_msec > 0) { - mdelay(1); - timeout_msec--; - tmp = readl(reg); - } - - return tmp; -} - -static void sil_config_port(void *port) -{ - /* configure IRQ WoC */ - writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR); - - /* zero error counters. */ - writew(0x8000, port + PORT_DECODE_ERR_THRESH); - writew(0x8000, port + PORT_CRC_ERR_THRESH); - writew(0x8000, port + PORT_HSHK_ERR_THRESH); - writew(0x0000, port + PORT_DECODE_ERR_CNT); - writew(0x0000, port + PORT_CRC_ERR_CNT); - writew(0x0000, port + PORT_HSHK_ERR_CNT); - - /* always use 64bit activation */ - writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR); - - /* clear port multiplier enable and resume bits */ - writel(PORT_CS_PMP_EN | PORT_CS_PMP_RESUME, port + PORT_CTRL_CLR); -} - -static int sil_init_port(void *port) -{ - u32 tmp; - - writel(PORT_CS_INIT, port + PORT_CTRL_STAT); - ata_wait_register(port + PORT_CTRL_STAT, - PORT_CS_INIT, PORT_CS_INIT, 100); - tmp = ata_wait_register(port + PORT_CTRL_STAT, - PORT_CS_RDY, 0, 100); - - if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY) - return 1; - - return 0; -} - -static void sil_read_fis(int dev, int tag, struct sata_fis_d2h *fis) -{ - struct sil_sata *sata = sata_dev_desc[dev].priv; - void *port = sata->port; - struct sil_prb *prb; - int i; - u32 *src, *dst; - - prb = port + PORT_LRAM + tag * PORT_LRAM_SLOT_SZ; - src = (u32 *)&prb->fis; - dst = (u32 *)fis; - for (i = 0; i < sizeof(struct sata_fis_h2d); i += 4) - *dst++ = readl(src++); -} - -static int sil_exec_cmd(int dev, struct sil_cmd_block *pcmd, int tag) -{ - struct sil_sata *sata = sata_dev_desc[dev].priv; - void *port = sata->port; - u64 paddr = virt_to_bus(sata->devno, pcmd); - u32 irq_mask, irq_stat; - int rc; - - writel(PORT_IRQ_COMPLETE | PORT_IRQ_ERROR, port + PORT_IRQ_ENABLE_CLR); - - /* better to add momery barrior here */ - writel((u32)paddr, port + PORT_CMD_ACTIVATE + tag * 8); - writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + tag * 8 + 4); - - irq_mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT; - irq_stat = ata_wait_register(port + PORT_IRQ_STAT, irq_mask, - 0, 10000); - - /* clear IRQs */ - writel(irq_mask, port + PORT_IRQ_STAT); - irq_stat >>= PORT_IRQ_RAW_SHIFT; - - if (irq_stat & PORT_IRQ_COMPLETE) - rc = 0; - else { - /* force port into known state */ - sil_init_port(port); - if (irq_stat & PORT_IRQ_ERROR) - rc = 1; /* error */ - else - rc = 2; /* busy */ - } - - return rc; -} - -static int sil_cmd_set_feature(int dev) -{ - struct sil_sata *sata = sata_dev_desc[dev].priv; - struct sil_cmd_block cmdb, *pcmd = &cmdb; - struct sata_fis_d2h fis; - u8 udma_cap; - int ret; - - memset((void *)&cmdb, 0, sizeof(struct sil_cmd_block)); - pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; - pcmd->prb.fis.pm_port_c = (1 << 7); - pcmd->prb.fis.command = ATA_CMD_SET_FEATURES; - pcmd->prb.fis.features = SETFEATURES_XFER; - - /* First check the device capablity */ - udma_cap = (u8)(sata->udma & 0xff); - debug("udma_cap %02x\n", udma_cap); - - if (udma_cap == ATA_UDMA6) - pcmd->prb.fis.sector_count = XFER_UDMA_6; - if (udma_cap == ATA_UDMA5) - pcmd->prb.fis.sector_count = XFER_UDMA_5; - if (udma_cap == ATA_UDMA4) - pcmd->prb.fis.sector_count = XFER_UDMA_4; - if (udma_cap == ATA_UDMA3) - pcmd->prb.fis.sector_count = XFER_UDMA_3; - - ret = sil_exec_cmd(dev, pcmd, 0); - if (ret) { - sil_read_fis(dev, 0, &fis); - printf("Err: exe cmd(0x%x).\n", - readl(sata->port + PORT_SERROR)); - sil_sata_dump_fis(&fis); - return 1; - } - - return 0; -} - -static int sil_cmd_identify_device(int dev, u16 *id) -{ - struct sil_sata *sata = sata_dev_desc[dev].priv; - struct sil_cmd_block cmdb, *pcmd = &cmdb; - struct sata_fis_d2h fis; - int ret; - - memset((void *)&cmdb, 0, sizeof(struct sil_cmd_block)); - pcmd->prb.ctrl = cpu_to_le16(PRB_CTRL_PROTOCOL); - pcmd->prb.prot = cpu_to_le16(PRB_PROT_READ); - pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; - pcmd->prb.fis.pm_port_c = (1 << 7); - pcmd->prb.fis.command = ATA_CMD_ID_ATA; - pcmd->sge.addr = cpu_to_le64(virt_to_bus(sata->devno, id)); - pcmd->sge.cnt = cpu_to_le32(sizeof(id[0]) * ATA_ID_WORDS); - pcmd->sge.flags = cpu_to_le32(SGE_TRM); - - ret = sil_exec_cmd(dev, pcmd, 0); - if (ret) { - sil_read_fis(dev, 0, &fis); - printf("Err: id cmd(0x%x).\n", readl(sata->port + PORT_SERROR)); - sil_sata_dump_fis(&fis); - return 1; - } - ata_swap_buf_le16(id, ATA_ID_WORDS); - - return 0; -} - -static int sil_cmd_soft_reset(int dev) -{ - struct sil_cmd_block cmdb, *pcmd = &cmdb; - struct sil_sata *sata = sata_dev_desc[dev].priv; - struct sata_fis_d2h fis; - void *port = sata->port; - int ret; - - /* put the port into known state */ - if (sil_init_port(port)) { - printf("SRST: port %d not ready\n", dev); - return 1; - } - - memset((void *)&cmdb, 0, sizeof(struct sil_cmd_block)); - - pcmd->prb.ctrl = cpu_to_le16(PRB_CTRL_SRST); - pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; - pcmd->prb.fis.pm_port_c = 0xf; - - ret = sil_exec_cmd(dev, &cmdb, 0); - if (ret) { - sil_read_fis(dev, 0, &fis); - printf("SRST cmd error.\n"); - sil_sata_dump_fis(&fis); - return 1; - } - - return 0; -} - -static ulong sil_sata_rw_cmd(int dev, ulong start, ulong blkcnt, - u8 *buffer, int is_write) -{ - struct sil_sata *sata = sata_dev_desc[dev].priv; - struct sil_cmd_block cmdb, *pcmd = &cmdb; - struct sata_fis_d2h fis; - u64 block; - int ret; - - block = (u64)start; - memset(pcmd, 0, sizeof(struct sil_cmd_block)); - pcmd->prb.ctrl = cpu_to_le16(PRB_CTRL_PROTOCOL); - pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; - pcmd->prb.fis.pm_port_c = (1 << 7); - if (is_write) { - pcmd->prb.fis.command = ATA_CMD_WRITE; - pcmd->prb.prot = cpu_to_le16(PRB_PROT_WRITE); - } else { - pcmd->prb.fis.command = ATA_CMD_READ; - pcmd->prb.prot = cpu_to_le16(PRB_PROT_READ); - } - - pcmd->prb.fis.device = ATA_LBA; - pcmd->prb.fis.device |= (block >> 24) & 0xf; - pcmd->prb.fis.lba_high = (block >> 16) & 0xff; - pcmd->prb.fis.lba_mid = (block >> 8) & 0xff; - pcmd->prb.fis.lba_low = block & 0xff; - pcmd->prb.fis.sector_count = (u8)blkcnt & 0xff; - - pcmd->sge.addr = cpu_to_le64(virt_to_bus(sata->devno, buffer)); - pcmd->sge.cnt = cpu_to_le32(blkcnt * ATA_SECT_SIZE); - pcmd->sge.flags = cpu_to_le32(SGE_TRM); - - ret = sil_exec_cmd(dev, pcmd, 0); - if (ret) { - sil_read_fis(dev, 0, &fis); - printf("Err: rw cmd(0x%08x).\n", - readl(sata->port + PORT_SERROR)); - sil_sata_dump_fis(&fis); - return 1; - } - - return blkcnt; -} - -static ulong sil_sata_rw_cmd_ext(int dev, ulong start, ulong blkcnt, - u8 *buffer, int is_write) -{ - struct sil_sata *sata = sata_dev_desc[dev].priv; - struct sil_cmd_block cmdb, *pcmd = &cmdb; - struct sata_fis_d2h fis; - u64 block; - int ret; - - block = (u64)start; - memset(pcmd, 0, sizeof(struct sil_cmd_block)); - pcmd->prb.ctrl = cpu_to_le16(PRB_CTRL_PROTOCOL); - pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; - pcmd->prb.fis.pm_port_c = (1 << 7); - if (is_write) { - pcmd->prb.fis.command = ATA_CMD_WRITE_EXT; - pcmd->prb.prot = cpu_to_le16(PRB_PROT_WRITE); - } else { - pcmd->prb.fis.command = ATA_CMD_READ_EXT; - pcmd->prb.prot = cpu_to_le16(PRB_PROT_READ); - } - - pcmd->prb.fis.lba_high_exp = (block >> 40) & 0xff; - pcmd->prb.fis.lba_mid_exp = (block >> 32) & 0xff; - pcmd->prb.fis.lba_low_exp = (block >> 24) & 0xff; - pcmd->prb.fis.lba_high = (block >> 16) & 0xff; - pcmd->prb.fis.lba_mid = (block >> 8) & 0xff; - pcmd->prb.fis.lba_low = block & 0xff; - pcmd->prb.fis.device = ATA_LBA; - pcmd->prb.fis.sector_count_exp = (blkcnt >> 8) & 0xff; - pcmd->prb.fis.sector_count = blkcnt & 0xff; - - pcmd->sge.addr = cpu_to_le64(virt_to_bus(sata->devno, buffer)); - pcmd->sge.cnt = cpu_to_le32(blkcnt * ATA_SECT_SIZE); - pcmd->sge.flags = cpu_to_le32(SGE_TRM); - - ret = sil_exec_cmd(dev, pcmd, 0); - if (ret) { - sil_read_fis(dev, 0, &fis); - printf("Err: rw ext cmd(0x%08x).\n", - readl(sata->port + PORT_SERROR)); - sil_sata_dump_fis(&fis); - return 1; - } - - return blkcnt; -} - -static ulong sil_sata_rw_lba28(int dev, ulong blknr, lbaint_t blkcnt, - const void *buffer, int is_write) -{ - ulong start, blks, max_blks; - u8 *addr; - - start = blknr; - blks = blkcnt; - addr = (u8 *)buffer; - - max_blks = ATA_MAX_SECTORS; - do { - if (blks > max_blks) { - sil_sata_rw_cmd(dev, start, max_blks, addr, is_write); - start += max_blks; - blks -= max_blks; - addr += ATA_SECT_SIZE * max_blks; - } else { - sil_sata_rw_cmd(dev, start, blks, addr, is_write); - start += blks; - blks = 0; - addr += ATA_SECT_SIZE * blks; - } - } while (blks != 0); - - return blkcnt; -} - -static ulong sil_sata_rw_lba48(int dev, ulong blknr, lbaint_t blkcnt, - const void *buffer, int is_write) -{ - ulong start, blks, max_blks; - u8 *addr; - - start = blknr; - blks = blkcnt; - addr = (u8 *)buffer; - - max_blks = ATA_MAX_SECTORS_LBA48; - do { - if (blks > max_blks) { - sil_sata_rw_cmd_ext(dev, start, max_blks, - addr, is_write); - start += max_blks; - blks -= max_blks; - addr += ATA_SECT_SIZE * max_blks; - } else { - sil_sata_rw_cmd_ext(dev, start, blks, - addr, is_write); - start += blks; - blks = 0; - addr += ATA_SECT_SIZE * blks; - } - } while (blks != 0); - - return blkcnt; -} - -static void sil_sata_cmd_flush_cache(int dev) -{ - struct sil_cmd_block cmdb, *pcmd = &cmdb; - - memset((void *)pcmd, 0, sizeof(struct sil_cmd_block)); - pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; - pcmd->prb.fis.pm_port_c = (1 << 7); - pcmd->prb.fis.command = ATA_CMD_FLUSH; - - sil_exec_cmd(dev, pcmd, 0); -} - -static void sil_sata_cmd_flush_cache_ext(int dev) -{ - struct sil_cmd_block cmdb, *pcmd = &cmdb; - - memset((void *)pcmd, 0, sizeof(struct sil_cmd_block)); - pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; - pcmd->prb.fis.pm_port_c = (1 << 7); - pcmd->prb.fis.command = ATA_CMD_FLUSH_EXT; - - sil_exec_cmd(dev, pcmd, 0); -} - -static void sil_sata_init_wcache(int dev, u16 *id) -{ - struct sil_sata *sata = sata_dev_desc[dev].priv; - - if (ata_id_has_wcache(id) && ata_id_wcache_enabled(id)) - sata->wcache = 1; - if (ata_id_has_flush(id)) - sata->flush = 1; - if (ata_id_has_flush_ext(id)) - sata->flush_ext = 1; -} - -static int sil_sata_get_wcache(int dev) -{ - struct sil_sata *sata = sata_dev_desc[dev].priv; - - return sata->wcache; -} - -static int sil_sata_get_flush(int dev) -{ - struct sil_sata *sata = sata_dev_desc[dev].priv; - - return sata->flush; -} - -static int sil_sata_get_flush_ext(int dev) -{ - struct sil_sata *sata = sata_dev_desc[dev].priv; - - return sata->flush_ext; -} - -/* - * SATA interface between low level driver and command layer - */ -ulong sata_read(int dev, ulong blknr, lbaint_t blkcnt, void *buffer) -{ - struct sil_sata *sata = sata_dev_desc[dev].priv; - ulong rc; - - if (sata->lba48) - rc = sil_sata_rw_lba48(dev, blknr, blkcnt, buffer, READ_CMD); - else - rc = sil_sata_rw_lba28(dev, blknr, blkcnt, buffer, READ_CMD); - - return rc; -} - -/* - * SATA interface between low level driver and command layer - */ -ulong sata_write(int dev, ulong blknr, lbaint_t blkcnt, const void *buffer) -{ - struct sil_sata *sata = sata_dev_desc[dev].priv; - ulong rc; - - if (sata->lba48) { - rc = sil_sata_rw_lba48(dev, blknr, blkcnt, buffer, WRITE_CMD); - if (sil_sata_get_wcache(dev) && sil_sata_get_flush_ext(dev)) - sil_sata_cmd_flush_cache_ext(dev); - } else { - rc = sil_sata_rw_lba28(dev, blknr, blkcnt, buffer, WRITE_CMD); - if (sil_sata_get_wcache(dev) && sil_sata_get_flush(dev)) - sil_sata_cmd_flush_cache(dev); - } - - return rc; -} - -/* - * SATA interface between low level driver and command layer - */ -int init_sata(int dev) -{ - static int init_done, idx; - pci_dev_t devno; - u16 word; - - if (init_done == 1 && dev < sata_info.maxport) - return 0; - - init_done = 1; - - /* Find PCI device(s) */ - devno = pci_find_devices(supported, idx++); - if (devno == -1) - return 1; - - pci_read_config_word(devno, PCI_DEVICE_ID, &word); - - /* get the port count */ - word &= 0xf; - - sata_info.portbase = sata_info.maxport; - sata_info.maxport = sata_info.portbase + word; - sata_info.devno = devno; - - /* Read out all BARs */ - sata_info.iobase[0] = (ulong)pci_map_bar(devno, - PCI_BASE_ADDRESS_0, PCI_REGION_MEM); - sata_info.iobase[1] = (ulong)pci_map_bar(devno, - PCI_BASE_ADDRESS_2, PCI_REGION_MEM); - sata_info.iobase[2] = (ulong)pci_map_bar(devno, - PCI_BASE_ADDRESS_4, PCI_REGION_MEM); - - /* mask out the unused bits */ - sata_info.iobase[0] &= 0xffffff80; - sata_info.iobase[1] &= 0xfffffc00; - sata_info.iobase[2] &= 0xffffff80; - - /* Enable Bus Mastering and memory region */ - pci_write_config_word(devno, PCI_COMMAND, - PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); - - /* Check if mem accesses and Bus Mastering are enabled. */ - pci_read_config_word(devno, PCI_COMMAND, &word); - if (!(word & PCI_COMMAND_MEMORY) || - (!(word & PCI_COMMAND_MASTER))) { - printf("Error: Can not enable MEM access or Bus Mastering.\n"); - debug("PCI command: %04x\n", word); - return 1; - } - - /* GPIO off */ - writel(0, (void *)(sata_info.iobase[0] + HOST_FLASH_CMD)); - /* clear global reset & mask interrupts during initialization */ - writel(0, (void *)(sata_info.iobase[0] + HOST_CTRL)); - - return 0; -} - -int reset_sata(int dev) -{ - return 0; -} - -/* - * SATA interface between low level driver and command layer - */ -int scan_sata(int dev) -{ - unsigned char serial[ATA_ID_SERNO_LEN + 1]; - unsigned char firmware[ATA_ID_FW_REV_LEN + 1]; - unsigned char product[ATA_ID_PROD_LEN + 1]; - struct sil_sata *sata; - void *port; - int cnt; - u16 *id; - u32 tmp; - - if (dev >= sata_info.maxport) { - printf("SATA#%d is not present\n", dev); - return 1; - } - - printf("SATA#%d\n", dev); - port = (void *)sata_info.iobase[1] + - PORT_REGS_SIZE * (dev - sata_info.portbase); - - /* Initial PHY setting */ - writel(0x20c, port + PORT_PHY_CFG); - - /* clear port RST */ - tmp = readl(port + PORT_CTRL_STAT); - if (tmp & PORT_CS_PORT_RST) { - writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR); - tmp = ata_wait_register(port + PORT_CTRL_STAT, - PORT_CS_PORT_RST, PORT_CS_PORT_RST, 100); - if (tmp & PORT_CS_PORT_RST) - printf("Err: Failed to clear port RST\n"); - } - - /* Check if device is present */ - for (cnt = 0; cnt < 100; cnt++) { - tmp = readl(port + PORT_SSTATUS); - if ((tmp & 0xF) == 0x3) - break; - mdelay(1); - } - - tmp = readl(port + PORT_SSTATUS); - if ((tmp & 0xf) != 0x3) { - printf(" (No RDY)\n"); - return 1; - } - - /* Wait for port ready */ - tmp = ata_wait_register(port + PORT_CTRL_STAT, - PORT_CS_RDY, PORT_CS_RDY, 100); - if ((tmp & PORT_CS_RDY) != PORT_CS_RDY) { - printf("%d port not ready.\n", dev); - return 1; - } - - /* configure port */ - sil_config_port(port); - - /* Reset port */ - writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT); - readl(port + PORT_CTRL_STAT); - tmp = ata_wait_register(port + PORT_CTRL_STAT, PORT_CS_DEV_RST, - PORT_CS_DEV_RST, 100); - if (tmp & PORT_CS_DEV_RST) { - printf("%d port reset failed.\n", dev); - return 1; - } - - sata = (struct sil_sata *)malloc(sizeof(struct sil_sata)); - if (!sata) { - printf("%d no memory.\n", dev); - return 1; - } - memset((void *)sata, 0, sizeof(struct sil_sata)); - - /* turn on port interrupt */ - tmp = readl((void *)(sata_info.iobase[0] + HOST_CTRL)); - tmp |= (1 << (dev - sata_info.portbase)); - writel(tmp, (void *)(sata_info.iobase[0] + HOST_CTRL)); - - /* Save the private struct to block device struct */ - sata_dev_desc[dev].priv = (void *)sata; - sata->port = port; - sata->devno = sata_info.devno; - sprintf(sata->name, "SATA#%d", dev); - sil_cmd_soft_reset(dev); - tmp = readl(port + PORT_SSTATUS); - tmp = (tmp >> 4) & 0xf; - printf(" (%s)\n", sata_spd_string(tmp)); - - id = (u16 *)malloc(ATA_ID_WORDS * 2); - if (!id) { - printf("Id malloc failed\n"); - free((void *)sata); - return 1; - } - sil_cmd_identify_device(dev, id); - -#ifdef CONFIG_LBA48 - /* Check if support LBA48 */ - if (ata_id_has_lba48(id)) { - sata_dev_desc[dev].lba48 = 1; - sata->lba48 = 1; - debug("Device supports LBA48\n"); - } else - debug("Device supports LBA28\n"); -#endif - - /* Serial number */ - ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial)); - memcpy(sata_dev_desc[dev].product, serial, sizeof(serial)); - - /* Firmware version */ - ata_id_c_string(id, firmware, ATA_ID_FW_REV, sizeof(firmware)); - memcpy(sata_dev_desc[dev].revision, firmware, sizeof(firmware)); - - /* Product model */ - ata_id_c_string(id, product, ATA_ID_PROD, sizeof(product)); - memcpy(sata_dev_desc[dev].vendor, product, sizeof(product)); - - /* Totoal sectors */ - sata_dev_desc[dev].lba = ata_id_n_sectors(id); - - sil_sata_init_wcache(dev, id); - sil_cmd_set_feature(dev); - -#ifdef DEBUG - sil_cmd_identify_device(dev, id); - ata_dump_id(id); -#endif - free((void *)id); - - return 0; -} diff --git a/drivers/block/sata_sil.h b/drivers/block/sata_sil.h deleted file mode 100644 index 55954ef..0000000 --- a/drivers/block/sata_sil.h +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (C) 2011 Freescale Semiconductor, Inc. - * Author: Tang Yuantian - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#ifndef SATA_SIL3132_H -#define SATA_SIL3132_H - -#define READ_CMD 0 -#define WRITE_CMD 1 - -/* - * SATA device driver struct for each dev - */ -struct sil_sata { - char name[12]; - void *port; /* the port base address */ - int lba48; - u16 pio; - u16 mwdma; - u16 udma; - pci_dev_t devno; - int wcache; - int flush; - int flush_ext; -}; - -/* sata info for each controller */ -struct sata_info { - ulong iobase[3]; - pci_dev_t devno; - int portbase; - int maxport; -}; - -/* - * Scatter gather entry (SGE),MUST 8 bytes aligned - */ -struct sil_sge { - __le64 addr; - __le32 cnt; - __le32 flags; -} __attribute__ ((aligned(8), packed)); - -/* - * Port request block, MUST 8 bytes aligned - */ -struct sil_prb { - __le16 ctrl; - __le16 prot; - __le32 rx_cnt; - struct sata_fis_h2d fis; -} __attribute__ ((aligned(8), packed)); - -struct sil_cmd_block { - struct sil_prb prb; - struct sil_sge sge; -}; - -enum { - HOST_SLOT_STAT = 0x00, /* 32 bit slot stat * 4 */ - HOST_CTRL = 0x40, - HOST_IRQ_STAT = 0x44, - HOST_PHY_CFG = 0x48, - HOST_BIST_CTRL = 0x50, - HOST_BIST_PTRN = 0x54, - HOST_BIST_STAT = 0x58, - HOST_MEM_BIST_STAT = 0x5c, - HOST_FLASH_CMD = 0x70, - /* 8 bit regs */ - HOST_FLASH_DATA = 0x74, - HOST_TRANSITION_DETECT = 0x75, - HOST_GPIO_CTRL = 0x76, - HOST_I2C_ADDR = 0x78, /* 32 bit */ - HOST_I2C_DATA = 0x7c, - HOST_I2C_XFER_CNT = 0x7e, - HOST_I2C_CTRL = 0x7f, - - /* HOST_SLOT_STAT bits */ - HOST_SSTAT_ATTN = (1 << 31), - - /* HOST_CTRL bits */ - HOST_CTRL_M66EN = (1 << 16), /* M66EN PCI bus signal */ - HOST_CTRL_TRDY = (1 << 17), /* latched PCI TRDY */ - HOST_CTRL_STOP = (1 << 18), /* latched PCI STOP */ - HOST_CTRL_DEVSEL = (1 << 19), /* latched PCI DEVSEL */ - HOST_CTRL_REQ64 = (1 << 20), /* latched PCI REQ64 */ - HOST_CTRL_GLOBAL_RST = (1 << 31), /* global reset */ - - /* - * Port registers - * (8192 bytes @ +0x0000, +0x2000, +0x4000 and +0x6000 @ BAR2) - */ - PORT_REGS_SIZE = 0x2000, - - PORT_LRAM = 0x0000, /* 31 LRAM slots and PMP regs */ - PORT_LRAM_SLOT_SZ = 0x0080, /* 32 bytes PRB + 2 SGE, ACT... */ - - PORT_PMP = 0x0f80, /* 8 bytes PMP * 16 (128 bytes) */ - PORT_PMP_STATUS = 0x0000, /* port device status offset */ - PORT_PMP_QACTIVE = 0x0004, /* port device QActive offset */ - PORT_PMP_SIZE = 0x0008, /* 8 bytes per PMP */ - - /* 32 bit regs */ - PORT_CTRL_STAT = 0x1000, /* write: ctrl-set, read: stat */ - PORT_CTRL_CLR = 0x1004, /* write: ctrl-clear */ - PORT_IRQ_STAT = 0x1008, /* high: status, low: interrupt */ - PORT_IRQ_ENABLE_SET = 0x1010, /* write: enable-set */ - PORT_IRQ_ENABLE_CLR = 0x1014, /* write: enable-clear */ - PORT_ACTIVATE_UPPER_ADDR = 0x101c, - PORT_EXEC_FIFO = 0x1020, /* command execution fifo */ - PORT_CMD_ERR = 0x1024, /* command error number */ - PORT_FIS_CFG = 0x1028, - PORT_FIFO_THRES = 0x102c, - - /* 16 bit regs */ - PORT_DECODE_ERR_CNT = 0x1040, - PORT_DECODE_ERR_THRESH = 0x1042, - PORT_CRC_ERR_CNT = 0x1044, - PORT_CRC_ERR_THRESH = 0x1046, - PORT_HSHK_ERR_CNT = 0x1048, - PORT_HSHK_ERR_THRESH = 0x104a, - - /* 32 bit regs */ - PORT_PHY_CFG = 0x1050, - PORT_SLOT_STAT = 0x1800, - PORT_CMD_ACTIVATE = 0x1c00, /* 64 bit cmd activate * 31 */ - PORT_CONTEXT = 0x1e04, - PORT_EXEC_DIAG = 0x1e00, /* 32bit exec diag * 16 */ - PORT_PSD_DIAG = 0x1e40, /* 32bit psd diag * 16 */ - PORT_SCONTROL = 0x1f00, - PORT_SSTATUS = 0x1f04, - PORT_SERROR = 0x1f08, - PORT_SACTIVE = 0x1f0c, - - /* PORT_CTRL_STAT bits */ - PORT_CS_PORT_RST = (1 << 0), /* port reset */ - PORT_CS_DEV_RST = (1 << 1), /* device reset */ - PORT_CS_INIT = (1 << 2), /* port initialize */ - PORT_CS_IRQ_WOC = (1 << 3), /* interrupt write one to clear */ - PORT_CS_CDB16 = (1 << 5), /* 0=12b cdb, 1=16b cdb */ - PORT_CS_PMP_RESUME = (1 << 6), /* PMP resume */ - PORT_CS_32BIT_ACTV = (1 << 10), /* 32-bit activation */ - PORT_CS_PMP_EN = (1 << 13), /* port multiplier enable */ - PORT_CS_RDY = (1 << 31), /* port ready to accept commands */ - - /* PORT_IRQ_STAT/ENABLE_SET/CLR */ - /* bits[11:0] are masked */ - PORT_IRQ_COMPLETE = (1 << 0), /* command(s) completed */ - PORT_IRQ_ERROR = (1 << 1), /* command execution error */ - PORT_IRQ_PORTRDY_CHG = (1 << 2), /* port ready change */ - PORT_IRQ_PWR_CHG = (1 << 3), /* power management change */ - PORT_IRQ_PHYRDY_CHG = (1 << 4), /* PHY ready change */ - PORT_IRQ_COMWAKE = (1 << 5), /* COMWAKE received */ - PORT_IRQ_UNK_FIS = (1 << 6), /* unknown FIS received */ - PORT_IRQ_DEV_XCHG = (1 << 7), /* device exchanged */ - PORT_IRQ_8B10B = (1 << 8), /* 8b/10b decode error threshold */ - PORT_IRQ_CRC = (1 << 9), /* CRC error threshold */ - PORT_IRQ_HANDSHAKE = (1 << 10), /* handshake error threshold */ - PORT_IRQ_SDB_NOTIFY = (1 << 11), /* SDB notify received */ - - DEF_PORT_IRQ = PORT_IRQ_COMPLETE | PORT_IRQ_ERROR | - PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG | - PORT_IRQ_UNK_FIS | PORT_IRQ_SDB_NOTIFY, - - /* bits[27:16] are unmasked (raw) */ - PORT_IRQ_RAW_SHIFT = 16, - PORT_IRQ_MASKED_MASK = 0x7ff, - PORT_IRQ_RAW_MASK = (0x7ff << PORT_IRQ_RAW_SHIFT), - - /* ENABLE_SET/CLR specific, intr steering - 2 bit field */ - PORT_IRQ_STEER_SHIFT = 30, - PORT_IRQ_STEER_MASK = (3 << PORT_IRQ_STEER_SHIFT), - - /* PORT_CMD_ERR constants */ - PORT_CERR_DEV = 1, /* Error bit in D2H Register FIS */ - PORT_CERR_SDB = 2, /* Error bit in SDB FIS */ - PORT_CERR_DATA = 3, /* Error in data FIS not detected by dev */ - PORT_CERR_SEND = 4, /* Initial cmd FIS transmission failure */ - PORT_CERR_INCONSISTENT = 5, /* Protocol mismatch */ - PORT_CERR_DIRECTION = 6, /* Data direction mismatch */ - PORT_CERR_UNDERRUN = 7, /* Ran out of SGEs while writing */ - PORT_CERR_OVERRUN = 8, /* Ran out of SGEs while reading */ - - /* bits of PRB control field */ - PRB_CTRL_PROTOCOL = (1 << 0), /* override def. ATA protocol */ - PRB_CTRL_PACKET_READ = (1 << 4), /* PACKET cmd read */ - PRB_CTRL_PACKET_WRITE = (1 << 5), /* PACKET cmd write */ - PRB_CTRL_NIEN = (1 << 6), /* Mask completion irq */ - PRB_CTRL_SRST = (1 << 7), /* Soft reset request (ign BSY?) */ - - /* PRB protocol field */ - PRB_PROT_PACKET = (1 << 0), - PRB_PROT_TCQ = (1 << 1), - PRB_PROT_NCQ = (1 << 2), - PRB_PROT_READ = (1 << 3), - PRB_PROT_WRITE = (1 << 4), - PRB_PROT_TRANSPARENT = (1 << 5), - - /* - * Other constants - */ - SGE_TRM = (1 << 31), /* Last SGE in chain */ - SGE_LNK = (1 << 30), /* linked list - Points to SGT, not SGE */ - SGE_DRD = (1 << 29), /* discard data read (/dev/null) - data address ignored */ - - CMD_ERR = 0x21, -}; - -#endif diff --git a/drivers/block/sata_sil3114.c b/drivers/block/sata_sil3114.c deleted file mode 100644 index 61ffb66..0000000 --- a/drivers/block/sata_sil3114.c +++ /dev/null @@ -1,835 +0,0 @@ -/* - * Copyright (C) Excito Elektronik i SkÃ¥ne AB, All rights reserved. - * Author: Tor Krill - * - * SPDX-License-Identifier: GPL-2.0+ - * - * This is a driver for Silicon Image sil3114 sata chip modelled on - * the ata_piix driver - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "sata_sil3114.h" - -/* Convert sectorsize to wordsize */ -#define ATA_SECTOR_WORDS (ATA_SECT_SIZE/2) - -/* Forwards */ -u8 sil3114_spin_up (int num); -u8 sil3114_spin_down (int num); -static int sata_bus_softreset (int num); -static void sata_identify (int num, int dev); -static u8 check_power_mode (int num); -static void sata_port (struct sata_ioports *ioport); -static void set_Feature_cmd (int num, int dev); -static u8 sata_busy_wait (struct sata_ioports *ioaddr, int bits, - unsigned int max, u8 usealtstatus); -static u8 sata_chk_status (struct sata_ioports *ioaddr, u8 usealtstatus); -static void msleep (int count); - -static u32 iobase[6] = { 0, 0, 0, 0, 0, 0}; /* PCI BAR registers for device */ - -static struct sata_port port[CONFIG_SYS_SATA_MAX_DEVICE]; - -static void output_data (struct sata_ioports *ioaddr, u16 * sect_buf, int words) -{ - while (words--) { - __raw_writew (*sect_buf++, (void *)ioaddr->data_addr); - } -} - -static int input_data (struct sata_ioports *ioaddr, u16 * sect_buf, int words) -{ - while (words--) { - *sect_buf++ = __raw_readw ((void *)ioaddr->data_addr); - } - return 0; -} - -static int sata_bus_softreset (int num) -{ - u8 status = 0; - - port[num].dev_mask = 1; - - port[num].ctl_reg = 0x08; /*Default value of control reg */ - writeb (port[num].ctl_reg, port[num].ioaddr.ctl_addr); - udelay (10); - writeb (port[num].ctl_reg | ATA_SRST, port[num].ioaddr.ctl_addr); - udelay (10); - writeb (port[num].ctl_reg, port[num].ioaddr.ctl_addr); - - /* spec mandates ">= 2ms" before checking status. - * We wait 150ms, because that was the magic delay used for - * ATAPI devices in Hale Landis's ATADRVR, for the period of time - * between when the ATA command register is written, and then - * status is checked. Because waiting for "a while" before - * checking status is fine, post SRST, we perform this magic - * delay here as well. - */ - msleep (150); - status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 300, 0); - while ((status & ATA_BUSY)) { - msleep (100); - status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 3, 0); - } - - if (status & ATA_BUSY) { - printf ("ata%u is slow to respond,plz be patient\n", num); - } - - while ((status & ATA_BUSY)) { - msleep (100); - status = sata_chk_status (&port[num].ioaddr, 0); - } - - if (status & ATA_BUSY) { - printf ("ata%u failed to respond : ", num); - printf ("bus reset failed\n"); - port[num].dev_mask = 0; - return 1; - } - return 0; -} - -static void sata_identify (int num, int dev) -{ - u8 cmd = 0, status = 0, devno = num; - u16 iobuf[ATA_SECTOR_WORDS]; - u64 n_sectors = 0; - - memset (iobuf, 0, sizeof (iobuf)); - - if (!(port[num].dev_mask & 0x01)) { - printf ("dev%d is not present on port#%d\n", dev, num); - return; - } - - debug ("port=%d dev=%d\n", num, dev); - - status = 0; - cmd = ATA_CMD_ID_ATA; /*Device Identify Command */ - writeb (cmd, port[num].ioaddr.command_addr); - readb (port[num].ioaddr.altstatus_addr); - udelay (10); - - status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 1000, 0); - if (status & ATA_ERR) { - printf ("\ndevice not responding\n"); - port[num].dev_mask &= ~0x01; - return; - } - - input_data (&port[num].ioaddr, iobuf, ATA_SECTOR_WORDS); - - ata_swap_buf_le16 (iobuf, ATA_SECTOR_WORDS); - - debug ("Specific config: %x\n", iobuf[2]); - - /* we require LBA and DMA support (bits 8 & 9 of word 49) */ - if (!ata_id_has_dma (iobuf) || !ata_id_has_lba (iobuf)) { - debug ("ata%u: no dma/lba\n", num); - } -#ifdef DEBUG - ata_dump_id (iobuf); -#endif - n_sectors = ata_id_n_sectors (iobuf); - - if (n_sectors == 0) { - port[num].dev_mask &= ~0x01; - return; - } - ata_id_c_string (iobuf, (unsigned char *)sata_dev_desc[devno].revision, - ATA_ID_FW_REV, sizeof (sata_dev_desc[devno].revision)); - ata_id_c_string (iobuf, (unsigned char *)sata_dev_desc[devno].vendor, - ATA_ID_PROD, sizeof (sata_dev_desc[devno].vendor)); - ata_id_c_string (iobuf, (unsigned char *)sata_dev_desc[devno].product, - ATA_ID_SERNO, sizeof (sata_dev_desc[devno].product)); - - /* TODO - atm we asume harddisk ie not removable */ - sata_dev_desc[devno].removable = 0; - - sata_dev_desc[devno].lba = (u32) n_sectors; - debug("lba=0x%lx\n", sata_dev_desc[devno].lba); - -#ifdef CONFIG_LBA48 - if (iobuf[83] & (1 << 10)) { - sata_dev_desc[devno].lba48 = 1; - } else { - sata_dev_desc[devno].lba48 = 0; - } -#endif - - /* assuming HD */ - sata_dev_desc[devno].type = DEV_TYPE_HARDDISK; - sata_dev_desc[devno].blksz = ATA_SECT_SIZE; - sata_dev_desc[devno].lun = 0; /* just to fill something in... */ -} - -static void set_Feature_cmd (int num, int dev) -{ - u8 status = 0; - - if (!(port[num].dev_mask & 0x01)) { - debug ("dev%d is not present on port#%d\n", dev, num); - return; - } - - writeb (SETFEATURES_XFER, port[num].ioaddr.feature_addr); - writeb (XFER_PIO_4, port[num].ioaddr.nsect_addr); - writeb (0, port[num].ioaddr.lbal_addr); - writeb (0, port[num].ioaddr.lbam_addr); - writeb (0, port[num].ioaddr.lbah_addr); - - writeb (ATA_DEVICE_OBS, port[num].ioaddr.device_addr); - writeb (ATA_CMD_SET_FEATURES, port[num].ioaddr.command_addr); - - udelay (50); - msleep (150); - - status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 5000, 0); - if ((status & (ATA_BUSY | ATA_ERR))) { - printf ("Error : status 0x%02x\n", status); - port[num].dev_mask &= ~0x01; - } -} - -u8 sil3114_spin_down (int num) -{ - u8 status = 0; - - debug ("Spin down disk\n"); - - if (!(port[num].dev_mask & 0x01)) { - debug ("Device ata%d is not present\n", num); - return 1; - } - - if ((status = check_power_mode (num)) == 0x00) { - debug ("Already in standby\n"); - return 0; - } - - if (status == 0x01) { - printf ("Failed to check power mode on ata%d\n", num); - return 1; - } - - if (!((status = sata_chk_status (&port[num].ioaddr, 0)) & ATA_DRDY)) { - printf ("Device ata%d not ready\n", num); - return 1; - } - - writeb (0x00, port[num].ioaddr.feature_addr); - - writeb (0x00, port[num].ioaddr.nsect_addr); - writeb (0x00, port[num].ioaddr.lbal_addr); - writeb (0x00, port[num].ioaddr.lbam_addr); - writeb (0x00, port[num].ioaddr.lbah_addr); - - writeb (ATA_DEVICE_OBS, port[num].ioaddr.device_addr); - writeb (ATA_CMD_STANDBY, port[num].ioaddr.command_addr); - - status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 30000, 0); - if ((status & (ATA_BUSY | ATA_ERR))) { - printf ("Error waiting for disk spin down: status 0x%02x\n", - status); - port[num].dev_mask &= ~0x01; - return 1; - } - return 0; -} - -u8 sil3114_spin_up (int num) -{ - u8 status = 0; - - debug ("Spin up disk\n"); - - if (!(port[num].dev_mask & 0x01)) { - debug ("Device ata%d is not present\n", num); - return 1; - } - - if ((status = check_power_mode (num)) != 0x00) { - if (status == 0x01) { - printf ("Failed to check power mode on ata%d\n", num); - return 1; - } else { - /* should be up and running already */ - return 0; - } - } - - if (!((status = sata_chk_status (&port[num].ioaddr, 0)) & ATA_DRDY)) { - printf ("Device ata%d not ready\n", num); - return 1; - } - - debug ("Stautus of device check: %d\n", status); - - writeb (0x00, port[num].ioaddr.feature_addr); - - writeb (0x00, port[num].ioaddr.nsect_addr); - writeb (0x00, port[num].ioaddr.lbal_addr); - writeb (0x00, port[num].ioaddr.lbam_addr); - writeb (0x00, port[num].ioaddr.lbah_addr); - - writeb (ATA_DEVICE_OBS, port[num].ioaddr.device_addr); - writeb (ATA_CMD_IDLE, port[num].ioaddr.command_addr); - - status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 30000, 0); - if ((status & (ATA_BUSY | ATA_ERR))) { - printf ("Error waiting for disk spin up: status 0x%02x\n", - status); - port[num].dev_mask &= ~0x01; - return 1; - } - - /* Wait for disk to enter Active state */ - do { - msleep (10); - status = check_power_mode (num); - } while ((status == 0x00) || (status == 0x80)); - - if (status == 0x01) { - printf ("Falied waiting for disk to spin up\n"); - return 1; - } - - return 0; -} - -/* Return value is not the usual here - * 0x00 - Device stand by - * 0x01 - Operation failed - * 0x80 - Device idle - * 0xff - Device active -*/ -static u8 check_power_mode (int num) -{ - u8 status = 0; - u8 res = 0; - if (!(port[num].dev_mask & 0x01)) { - debug ("Device ata%d is not present\n", num); - return 1; - } - - if (!(sata_chk_status (&port[num].ioaddr, 0) & ATA_DRDY)) { - printf ("Device ata%d not ready\n", num); - return 1; - } - - writeb (0, port[num].ioaddr.feature_addr); - writeb (0, port[num].ioaddr.nsect_addr); - writeb (0, port[num].ioaddr.lbal_addr); - writeb (0, port[num].ioaddr.lbam_addr); - writeb (0, port[num].ioaddr.lbah_addr); - - writeb (ATA_DEVICE_OBS, port[num].ioaddr.device_addr); - writeb (ATA_CMD_CHK_POWER, port[num].ioaddr.command_addr); - - status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 5000, 0); - if ((status & (ATA_BUSY | ATA_ERR))) { - printf - ("Error waiting for check power mode complete : status 0x%02x\n", - status); - port[num].dev_mask &= ~0x01; - return 1; - } - res = readb (port[num].ioaddr.nsect_addr); - debug ("Check powermode: %d\n", res); - return res; - -} - -static void sata_port (struct sata_ioports *ioport) -{ - ioport->data_addr = ioport->cmd_addr + ATA_REG_DATA; - ioport->error_addr = ioport->cmd_addr + ATA_REG_ERR; - ioport->feature_addr = ioport->cmd_addr + ATA_REG_FEATURE; - ioport->nsect_addr = ioport->cmd_addr + ATA_REG_NSECT; - ioport->lbal_addr = ioport->cmd_addr + ATA_REG_LBAL; - ioport->lbam_addr = ioport->cmd_addr + ATA_REG_LBAM; - ioport->lbah_addr = ioport->cmd_addr + ATA_REG_LBAH; - ioport->device_addr = ioport->cmd_addr + ATA_REG_DEVICE; - ioport->status_addr = ioport->cmd_addr + ATA_REG_STATUS; - ioport->command_addr = ioport->cmd_addr + ATA_REG_CMD; -} - -static u8 wait_for_irq (int num, unsigned int max) -{ - - u32 port = iobase[5]; - switch (num) { - case 0: - port += VND_TF_CNST_CH0; - break; - case 1: - port += VND_TF_CNST_CH1; - break; - case 2: - port += VND_TF_CNST_CH2; - break; - case 3: - port += VND_TF_CNST_CH3; - break; - default: - return 1; - } - - do { - if (readl (port) & VND_TF_CNST_INTST) { - break; - } - udelay (1000); - max--; - } while ((max > 0)); - - return (max == 0); -} - -static u8 sata_busy_wait (struct sata_ioports *ioaddr, int bits, - unsigned int max, u8 usealtstatus) -{ - u8 status; - - do { - if (!((status = sata_chk_status (ioaddr, usealtstatus)) & bits)) { - break; - } - udelay (1000); - max--; - } while ((status & bits) && (max > 0)); - - return status; -} - -static u8 sata_chk_status (struct sata_ioports *ioaddr, u8 usealtstatus) -{ - if (!usealtstatus) { - return readb (ioaddr->status_addr); - } else { - return readb (ioaddr->altstatus_addr); - } -} - -static void msleep (int count) -{ - int i; - - for (i = 0; i < count; i++) - udelay (1000); -} - -/* Read up to 255 sectors - * - * Returns sectors read -*/ -static u8 do_one_read (int device, ulong block, u8 blkcnt, u16 * buff, - uchar lba48) -{ - - u8 sr = 0; - u8 status; - u64 blknr = (u64) block; - - if (!(sata_chk_status (&port[device].ioaddr, 0) & ATA_DRDY)) { - printf ("Device ata%d not ready\n", device); - return 0; - } - - /* Set up transfer */ -#ifdef CONFIG_LBA48 - if (lba48) { - /* write high bits */ - writeb (0, port[device].ioaddr.nsect_addr); - writeb ((blknr >> 24) & 0xFF, port[device].ioaddr.lbal_addr); - writeb ((blknr >> 32) & 0xFF, port[device].ioaddr.lbam_addr); - writeb ((blknr >> 40) & 0xFF, port[device].ioaddr.lbah_addr); - } -#endif - writeb (blkcnt, port[device].ioaddr.nsect_addr); - writeb (((blknr) >> 0) & 0xFF, port[device].ioaddr.lbal_addr); - writeb ((blknr >> 8) & 0xFF, port[device].ioaddr.lbam_addr); - writeb ((blknr >> 16) & 0xFF, port[device].ioaddr.lbah_addr); - -#ifdef CONFIG_LBA48 - if (lba48) { - writeb (ATA_LBA, port[device].ioaddr.device_addr); - writeb (ATA_CMD_PIO_READ_EXT, port[device].ioaddr.command_addr); - } else -#endif - { - writeb (ATA_LBA | ((blknr >> 24) & 0xF), - port[device].ioaddr.device_addr); - writeb (ATA_CMD_PIO_READ, port[device].ioaddr.command_addr); - } - - status = sata_busy_wait (&port[device].ioaddr, ATA_BUSY, 10000, 1); - - if (status & ATA_BUSY) { - u8 err = 0; - - printf ("Device %d not responding status %d\n", device, status); - err = readb (port[device].ioaddr.error_addr); - printf ("Error reg = 0x%x\n", err); - - return (sr); - } - while (blkcnt--) { - - if (wait_for_irq (device, 500)) { - printf ("ata%u irq failed\n", device); - return sr; - } - - status = sata_chk_status (&port[device].ioaddr, 0); - if (status & ATA_ERR) { - printf ("ata%u error %d\n", device, - readb (port[device].ioaddr.error_addr)); - return sr; - } - /* Read one sector */ - input_data (&port[device].ioaddr, buff, ATA_SECTOR_WORDS); - buff += ATA_SECTOR_WORDS; - sr++; - - } - return sr; -} - -ulong sata_read (int device, ulong block, lbaint_t blkcnt, void *buff) -{ - ulong n = 0, sread; - u16 *buffer = (u16 *) buff; - u8 status = 0; - u64 blknr = (u64) block; - unsigned char lba48 = 0; - -#ifdef CONFIG_LBA48 - if (blknr > 0xfffffff) { - if (!sata_dev_desc[device].lba48) { - printf ("Drive doesn't support 48-bit addressing\n"); - return 0; - } - /* more than 28 bits used, use 48bit mode */ - lba48 = 1; - } -#endif - - while (blkcnt > 0) { - - if (blkcnt > 255) { - sread = 255; - } else { - sread = blkcnt; - } - - status = do_one_read (device, blknr, sread, buffer, lba48); - if (status != sread) { - printf ("Read failed\n"); - return n; - } - - blkcnt -= sread; - blknr += sread; - n += sread; - buffer += sread * ATA_SECTOR_WORDS; - } - return n; -} - -ulong sata_write (int device, ulong block, lbaint_t blkcnt, const void *buff) -{ - ulong n = 0; - u16 *buffer = (u16 *) buff; - unsigned char status = 0, num = 0; - u64 blknr = (u64) block; -#ifdef CONFIG_LBA48 - unsigned char lba48 = 0; - - if (blknr > 0xfffffff) { - if (!sata_dev_desc[device].lba48) { - printf ("Drive doesn't support 48-bit addressing\n"); - return 0; - } - /* more than 28 bits used, use 48bit mode */ - lba48 = 1; - } -#endif - /*Port Number */ - num = device; - - while (blkcnt-- > 0) { - status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 500, 0); - if (status & ATA_BUSY) { - printf ("ata%u failed to respond\n", port[num].port_no); - return n; - } -#ifdef CONFIG_LBA48 - if (lba48) { - /* write high bits */ - writeb (0, port[num].ioaddr.nsect_addr); - writeb ((blknr >> 24) & 0xFF, - port[num].ioaddr.lbal_addr); - writeb ((blknr >> 32) & 0xFF, - port[num].ioaddr.lbam_addr); - writeb ((blknr >> 40) & 0xFF, - port[num].ioaddr.lbah_addr); - } -#endif - writeb (1, port[num].ioaddr.nsect_addr); - writeb ((blknr >> 0) & 0xFF, port[num].ioaddr.lbal_addr); - writeb ((blknr >> 8) & 0xFF, port[num].ioaddr.lbam_addr); - writeb ((blknr >> 16) & 0xFF, port[num].ioaddr.lbah_addr); -#ifdef CONFIG_LBA48 - if (lba48) { - writeb (ATA_LBA, port[num].ioaddr.device_addr); - writeb (ATA_CMD_PIO_WRITE_EXT, port[num].ioaddr.command_addr); - } else -#endif - { - writeb (ATA_LBA | ((blknr >> 24) & 0xF), - port[num].ioaddr.device_addr); - writeb (ATA_CMD_PIO_WRITE, port[num].ioaddr.command_addr); - } - - msleep (50); - /*may take up to 4 sec */ - status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 4000, 0); - if ((status & (ATA_DRQ | ATA_BUSY | ATA_ERR)) != ATA_DRQ) { - printf ("Error no DRQ dev %d blk %ld: sts 0x%02x\n", - device, (ulong) blknr, status); - return (n); - } - - output_data (&port[num].ioaddr, buffer, ATA_SECTOR_WORDS); - readb (port[num].ioaddr.altstatus_addr); - udelay (50); - - ++n; - ++blknr; - buffer += ATA_SECTOR_WORDS; - } - return n; -} - -/* Driver implementation */ -static u8 sil_get_device_cache_line (pci_dev_t pdev) -{ - u8 cache_line = 0; - pci_read_config_byte (pdev, PCI_CACHE_LINE_SIZE, &cache_line); - return cache_line; -} - -int init_sata (int dev) -{ - static u8 init_done = 0; - static int res = 1; - pci_dev_t devno; - u8 cls = 0; - u16 cmd = 0; - u32 sconf = 0; - - if (init_done) { - return res; - } - - init_done = 1; - - if ((devno = pci_find_device (SIL_VEND_ID, SIL3114_DEVICE_ID, 0)) == -1) { - res = 1; - return res; - } - - /* Read out all BARs, even though we only use MMIO from BAR5 */ - pci_read_config_dword (devno, PCI_BASE_ADDRESS_0, &iobase[0]); - pci_read_config_dword (devno, PCI_BASE_ADDRESS_1, &iobase[1]); - pci_read_config_dword (devno, PCI_BASE_ADDRESS_2, &iobase[2]); - pci_read_config_dword (devno, PCI_BASE_ADDRESS_3, &iobase[3]); - pci_read_config_dword (devno, PCI_BASE_ADDRESS_4, &iobase[4]); - pci_read_config_dword (devno, PCI_BASE_ADDRESS_5, &iobase[5]); - - if ((iobase[0] == 0xFFFFFFFF) || (iobase[1] == 0xFFFFFFFF) || - (iobase[2] == 0xFFFFFFFF) || (iobase[3] == 0xFFFFFFFF) || - (iobase[4] == 0xFFFFFFFF) || (iobase[5] == 0xFFFFFFFF)) { - printf ("Error no base addr for SATA controller\n"); - res = 1; - return res; - } - - /* mask off unused bits */ - iobase[0] &= 0xfffffffc; - iobase[1] &= 0xfffffff8; - iobase[2] &= 0xfffffffc; - iobase[3] &= 0xfffffff8; - iobase[4] &= 0xfffffff0; - iobase[5] &= 0xfffffc00; - - /* from sata_sil in Linux kernel */ - cls = sil_get_device_cache_line (devno); - if (cls) { - cls >>= 3; - cls++; /* cls = (line_size/8)+1 */ - writel (cls << 8 | cls, iobase[5] + VND_FIFOCFG_CH0); - writel (cls << 8 | cls, iobase[5] + VND_FIFOCFG_CH1); - writel (cls << 8 | cls, iobase[5] + VND_FIFOCFG_CH2); - writel (cls << 8 | cls, iobase[5] + VND_FIFOCFG_CH3); - } else { - printf ("Cache line not set. Driver may not function\n"); - } - - /* Enable operation */ - pci_read_config_word (devno, PCI_COMMAND, &cmd); - cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_IO | PCI_COMMAND_MEMORY; - pci_write_config_word (devno, PCI_COMMAND, cmd); - - /* Disable interrupt usage */ - pci_read_config_dword (devno, VND_SYSCONFSTAT, &sconf); - sconf |= (VND_SYSCONFSTAT_CHN_0_INTBLOCK | VND_SYSCONFSTAT_CHN_1_INTBLOCK); - pci_write_config_dword (devno, VND_SYSCONFSTAT, sconf); - - res = 0; - return res; -} - -int reset_sata(int dev) -{ - return 0; -} - -/* Check if device is connected to port */ -int sata_bus_probe (int portno) -{ - u32 port = iobase[5]; - u32 val; - switch (portno) { - case 0: - port += VND_SSTATUS_CH0; - break; - case 1: - port += VND_SSTATUS_CH1; - break; - case 2: - port += VND_SSTATUS_CH2; - break; - case 3: - port += VND_SSTATUS_CH3; - break; - default: - return 0; - } - val = readl (port); - if ((val & SATA_DET_PRES) == SATA_DET_PRES) { - return 1; - } else { - return 0; - } -} - -int sata_phy_reset (int portno) -{ - u32 port = iobase[5]; - u32 val; - switch (portno) { - case 0: - port += VND_SCONTROL_CH0; - break; - case 1: - port += VND_SCONTROL_CH1; - break; - case 2: - port += VND_SCONTROL_CH2; - break; - case 3: - port += VND_SCONTROL_CH3; - break; - default: - return 0; - } - val = readl (port); - writel (val | SATA_SC_DET_RST, port); - msleep (150); - writel (val & ~SATA_SC_DET_RST, port); - return 0; -} - -int scan_sata (int dev) -{ - /* A bit brain dead, but the code has a legacy */ - switch (dev) { - case 0: - port[0].port_no = 0; - port[0].ioaddr.cmd_addr = iobase[5] + VND_TF0_CH0; - port[0].ioaddr.altstatus_addr = port[0].ioaddr.ctl_addr = - (iobase[5] + VND_TF2_CH0) | ATA_PCI_CTL_OFS; - port[0].ioaddr.bmdma_addr = iobase[5] + VND_BMDMA_CH0; - break; -#if (CONFIG_SYS_SATA_MAX_DEVICE >= 1) - case 1: - port[1].port_no = 0; - port[1].ioaddr.cmd_addr = iobase[5] + VND_TF0_CH1; - port[1].ioaddr.altstatus_addr = port[1].ioaddr.ctl_addr = - (iobase[5] + VND_TF2_CH1) | ATA_PCI_CTL_OFS; - port[1].ioaddr.bmdma_addr = iobase[5] + VND_BMDMA_CH1; - break; -#elif (CONFIG_SYS_SATA_MAX_DEVICE >= 2) - case 2: - port[2].port_no = 0; - port[2].ioaddr.cmd_addr = iobase[5] + VND_TF0_CH2; - port[2].ioaddr.altstatus_addr = port[2].ioaddr.ctl_addr = - (iobase[5] + VND_TF2_CH2) | ATA_PCI_CTL_OFS; - port[2].ioaddr.bmdma_addr = iobase[5] + VND_BMDMA_CH2; - break; -#elif (CONFIG_SYS_SATA_MAX_DEVICE >= 3) - case 3: - port[3].port_no = 0; - port[3].ioaddr.cmd_addr = iobase[5] + VND_TF0_CH3; - port[3].ioaddr.altstatus_addr = port[3].ioaddr.ctl_addr = - (iobase[5] + VND_TF2_CH3) | ATA_PCI_CTL_OFS; - port[3].ioaddr.bmdma_addr = iobase[5] + VND_BMDMA_CH3; - break; -#endif - default: - printf ("Tried to scan unknown port: ata%d\n", dev); - return 1; - } - - /* Initialize other registers */ - sata_port (&port[dev].ioaddr); - - /* Check for attached device */ - if (!sata_bus_probe (dev)) { - port[dev].port_state = 0; - debug ("SATA#%d port is not present\n", dev); - } else { - debug ("SATA#%d port is present\n", dev); - if (sata_bus_softreset (dev)) { - /* soft reset failed, try a hard one */ - sata_phy_reset (dev); - if (sata_bus_softreset (dev)) { - port[dev].port_state = 0; - } else { - port[dev].port_state = 1; - } - } else { - port[dev].port_state = 1; - } - } - if (port[dev].port_state == 1) { - /* Probe device and set xfer mode */ - sata_identify (dev, 0); - set_Feature_cmd (dev, 0); - } - - return 0; -} diff --git a/drivers/block/sata_sil3114.h b/drivers/block/sata_sil3114.h deleted file mode 100644 index 091fca1..0000000 --- a/drivers/block/sata_sil3114.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (C) Excito Elektronik i SkÃ¥ne AB, All rights reserved. - * Author: Tor Krill - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#ifndef SATA_SIL3114_H -#define SATA_SIL3114_H - -struct sata_ioports { - unsigned long cmd_addr; - unsigned long data_addr; - unsigned long error_addr; - unsigned long feature_addr; - unsigned long nsect_addr; - unsigned long lbal_addr; - unsigned long lbam_addr; - unsigned long lbah_addr; - unsigned long device_addr; - unsigned long status_addr; - unsigned long command_addr; - unsigned long altstatus_addr; - unsigned long ctl_addr; - unsigned long bmdma_addr; - unsigned long scr_addr; -}; - -struct sata_port { - unsigned char port_no; /* primary=0, secondary=1 */ - struct sata_ioports ioaddr; /* ATA cmd/ctl/dma reg blks */ - unsigned char ctl_reg; - unsigned char last_ctl; - unsigned char port_state; /* 1-port is available and */ - /* 0-port is not available */ - unsigned char dev_mask; -}; - -/* Missing ata defines */ -#define ATA_CMD_STANDBY 0xE2 -#define ATA_CMD_STANDBYNOW1 0xE0 -#define ATA_CMD_IDLE 0xE3 -#define ATA_CMD_IDLEIMMEDIATE 0xE1 - -/* Defines for SIL3114 chip */ - -/* PCI defines */ -#define SIL_VEND_ID 0x1095 -#define SIL3114_DEVICE_ID 0x3114 - -/* some vendor specific registers */ -#define VND_SYSCONFSTAT 0x88 /* System Configuration Status and Command */ -#define VND_SYSCONFSTAT_CHN_0_INTBLOCK (1<<22) -#define VND_SYSCONFSTAT_CHN_1_INTBLOCK (1<<23) -#define VND_SYSCONFSTAT_CHN_2_INTBLOCK (1<<24) -#define VND_SYSCONFSTAT_CHN_3_INTBLOCK (1<<25) - -/* internal registers mapped by BAR5 */ -/* SATA Control*/ -#define VND_SCONTROL_CH0 0x100 -#define VND_SCONTROL_CH1 0x180 -#define VND_SCONTROL_CH2 0x300 -#define VND_SCONTROL_CH3 0x380 - -#define SATA_SC_IPM_T2P (1<<16) -#define SATA_SC_IPM_T2S (2<<16) -#define SATA_SC_SPD_1_5 (1<<4) -#define SATA_SC_SPD_3_0 (2<<4) -#define SATA_SC_DET_RST (1) /* ATA Reset sequence */ -#define SATA_SC_DET_PDIS (4) /* PHY Disable */ - -/* SATA Status */ -#define VND_SSTATUS_CH0 0x104 -#define VND_SSTATUS_CH1 0x184 -#define VND_SSTATUS_CH2 0x304 -#define VND_SSTATUS_CH3 0x384 - -#define SATA_SS_IPM_ACTIVE (1<<8) -#define SATA_SS_IPM_PARTIAL (2<<8) -#define SATA_SS_IPM_SLUMBER (6<<8) -#define SATA_SS_SPD_1_5 (1<<4) -#define SATA_SS_SPD_3_0 (2<<4) -#define SATA_DET_P_NOPHY (1) /* Device presence but no PHY connection established */ -#define SATA_DET_PRES (3) /* Device presence and active PHY */ -#define SATA_DET_OFFLINE (4) /* Device offline or in loopback mode */ - -/* Task file registers in BAR5 mapping */ -#define VND_TF0_CH0 0x80 -#define VND_TF0_CH1 0xc0 -#define VND_TF0_CH2 0x280 -#define VND_TF0_CH3 0x2c0 -#define VND_TF1_CH0 0x88 -#define VND_TF1_CH1 0xc8 -#define VND_TF1_CH2 0x288 -#define VND_TF1_CH3 0x2c8 -#define VND_TF2_CH0 0x88 -#define VND_TF2_CH1 0xc8 -#define VND_TF2_CH2 0x288 -#define VND_TF2_CH3 0x2c8 - -#define VND_BMDMA_CH0 0x00 -#define VND_BMDMA_CH1 0x08 -#define VND_BMDMA_CH2 0x200 -#define VND_BMDMA_CH3 0x208 -#define VND_BMDMA2_CH0 0x10 -#define VND_BMDMA2_CH1 0x18 -#define VND_BMDMA2_CH2 0x210 -#define VND_BMDMA2_CH3 0x218 - -/* FIFO control */ -#define VND_FIFOCFG_CH0 0x40 -#define VND_FIFOCFG_CH1 0x44 -#define VND_FIFOCFG_CH2 0x240 -#define VND_FIFOCFG_CH3 0x244 - -/* Task File configuration and status */ -#define VND_TF_CNST_CH0 0xa0 -#define VND_TF_CNST_CH1 0xe0 -#define VND_TF_CNST_CH2 0x2a0 -#define VND_TF_CNST_CH3 0x2e0 - -#define VND_TF_CNST_BFCMD (1<<1) -#define VND_TF_CNST_CHNRST (1<<2) -#define VND_TF_CNST_VDMA (1<<10) -#define VND_TF_CNST_INTST (1<<11) -#define VND_TF_CNST_WDTO (1<<12) -#define VND_TF_CNST_WDEN (1<<13) -#define VND_TF_CNST_WDIEN (1<<14) - -/* for testing */ -#define VND_SSDR 0x04c /* System Software Data Register */ -#define VND_FMACS 0x050 /* Flash Memory Address control and status */ - -#endif -- cgit v0.10.2 From 0fcd48fe00e8fb2d433c1bf5ebe586b19228f027 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 14 Jun 2017 21:28:27 -0600 Subject: scsi: Move drivers into new drivers/scsi directory At present we have the SCSI drivers in the drivers/block and common/ directories. It is better to split them out into their own place. Use drivers/scsi which is what Linux does. Signed-off-by: Simon Glass Reviewed-by: Bin Meng diff --git a/common/Makefile b/common/Makefile index f04ddc8..17a92ea 100644 --- a/common/Makefile +++ b/common/Makefile @@ -79,7 +79,6 @@ obj-$(CONFIG_LCD_ROTATION) += lcd_console_rotation.o obj-$(CONFIG_LCD_DT_SIMPLEFB) += lcd_simplefb.o obj-$(CONFIG_LYNXKDI) += lynxkdi.o obj-$(CONFIG_MENU) += menu.o -obj-$(CONFIG_SCSI) += scsi.o obj-$(CONFIG_UPDATE_TFTP) += update.o obj-$(CONFIG_DFU_TFTP) += update.o obj-$(CONFIG_USB_KEYBOARD) += usb_kbd.o @@ -121,9 +120,6 @@ obj-$(CONFIG_ENV_IS_IN_NAND) += env_nand.o obj-$(CONFIG_ENV_IS_IN_SPI_FLASH) += env_sf.o obj-$(CONFIG_ENV_IS_IN_FLASH) += env_flash.o endif -ifdef CONFIG_SPL_SATA_SUPPORT -obj-$(CONFIG_SCSI) += scsi.o -endif endif #environment obj-y += env_common.o diff --git a/common/scsi.c b/common/scsi.c deleted file mode 100644 index 6175e50..0000000 --- a/common/scsi.c +++ /dev/null @@ -1,688 +0,0 @@ -/* - * (C) Copyright 2001 - * Denis Peter, MPL AG Switzerland - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include -#include -#include -#include -#include - -#if !defined(CONFIG_DM_SCSI) -#ifdef CONFIG_SCSI_DEV_LIST -#define SCSI_DEV_LIST CONFIG_SCSI_DEV_LIST -#else -#ifdef CONFIG_SATA_ULI5288 - -#define SCSI_VEND_ID 0x10b9 -#define SCSI_DEV_ID 0x5288 - -#elif !defined(CONFIG_SCSI_AHCI_PLAT) -#error no scsi device defined -#endif -#define SCSI_DEV_LIST {SCSI_VEND_ID, SCSI_DEV_ID} -#endif -#endif - -#if defined(CONFIG_PCI) && !defined(CONFIG_SCSI_AHCI_PLAT) -const struct pci_device_id scsi_device_list[] = { SCSI_DEV_LIST }; -#endif -static ccb tempccb; /* temporary scsi command buffer */ - -static unsigned char tempbuff[512]; /* temporary data buffer */ - -#if !defined(CONFIG_DM_SCSI) -static int scsi_max_devs; /* number of highest available scsi device */ - -static int scsi_curr_dev; /* current device */ - -static struct blk_desc scsi_dev_desc[CONFIG_SYS_SCSI_MAX_DEVICE]; -#endif - -/* almost the maximum amount of the scsi_ext command.. */ -#define SCSI_MAX_READ_BLK 0xFFFF -#define SCSI_LBA48_READ 0xFFFFFFF - -static void scsi_print_error(ccb *pccb) -{ - /* Dummy function that could print an error for debugging */ -} - -#ifdef CONFIG_SYS_64BIT_LBA -void scsi_setup_read16(ccb *pccb, lbaint_t start, unsigned long blocks) -{ - pccb->cmd[0] = SCSI_READ16; - pccb->cmd[1] = pccb->lun << 5; - pccb->cmd[2] = (unsigned char)(start >> 56) & 0xff; - pccb->cmd[3] = (unsigned char)(start >> 48) & 0xff; - pccb->cmd[4] = (unsigned char)(start >> 40) & 0xff; - pccb->cmd[5] = (unsigned char)(start >> 32) & 0xff; - pccb->cmd[6] = (unsigned char)(start >> 24) & 0xff; - pccb->cmd[7] = (unsigned char)(start >> 16) & 0xff; - pccb->cmd[8] = (unsigned char)(start >> 8) & 0xff; - pccb->cmd[9] = (unsigned char)start & 0xff; - pccb->cmd[10] = 0; - pccb->cmd[11] = (unsigned char)(blocks >> 24) & 0xff; - pccb->cmd[12] = (unsigned char)(blocks >> 16) & 0xff; - pccb->cmd[13] = (unsigned char)(blocks >> 8) & 0xff; - pccb->cmd[14] = (unsigned char)blocks & 0xff; - pccb->cmd[15] = 0; - pccb->cmdlen = 16; - pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ - debug("scsi_setup_read16: cmd: %02X %02X startblk %02X%02X%02X%02X%02X%02X%02X%02X blccnt %02X%02X%02X%02X\n", - pccb->cmd[0], pccb->cmd[1], - pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5], - pccb->cmd[6], pccb->cmd[7], pccb->cmd[8], pccb->cmd[9], - pccb->cmd[11], pccb->cmd[12], pccb->cmd[13], pccb->cmd[14]); -} -#endif - -static void scsi_setup_read_ext(ccb *pccb, lbaint_t start, - unsigned short blocks) -{ - pccb->cmd[0] = SCSI_READ10; - pccb->cmd[1] = pccb->lun << 5; - pccb->cmd[2] = (unsigned char)(start >> 24) & 0xff; - pccb->cmd[3] = (unsigned char)(start >> 16) & 0xff; - pccb->cmd[4] = (unsigned char)(start >> 8) & 0xff; - pccb->cmd[5] = (unsigned char)start & 0xff; - pccb->cmd[6] = 0; - pccb->cmd[7] = (unsigned char)(blocks >> 8) & 0xff; - pccb->cmd[8] = (unsigned char)blocks & 0xff; - pccb->cmd[6] = 0; - pccb->cmdlen = 10; - pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ - debug("scsi_setup_read_ext: cmd: %02X %02X startblk %02X%02X%02X%02X blccnt %02X%02X\n", - pccb->cmd[0], pccb->cmd[1], - pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5], - pccb->cmd[7], pccb->cmd[8]); -} - -static void scsi_setup_write_ext(ccb *pccb, lbaint_t start, - unsigned short blocks) -{ - pccb->cmd[0] = SCSI_WRITE10; - pccb->cmd[1] = pccb->lun << 5; - pccb->cmd[2] = (unsigned char)(start >> 24) & 0xff; - pccb->cmd[3] = (unsigned char)(start >> 16) & 0xff; - pccb->cmd[4] = (unsigned char)(start >> 8) & 0xff; - pccb->cmd[5] = (unsigned char)start & 0xff; - pccb->cmd[6] = 0; - pccb->cmd[7] = ((unsigned char)(blocks >> 8)) & 0xff; - pccb->cmd[8] = (unsigned char)blocks & 0xff; - pccb->cmd[9] = 0; - pccb->cmdlen = 10; - pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ - debug("%s: cmd: %02X %02X startblk %02X%02X%02X%02X blccnt %02X%02X\n", - __func__, - pccb->cmd[0], pccb->cmd[1], - pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5], - pccb->cmd[7], pccb->cmd[8]); -} - -static void scsi_setup_inquiry(ccb *pccb) -{ - pccb->cmd[0] = SCSI_INQUIRY; - pccb->cmd[1] = pccb->lun << 5; - pccb->cmd[2] = 0; - pccb->cmd[3] = 0; - if (pccb->datalen > 255) - pccb->cmd[4] = 255; - else - pccb->cmd[4] = (unsigned char)pccb->datalen; - pccb->cmd[5] = 0; - pccb->cmdlen = 6; - pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ -} - -#ifdef CONFIG_BLK -static ulong scsi_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, - void *buffer) -#else -static ulong scsi_read(struct blk_desc *block_dev, lbaint_t blknr, - lbaint_t blkcnt, void *buffer) -#endif -{ -#ifdef CONFIG_BLK - struct blk_desc *block_dev = dev_get_uclass_platdata(dev); -#endif - lbaint_t start, blks; - uintptr_t buf_addr; - unsigned short smallblks = 0; - ccb *pccb = (ccb *)&tempccb; - - /* Setup device */ - pccb->target = block_dev->target; - pccb->lun = block_dev->lun; - buf_addr = (unsigned long)buffer; - start = blknr; - blks = blkcnt; - debug("\nscsi_read: dev %d startblk " LBAF - ", blccnt " LBAF " buffer %lx\n", - block_dev->devnum, start, blks, (unsigned long)buffer); - do { - pccb->pdata = (unsigned char *)buf_addr; -#ifdef CONFIG_SYS_64BIT_LBA - if (start > SCSI_LBA48_READ) { - unsigned long blocks; - blocks = min_t(lbaint_t, blks, SCSI_MAX_READ_BLK); - pccb->datalen = block_dev->blksz * blocks; - scsi_setup_read16(pccb, start, blocks); - start += blocks; - blks -= blocks; - } else -#endif - if (blks > SCSI_MAX_READ_BLK) { - pccb->datalen = block_dev->blksz * - SCSI_MAX_READ_BLK; - smallblks = SCSI_MAX_READ_BLK; - scsi_setup_read_ext(pccb, start, smallblks); - start += SCSI_MAX_READ_BLK; - blks -= SCSI_MAX_READ_BLK; - } else { - pccb->datalen = block_dev->blksz * blks; - smallblks = (unsigned short)blks; - scsi_setup_read_ext(pccb, start, smallblks); - start += blks; - blks = 0; - } - debug("scsi_read_ext: startblk " LBAF - ", blccnt %x buffer %" PRIXPTR "\n", - start, smallblks, buf_addr); - if (scsi_exec(pccb) != true) { - scsi_print_error(pccb); - blkcnt -= blks; - break; - } - buf_addr += pccb->datalen; - } while (blks != 0); - debug("scsi_read_ext: end startblk " LBAF - ", blccnt %x buffer %" PRIXPTR "\n", start, smallblks, buf_addr); - return blkcnt; -} - -/******************************************************************************* - * scsi_write - */ - -/* Almost the maximum amount of the scsi_ext command.. */ -#define SCSI_MAX_WRITE_BLK 0xFFFF - -#ifdef CONFIG_BLK -static ulong scsi_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, - const void *buffer) -#else -static ulong scsi_write(struct blk_desc *block_dev, lbaint_t blknr, - lbaint_t blkcnt, const void *buffer) -#endif -{ -#ifdef CONFIG_BLK - struct blk_desc *block_dev = dev_get_uclass_platdata(dev); -#endif - lbaint_t start, blks; - uintptr_t buf_addr; - unsigned short smallblks; - ccb *pccb = (ccb *)&tempccb; - - /* Setup device */ - pccb->target = block_dev->target; - pccb->lun = block_dev->lun; - buf_addr = (unsigned long)buffer; - start = blknr; - blks = blkcnt; - debug("\n%s: dev %d startblk " LBAF ", blccnt " LBAF " buffer %lx\n", - __func__, block_dev->devnum, start, blks, (unsigned long)buffer); - do { - pccb->pdata = (unsigned char *)buf_addr; - if (blks > SCSI_MAX_WRITE_BLK) { - pccb->datalen = (block_dev->blksz * - SCSI_MAX_WRITE_BLK); - smallblks = SCSI_MAX_WRITE_BLK; - scsi_setup_write_ext(pccb, start, smallblks); - start += SCSI_MAX_WRITE_BLK; - blks -= SCSI_MAX_WRITE_BLK; - } else { - pccb->datalen = block_dev->blksz * blks; - smallblks = (unsigned short)blks; - scsi_setup_write_ext(pccb, start, smallblks); - start += blks; - blks = 0; - } - debug("%s: startblk " LBAF ", blccnt %x buffer %" PRIXPTR "\n", - __func__, start, smallblks, buf_addr); - if (scsi_exec(pccb) != true) { - scsi_print_error(pccb); - blkcnt -= blks; - break; - } - buf_addr += pccb->datalen; - } while (blks != 0); - debug("%s: end startblk " LBAF ", blccnt %x buffer %" PRIXPTR "\n", - __func__, start, smallblks, buf_addr); - return blkcnt; -} - -#if defined(CONFIG_PCI) && !defined(CONFIG_SCSI_AHCI_PLAT) -void scsi_init(void) -{ - int busdevfunc = -1; - int i; - /* - * Find a device from the list, this driver will support a single - * controller. - */ - for (i = 0; i < ARRAY_SIZE(scsi_device_list); i++) { - /* get PCI Device ID */ -#ifdef CONFIG_DM_PCI - struct udevice *dev; - int ret; - - ret = dm_pci_find_device(scsi_device_list[i].vendor, - scsi_device_list[i].device, 0, &dev); - if (!ret) { - busdevfunc = dm_pci_get_bdf(dev); - break; - } -#else - busdevfunc = pci_find_device(scsi_device_list[i].vendor, - scsi_device_list[i].device, - 0); -#endif - if (busdevfunc != -1) - break; - } - - if (busdevfunc == -1) { - printf("Error: SCSI Controller(s) "); - for (i = 0; i < ARRAY_SIZE(scsi_device_list); i++) { - printf("%04X:%04X ", - scsi_device_list[i].vendor, - scsi_device_list[i].device); - } - printf("not found\n"); - return; - } -#ifdef DEBUG - else { - printf("SCSI Controller (%04X,%04X) found (%d:%d:%d)\n", - scsi_device_list[i].vendor, - scsi_device_list[i].device, - (busdevfunc >> 16) & 0xFF, - (busdevfunc >> 11) & 0x1F, - (busdevfunc >> 8) & 0x7); - } -#endif - bootstage_start(BOOTSTAGE_ID_ACCUM_SCSI, "ahci"); - scsi_low_level_init(busdevfunc); - scsi_scan(1); - bootstage_accum(BOOTSTAGE_ID_ACCUM_SCSI); -} -#endif - -/* copy src to dest, skipping leading and trailing blanks - * and null terminate the string - */ -static void scsi_ident_cpy(unsigned char *dest, unsigned char *src, - unsigned int len) -{ - int start, end; - - start = 0; - while (start < len) { - if (src[start] != ' ') - break; - start++; - } - end = len-1; - while (end > start) { - if (src[end] != ' ') - break; - end--; - } - for (; start <= end; start++) - *dest ++= src[start]; - *dest = '\0'; -} - -static int scsi_read_capacity(ccb *pccb, lbaint_t *capacity, - unsigned long *blksz) -{ - *capacity = 0; - - memset(pccb->cmd, '\0', sizeof(pccb->cmd)); - pccb->cmd[0] = SCSI_RD_CAPAC10; - pccb->cmd[1] = pccb->lun << 5; - pccb->cmdlen = 10; - pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ - - pccb->datalen = 8; - if (scsi_exec(pccb) != true) - return 1; - - *capacity = ((lbaint_t)pccb->pdata[0] << 24) | - ((lbaint_t)pccb->pdata[1] << 16) | - ((lbaint_t)pccb->pdata[2] << 8) | - ((lbaint_t)pccb->pdata[3]); - - if (*capacity != 0xffffffff) { - /* Read capacity (10) was sufficient for this drive. */ - *blksz = ((unsigned long)pccb->pdata[4] << 24) | - ((unsigned long)pccb->pdata[5] << 16) | - ((unsigned long)pccb->pdata[6] << 8) | - ((unsigned long)pccb->pdata[7]); - return 0; - } - - /* Read capacity (10) was insufficient. Use read capacity (16). */ - memset(pccb->cmd, '\0', sizeof(pccb->cmd)); - pccb->cmd[0] = SCSI_RD_CAPAC16; - pccb->cmd[1] = 0x10; - pccb->cmdlen = 16; - pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ - - pccb->datalen = 16; - if (scsi_exec(pccb) != true) - return 1; - - *capacity = ((uint64_t)pccb->pdata[0] << 56) | - ((uint64_t)pccb->pdata[1] << 48) | - ((uint64_t)pccb->pdata[2] << 40) | - ((uint64_t)pccb->pdata[3] << 32) | - ((uint64_t)pccb->pdata[4] << 24) | - ((uint64_t)pccb->pdata[5] << 16) | - ((uint64_t)pccb->pdata[6] << 8) | - ((uint64_t)pccb->pdata[7]); - - *blksz = ((uint64_t)pccb->pdata[8] << 56) | - ((uint64_t)pccb->pdata[9] << 48) | - ((uint64_t)pccb->pdata[10] << 40) | - ((uint64_t)pccb->pdata[11] << 32) | - ((uint64_t)pccb->pdata[12] << 24) | - ((uint64_t)pccb->pdata[13] << 16) | - ((uint64_t)pccb->pdata[14] << 8) | - ((uint64_t)pccb->pdata[15]); - - return 0; -} - - -/* - * Some setup (fill-in) routines - */ -static void scsi_setup_test_unit_ready(ccb *pccb) -{ - pccb->cmd[0] = SCSI_TST_U_RDY; - pccb->cmd[1] = pccb->lun << 5; - pccb->cmd[2] = 0; - pccb->cmd[3] = 0; - pccb->cmd[4] = 0; - pccb->cmd[5] = 0; - pccb->cmdlen = 6; - pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ -} - -/** - * scsi_init_dev_desc_priv - initialize only SCSI specific blk_desc properties - * - * @dev_desc: Block device description pointer - */ -static void scsi_init_dev_desc_priv(struct blk_desc *dev_desc) -{ - dev_desc->target = 0xff; - dev_desc->lun = 0xff; - dev_desc->log2blksz = - LOG2_INVALID(typeof(dev_desc->log2blksz)); - dev_desc->type = DEV_TYPE_UNKNOWN; - dev_desc->vendor[0] = 0; - dev_desc->product[0] = 0; - dev_desc->revision[0] = 0; - dev_desc->removable = false; -#ifndef CONFIG_BLK - dev_desc->block_read = scsi_read; - dev_desc->block_write = scsi_write; -#endif -} - -#if !defined(CONFIG_DM_SCSI) -/** - * scsi_init_dev_desc - initialize all SCSI specific blk_desc properties - * - * @dev_desc: Block device description pointer - * @devnum: Device number - */ -static void scsi_init_dev_desc(struct blk_desc *dev_desc, int devnum) -{ - dev_desc->lba = 0; - dev_desc->blksz = 0; - dev_desc->if_type = IF_TYPE_SCSI; - dev_desc->devnum = devnum; - dev_desc->part_type = PART_TYPE_UNKNOWN; - - scsi_init_dev_desc_priv(dev_desc); -} -#endif - -/** - * scsi_detect_dev - Detect scsi device - * - * @target: target id - * @lun: target lun - * @dev_desc: block device description - * - * The scsi_detect_dev detects and fills a dev_desc structure when the device is - * detected. - * - * Return: 0 on success, error value otherwise - */ -static int scsi_detect_dev(int target, int lun, struct blk_desc *dev_desc) -{ - unsigned char perq, modi; - lbaint_t capacity; - unsigned long blksz; - ccb *pccb = (ccb *)&tempccb; - - pccb->target = target; - pccb->lun = lun; - pccb->pdata = (unsigned char *)&tempbuff; - pccb->datalen = 512; - scsi_setup_inquiry(pccb); - if (scsi_exec(pccb) != true) { - if (pccb->contr_stat == SCSI_SEL_TIME_OUT) { - /* - * selection timeout => assuming no - * device present - */ - debug("Selection timeout ID %d\n", - pccb->target); - return -ETIMEDOUT; - } - scsi_print_error(pccb); - return -ENODEV; - } - perq = tempbuff[0]; - modi = tempbuff[1]; - if ((perq & 0x1f) == 0x1f) - return -ENODEV; /* skip unknown devices */ - if ((modi & 0x80) == 0x80) /* drive is removable */ - dev_desc->removable = true; - /* get info for this device */ - scsi_ident_cpy((unsigned char *)dev_desc->vendor, - &tempbuff[8], 8); - scsi_ident_cpy((unsigned char *)dev_desc->product, - &tempbuff[16], 16); - scsi_ident_cpy((unsigned char *)dev_desc->revision, - &tempbuff[32], 4); - dev_desc->target = pccb->target; - dev_desc->lun = pccb->lun; - - pccb->datalen = 0; - scsi_setup_test_unit_ready(pccb); - if (scsi_exec(pccb) != true) { - if (dev_desc->removable) { - dev_desc->type = perq; - goto removable; - } - scsi_print_error(pccb); - return -EINVAL; - } - if (scsi_read_capacity(pccb, &capacity, &blksz)) { - scsi_print_error(pccb); - return -EINVAL; - } - dev_desc->lba = capacity; - dev_desc->blksz = blksz; - dev_desc->log2blksz = LOG2(dev_desc->blksz); - dev_desc->type = perq; -removable: - return 0; -} - -/* - * (re)-scan the scsi bus and reports scsi device info - * to the user if mode = 1 - */ -#if defined(CONFIG_DM_SCSI) -static int do_scsi_scan_one(struct udevice *dev, int id, int lun, int mode) -{ - int ret; - struct udevice *bdev; - struct blk_desc bd; - struct blk_desc *bdesc; - char str[10]; - - /* - * detect the scsi driver to get information about its geometry (block - * size, number of blocks) and other parameters (ids, type, ...) - */ - scsi_init_dev_desc_priv(&bd); - if (scsi_detect_dev(id, lun, &bd)) - return -ENODEV; - - /* - * Create only one block device and do detection - * to make sure that there won't be a lot of - * block devices created - */ - snprintf(str, sizeof(str), "id%dlun%d", id, lun); - ret = blk_create_devicef(dev, "scsi_blk", str, IF_TYPE_SCSI, -1, - bd.blksz, bd.blksz * bd.lba, &bdev); - if (ret) { - debug("Can't create device\n"); - return ret; - } - - bdesc = dev_get_uclass_platdata(bdev); - bdesc->target = id; - bdesc->lun = lun; - bdesc->removable = bd.removable; - bdesc->type = bd.type; - memcpy(&bdesc->vendor, &bd.vendor, sizeof(bd.vendor)); - memcpy(&bdesc->product, &bd.product, sizeof(bd.product)); - memcpy(&bdesc->revision, &bd.revision, sizeof(bd.revision)); - part_init(bdesc); - - if (mode == 1) { - printf(" Device %d: ", 0); - dev_print(bdesc); - } - return 0; -} - -int scsi_scan(int mode) -{ - unsigned char i, lun; - struct uclass *uc; - struct udevice *dev; /* SCSI controller */ - int ret; - - if (mode == 1) - printf("scanning bus for devices...\n"); - - blk_unbind_all(IF_TYPE_SCSI); - - ret = uclass_get(UCLASS_SCSI, &uc); - if (ret) - return ret; - - uclass_foreach_dev(dev, uc) { - struct scsi_platdata *plat; /* scsi controller platdata */ - - /* probe SCSI controller driver */ - ret = device_probe(dev); - if (ret) - return ret; - - /* Get controller platdata */ - plat = dev_get_platdata(dev); - - for (i = 0; i < plat->max_id; i++) - for (lun = 0; lun < plat->max_lun; lun++) - do_scsi_scan_one(dev, i, lun, mode); - } - - return 0; -} -#else -int scsi_scan(int mode) -{ - unsigned char i, lun; - int ret; - - if (mode == 1) - printf("scanning bus for devices...\n"); - for (i = 0; i < CONFIG_SYS_SCSI_MAX_DEVICE; i++) - scsi_init_dev_desc(&scsi_dev_desc[i], i); - - scsi_max_devs = 0; - for (i = 0; i < CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) { - for (lun = 0; lun < CONFIG_SYS_SCSI_MAX_LUN; lun++) { - ret = scsi_detect_dev(i, lun, - &scsi_dev_desc[scsi_max_devs]); - if (ret) - continue; - part_init(&scsi_dev_desc[scsi_max_devs]); - - if (mode == 1) { - printf(" Device %d: ", 0); - dev_print(&scsi_dev_desc[scsi_max_devs]); - } /* if mode */ - scsi_max_devs++; - } /* next LUN */ - } - if (scsi_max_devs > 0) - scsi_curr_dev = 0; - else - scsi_curr_dev = -1; - - printf("Found %d device(s).\n", scsi_max_devs); -#ifndef CONFIG_SPL_BUILD - setenv_ulong("scsidevs", scsi_max_devs); -#endif - return 0; -} -#endif - -#ifdef CONFIG_BLK -static const struct blk_ops scsi_blk_ops = { - .read = scsi_read, - .write = scsi_write, -}; - -U_BOOT_DRIVER(scsi_blk) = { - .name = "scsi_blk", - .id = UCLASS_BLK, - .ops = &scsi_blk_ops, -}; -#else -U_BOOT_LEGACY_BLK(scsi) = { - .if_typename = "scsi", - .if_type = IF_TYPE_SCSI, - .max_devs = CONFIG_SYS_SCSI_MAX_DEVICE, - .desc = scsi_dev_desc, -}; -#endif diff --git a/drivers/Kconfig b/drivers/Kconfig index 63e4034..2e03133 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -72,6 +72,8 @@ source "drivers/reset/Kconfig" source "drivers/rtc/Kconfig" +source "drivers/scsi/Kconfig" + source "drivers/serial/Kconfig" source "drivers/sound/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 9bbcc7b..8624bd8 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -45,7 +45,7 @@ obj-$(CONFIG_SPL_DFU_SUPPORT) += dfu/ obj-$(CONFIG_SPL_WATCHDOG_SUPPORT) += watchdog/ obj-$(CONFIG_SPL_USB_HOST_SUPPORT) += usb/host/ obj-$(CONFIG_OMAP_USB_PHY) += usb/phy/ -obj-$(CONFIG_SPL_SATA_SUPPORT) += ata/ +obj-$(CONFIG_SPL_SATA_SUPPORT) += ata/ scsi/ obj-$(CONFIG_SPL_USB_HOST_SUPPORT) += block/ obj-$(CONFIG_SPL_MMC_SUPPORT) += block/ endif @@ -82,6 +82,7 @@ obj-y += dfu/ obj-$(CONFIG_X86) += pch/ obj-y += phy/marvell/ obj-y += rtc/ +obj-y += scsi/ obj-y += sound/ obj-y += spmi/ obj-y += sysreset/ diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 1ddd650..ca7692d 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -10,24 +10,6 @@ config BLK be partitioned into several areas, called 'partitions' in U-Boot. A filesystem can be placed in each partition. -config SCSI - bool "Support SCSI controllers" - help - This enables support for SCSI (Small Computer System Interface), - a parallel interface widely used with storage peripherals such as - hard drives and optical drives. The SCSI standards define physical - interfaces as well as protocols for controlling devices and - tranferring data. - -config DM_SCSI - bool "Support SCSI controllers with driver model" - depends on BLK - help - This option enables the SCSI (Small Computer System Interface) uclass - which supports SCSI and SATA HDDs. For every device configuration - (IDs/LUNs) a block device is created with RAW read/write and - filesystem support. - config BLOCK_CACHE bool "Use block device cache" default n diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 064c76f..a5e7307 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -13,6 +13,6 @@ endif obj-$(CONFIG_IDE) += ide.o obj-$(CONFIG_IDE_FTIDE020) += ftide020.o -obj-$(CONFIG_SANDBOX) += sandbox.o sandbox_scsi.o +obj-$(CONFIG_SANDBOX) += sandbox.o obj-$(CONFIG_SYSTEMACE) += systemace.o obj-$(CONFIG_BLOCK_CACHE) += blkcache.o diff --git a/drivers/block/sandbox_scsi.c b/drivers/block/sandbox_scsi.c deleted file mode 100644 index f4004a3..0000000 --- a/drivers/block/sandbox_scsi.c +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2015 Google, Inc - * Written by Simon Glass - * - * SPDX-License-Identifier: GPL-2.0+ - * - * This file contains dummy implementations of SCSI functions requried so - * that CONFIG_SCSI can be enabled for sandbox. - */ - -#include -#include - -void scsi_bus_reset(void) -{ -} - -void scsi_init(void) -{ -} - -int scsi_exec(ccb *pccb) -{ - return 0; -} diff --git a/drivers/block/scsi-uclass.c b/drivers/block/scsi-uclass.c deleted file mode 100644 index 05da6cd..0000000 --- a/drivers/block/scsi-uclass.c +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2015 Google, Inc - * Written by Simon Glass - * Copyright (c) 2016 Xilinx, Inc - * Written by Michal Simek - * - * Based on ahci-uclass.c - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include - -static int scsi_post_probe(struct udevice *dev) -{ - debug("%s: device %p\n", __func__, dev); - scsi_low_level_init(0, dev); - return 0; -} - -UCLASS_DRIVER(scsi) = { - .id = UCLASS_SCSI, - .name = "scsi", - .post_probe = scsi_post_probe, -}; diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig new file mode 100644 index 0000000..db1606e --- /dev/null +++ b/drivers/scsi/Kconfig @@ -0,0 +1,17 @@ +config SCSI + bool "Support SCSI controllers" + help + This enables support for SCSI (Small Computer System Interface), + a parallel interface widely used with storage peripherals such as + hard drives and optical drives. The SCSI standards define physical + interfaces as well as protocols for controlling devices and + tranferring data. + +config DM_SCSI + bool "Support SCSI controllers with driver model" + depends on BLK + help + This option enables the SCSI (Small Computer System Interface) uclass + which supports SCSI and SATA HDDs. For every device configuration + (IDs/LUNs) a block device is created with RAW read/write and + filesystem support. diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile new file mode 100644 index 0000000..9e23699 --- /dev/null +++ b/drivers/scsi/Makefile @@ -0,0 +1,20 @@ +# +# (C) Copyright 2000-2007 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +ifndef CONFIG_SPL_BUILD +obj-$(CONFIG_DM_SCSI) += scsi-uclass.o +obj-$(CONFIG_SCSI) += scsi.o +endif + +ifdef CONFIG_SPL_BUILD +ifdef CONFIG_SPL_SATA_SUPPORT +obj-$(CONFIG_DM_SCSI) += scsi-uclass.o +obj-$(CONFIG_SCSI) += scsi.o +endif +endif + +obj-$(CONFIG_SANDBOX) += sandbox_scsi.o diff --git a/drivers/scsi/sandbox_scsi.c b/drivers/scsi/sandbox_scsi.c new file mode 100644 index 0000000..f4004a3 --- /dev/null +++ b/drivers/scsi/sandbox_scsi.c @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2015 Google, Inc + * Written by Simon Glass + * + * SPDX-License-Identifier: GPL-2.0+ + * + * This file contains dummy implementations of SCSI functions requried so + * that CONFIG_SCSI can be enabled for sandbox. + */ + +#include +#include + +void scsi_bus_reset(void) +{ +} + +void scsi_init(void) +{ +} + +int scsi_exec(ccb *pccb) +{ + return 0; +} diff --git a/drivers/scsi/scsi-uclass.c b/drivers/scsi/scsi-uclass.c new file mode 100644 index 0000000..05da6cd --- /dev/null +++ b/drivers/scsi/scsi-uclass.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2015 Google, Inc + * Written by Simon Glass + * Copyright (c) 2016 Xilinx, Inc + * Written by Michal Simek + * + * Based on ahci-uclass.c + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +static int scsi_post_probe(struct udevice *dev) +{ + debug("%s: device %p\n", __func__, dev); + scsi_low_level_init(0, dev); + return 0; +} + +UCLASS_DRIVER(scsi) = { + .id = UCLASS_SCSI, + .name = "scsi", + .post_probe = scsi_post_probe, +}; diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c new file mode 100644 index 0000000..6175e50 --- /dev/null +++ b/drivers/scsi/scsi.c @@ -0,0 +1,688 @@ +/* + * (C) Copyright 2001 + * Denis Peter, MPL AG Switzerland + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include + +#if !defined(CONFIG_DM_SCSI) +#ifdef CONFIG_SCSI_DEV_LIST +#define SCSI_DEV_LIST CONFIG_SCSI_DEV_LIST +#else +#ifdef CONFIG_SATA_ULI5288 + +#define SCSI_VEND_ID 0x10b9 +#define SCSI_DEV_ID 0x5288 + +#elif !defined(CONFIG_SCSI_AHCI_PLAT) +#error no scsi device defined +#endif +#define SCSI_DEV_LIST {SCSI_VEND_ID, SCSI_DEV_ID} +#endif +#endif + +#if defined(CONFIG_PCI) && !defined(CONFIG_SCSI_AHCI_PLAT) +const struct pci_device_id scsi_device_list[] = { SCSI_DEV_LIST }; +#endif +static ccb tempccb; /* temporary scsi command buffer */ + +static unsigned char tempbuff[512]; /* temporary data buffer */ + +#if !defined(CONFIG_DM_SCSI) +static int scsi_max_devs; /* number of highest available scsi device */ + +static int scsi_curr_dev; /* current device */ + +static struct blk_desc scsi_dev_desc[CONFIG_SYS_SCSI_MAX_DEVICE]; +#endif + +/* almost the maximum amount of the scsi_ext command.. */ +#define SCSI_MAX_READ_BLK 0xFFFF +#define SCSI_LBA48_READ 0xFFFFFFF + +static void scsi_print_error(ccb *pccb) +{ + /* Dummy function that could print an error for debugging */ +} + +#ifdef CONFIG_SYS_64BIT_LBA +void scsi_setup_read16(ccb *pccb, lbaint_t start, unsigned long blocks) +{ + pccb->cmd[0] = SCSI_READ16; + pccb->cmd[1] = pccb->lun << 5; + pccb->cmd[2] = (unsigned char)(start >> 56) & 0xff; + pccb->cmd[3] = (unsigned char)(start >> 48) & 0xff; + pccb->cmd[4] = (unsigned char)(start >> 40) & 0xff; + pccb->cmd[5] = (unsigned char)(start >> 32) & 0xff; + pccb->cmd[6] = (unsigned char)(start >> 24) & 0xff; + pccb->cmd[7] = (unsigned char)(start >> 16) & 0xff; + pccb->cmd[8] = (unsigned char)(start >> 8) & 0xff; + pccb->cmd[9] = (unsigned char)start & 0xff; + pccb->cmd[10] = 0; + pccb->cmd[11] = (unsigned char)(blocks >> 24) & 0xff; + pccb->cmd[12] = (unsigned char)(blocks >> 16) & 0xff; + pccb->cmd[13] = (unsigned char)(blocks >> 8) & 0xff; + pccb->cmd[14] = (unsigned char)blocks & 0xff; + pccb->cmd[15] = 0; + pccb->cmdlen = 16; + pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ + debug("scsi_setup_read16: cmd: %02X %02X startblk %02X%02X%02X%02X%02X%02X%02X%02X blccnt %02X%02X%02X%02X\n", + pccb->cmd[0], pccb->cmd[1], + pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5], + pccb->cmd[6], pccb->cmd[7], pccb->cmd[8], pccb->cmd[9], + pccb->cmd[11], pccb->cmd[12], pccb->cmd[13], pccb->cmd[14]); +} +#endif + +static void scsi_setup_read_ext(ccb *pccb, lbaint_t start, + unsigned short blocks) +{ + pccb->cmd[0] = SCSI_READ10; + pccb->cmd[1] = pccb->lun << 5; + pccb->cmd[2] = (unsigned char)(start >> 24) & 0xff; + pccb->cmd[3] = (unsigned char)(start >> 16) & 0xff; + pccb->cmd[4] = (unsigned char)(start >> 8) & 0xff; + pccb->cmd[5] = (unsigned char)start & 0xff; + pccb->cmd[6] = 0; + pccb->cmd[7] = (unsigned char)(blocks >> 8) & 0xff; + pccb->cmd[8] = (unsigned char)blocks & 0xff; + pccb->cmd[6] = 0; + pccb->cmdlen = 10; + pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ + debug("scsi_setup_read_ext: cmd: %02X %02X startblk %02X%02X%02X%02X blccnt %02X%02X\n", + pccb->cmd[0], pccb->cmd[1], + pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5], + pccb->cmd[7], pccb->cmd[8]); +} + +static void scsi_setup_write_ext(ccb *pccb, lbaint_t start, + unsigned short blocks) +{ + pccb->cmd[0] = SCSI_WRITE10; + pccb->cmd[1] = pccb->lun << 5; + pccb->cmd[2] = (unsigned char)(start >> 24) & 0xff; + pccb->cmd[3] = (unsigned char)(start >> 16) & 0xff; + pccb->cmd[4] = (unsigned char)(start >> 8) & 0xff; + pccb->cmd[5] = (unsigned char)start & 0xff; + pccb->cmd[6] = 0; + pccb->cmd[7] = ((unsigned char)(blocks >> 8)) & 0xff; + pccb->cmd[8] = (unsigned char)blocks & 0xff; + pccb->cmd[9] = 0; + pccb->cmdlen = 10; + pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ + debug("%s: cmd: %02X %02X startblk %02X%02X%02X%02X blccnt %02X%02X\n", + __func__, + pccb->cmd[0], pccb->cmd[1], + pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5], + pccb->cmd[7], pccb->cmd[8]); +} + +static void scsi_setup_inquiry(ccb *pccb) +{ + pccb->cmd[0] = SCSI_INQUIRY; + pccb->cmd[1] = pccb->lun << 5; + pccb->cmd[2] = 0; + pccb->cmd[3] = 0; + if (pccb->datalen > 255) + pccb->cmd[4] = 255; + else + pccb->cmd[4] = (unsigned char)pccb->datalen; + pccb->cmd[5] = 0; + pccb->cmdlen = 6; + pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ +} + +#ifdef CONFIG_BLK +static ulong scsi_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, + void *buffer) +#else +static ulong scsi_read(struct blk_desc *block_dev, lbaint_t blknr, + lbaint_t blkcnt, void *buffer) +#endif +{ +#ifdef CONFIG_BLK + struct blk_desc *block_dev = dev_get_uclass_platdata(dev); +#endif + lbaint_t start, blks; + uintptr_t buf_addr; + unsigned short smallblks = 0; + ccb *pccb = (ccb *)&tempccb; + + /* Setup device */ + pccb->target = block_dev->target; + pccb->lun = block_dev->lun; + buf_addr = (unsigned long)buffer; + start = blknr; + blks = blkcnt; + debug("\nscsi_read: dev %d startblk " LBAF + ", blccnt " LBAF " buffer %lx\n", + block_dev->devnum, start, blks, (unsigned long)buffer); + do { + pccb->pdata = (unsigned char *)buf_addr; +#ifdef CONFIG_SYS_64BIT_LBA + if (start > SCSI_LBA48_READ) { + unsigned long blocks; + blocks = min_t(lbaint_t, blks, SCSI_MAX_READ_BLK); + pccb->datalen = block_dev->blksz * blocks; + scsi_setup_read16(pccb, start, blocks); + start += blocks; + blks -= blocks; + } else +#endif + if (blks > SCSI_MAX_READ_BLK) { + pccb->datalen = block_dev->blksz * + SCSI_MAX_READ_BLK; + smallblks = SCSI_MAX_READ_BLK; + scsi_setup_read_ext(pccb, start, smallblks); + start += SCSI_MAX_READ_BLK; + blks -= SCSI_MAX_READ_BLK; + } else { + pccb->datalen = block_dev->blksz * blks; + smallblks = (unsigned short)blks; + scsi_setup_read_ext(pccb, start, smallblks); + start += blks; + blks = 0; + } + debug("scsi_read_ext: startblk " LBAF + ", blccnt %x buffer %" PRIXPTR "\n", + start, smallblks, buf_addr); + if (scsi_exec(pccb) != true) { + scsi_print_error(pccb); + blkcnt -= blks; + break; + } + buf_addr += pccb->datalen; + } while (blks != 0); + debug("scsi_read_ext: end startblk " LBAF + ", blccnt %x buffer %" PRIXPTR "\n", start, smallblks, buf_addr); + return blkcnt; +} + +/******************************************************************************* + * scsi_write + */ + +/* Almost the maximum amount of the scsi_ext command.. */ +#define SCSI_MAX_WRITE_BLK 0xFFFF + +#ifdef CONFIG_BLK +static ulong scsi_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, + const void *buffer) +#else +static ulong scsi_write(struct blk_desc *block_dev, lbaint_t blknr, + lbaint_t blkcnt, const void *buffer) +#endif +{ +#ifdef CONFIG_BLK + struct blk_desc *block_dev = dev_get_uclass_platdata(dev); +#endif + lbaint_t start, blks; + uintptr_t buf_addr; + unsigned short smallblks; + ccb *pccb = (ccb *)&tempccb; + + /* Setup device */ + pccb->target = block_dev->target; + pccb->lun = block_dev->lun; + buf_addr = (unsigned long)buffer; + start = blknr; + blks = blkcnt; + debug("\n%s: dev %d startblk " LBAF ", blccnt " LBAF " buffer %lx\n", + __func__, block_dev->devnum, start, blks, (unsigned long)buffer); + do { + pccb->pdata = (unsigned char *)buf_addr; + if (blks > SCSI_MAX_WRITE_BLK) { + pccb->datalen = (block_dev->blksz * + SCSI_MAX_WRITE_BLK); + smallblks = SCSI_MAX_WRITE_BLK; + scsi_setup_write_ext(pccb, start, smallblks); + start += SCSI_MAX_WRITE_BLK; + blks -= SCSI_MAX_WRITE_BLK; + } else { + pccb->datalen = block_dev->blksz * blks; + smallblks = (unsigned short)blks; + scsi_setup_write_ext(pccb, start, smallblks); + start += blks; + blks = 0; + } + debug("%s: startblk " LBAF ", blccnt %x buffer %" PRIXPTR "\n", + __func__, start, smallblks, buf_addr); + if (scsi_exec(pccb) != true) { + scsi_print_error(pccb); + blkcnt -= blks; + break; + } + buf_addr += pccb->datalen; + } while (blks != 0); + debug("%s: end startblk " LBAF ", blccnt %x buffer %" PRIXPTR "\n", + __func__, start, smallblks, buf_addr); + return blkcnt; +} + +#if defined(CONFIG_PCI) && !defined(CONFIG_SCSI_AHCI_PLAT) +void scsi_init(void) +{ + int busdevfunc = -1; + int i; + /* + * Find a device from the list, this driver will support a single + * controller. + */ + for (i = 0; i < ARRAY_SIZE(scsi_device_list); i++) { + /* get PCI Device ID */ +#ifdef CONFIG_DM_PCI + struct udevice *dev; + int ret; + + ret = dm_pci_find_device(scsi_device_list[i].vendor, + scsi_device_list[i].device, 0, &dev); + if (!ret) { + busdevfunc = dm_pci_get_bdf(dev); + break; + } +#else + busdevfunc = pci_find_device(scsi_device_list[i].vendor, + scsi_device_list[i].device, + 0); +#endif + if (busdevfunc != -1) + break; + } + + if (busdevfunc == -1) { + printf("Error: SCSI Controller(s) "); + for (i = 0; i < ARRAY_SIZE(scsi_device_list); i++) { + printf("%04X:%04X ", + scsi_device_list[i].vendor, + scsi_device_list[i].device); + } + printf("not found\n"); + return; + } +#ifdef DEBUG + else { + printf("SCSI Controller (%04X,%04X) found (%d:%d:%d)\n", + scsi_device_list[i].vendor, + scsi_device_list[i].device, + (busdevfunc >> 16) & 0xFF, + (busdevfunc >> 11) & 0x1F, + (busdevfunc >> 8) & 0x7); + } +#endif + bootstage_start(BOOTSTAGE_ID_ACCUM_SCSI, "ahci"); + scsi_low_level_init(busdevfunc); + scsi_scan(1); + bootstage_accum(BOOTSTAGE_ID_ACCUM_SCSI); +} +#endif + +/* copy src to dest, skipping leading and trailing blanks + * and null terminate the string + */ +static void scsi_ident_cpy(unsigned char *dest, unsigned char *src, + unsigned int len) +{ + int start, end; + + start = 0; + while (start < len) { + if (src[start] != ' ') + break; + start++; + } + end = len-1; + while (end > start) { + if (src[end] != ' ') + break; + end--; + } + for (; start <= end; start++) + *dest ++= src[start]; + *dest = '\0'; +} + +static int scsi_read_capacity(ccb *pccb, lbaint_t *capacity, + unsigned long *blksz) +{ + *capacity = 0; + + memset(pccb->cmd, '\0', sizeof(pccb->cmd)); + pccb->cmd[0] = SCSI_RD_CAPAC10; + pccb->cmd[1] = pccb->lun << 5; + pccb->cmdlen = 10; + pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ + + pccb->datalen = 8; + if (scsi_exec(pccb) != true) + return 1; + + *capacity = ((lbaint_t)pccb->pdata[0] << 24) | + ((lbaint_t)pccb->pdata[1] << 16) | + ((lbaint_t)pccb->pdata[2] << 8) | + ((lbaint_t)pccb->pdata[3]); + + if (*capacity != 0xffffffff) { + /* Read capacity (10) was sufficient for this drive. */ + *blksz = ((unsigned long)pccb->pdata[4] << 24) | + ((unsigned long)pccb->pdata[5] << 16) | + ((unsigned long)pccb->pdata[6] << 8) | + ((unsigned long)pccb->pdata[7]); + return 0; + } + + /* Read capacity (10) was insufficient. Use read capacity (16). */ + memset(pccb->cmd, '\0', sizeof(pccb->cmd)); + pccb->cmd[0] = SCSI_RD_CAPAC16; + pccb->cmd[1] = 0x10; + pccb->cmdlen = 16; + pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ + + pccb->datalen = 16; + if (scsi_exec(pccb) != true) + return 1; + + *capacity = ((uint64_t)pccb->pdata[0] << 56) | + ((uint64_t)pccb->pdata[1] << 48) | + ((uint64_t)pccb->pdata[2] << 40) | + ((uint64_t)pccb->pdata[3] << 32) | + ((uint64_t)pccb->pdata[4] << 24) | + ((uint64_t)pccb->pdata[5] << 16) | + ((uint64_t)pccb->pdata[6] << 8) | + ((uint64_t)pccb->pdata[7]); + + *blksz = ((uint64_t)pccb->pdata[8] << 56) | + ((uint64_t)pccb->pdata[9] << 48) | + ((uint64_t)pccb->pdata[10] << 40) | + ((uint64_t)pccb->pdata[11] << 32) | + ((uint64_t)pccb->pdata[12] << 24) | + ((uint64_t)pccb->pdata[13] << 16) | + ((uint64_t)pccb->pdata[14] << 8) | + ((uint64_t)pccb->pdata[15]); + + return 0; +} + + +/* + * Some setup (fill-in) routines + */ +static void scsi_setup_test_unit_ready(ccb *pccb) +{ + pccb->cmd[0] = SCSI_TST_U_RDY; + pccb->cmd[1] = pccb->lun << 5; + pccb->cmd[2] = 0; + pccb->cmd[3] = 0; + pccb->cmd[4] = 0; + pccb->cmd[5] = 0; + pccb->cmdlen = 6; + pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ +} + +/** + * scsi_init_dev_desc_priv - initialize only SCSI specific blk_desc properties + * + * @dev_desc: Block device description pointer + */ +static void scsi_init_dev_desc_priv(struct blk_desc *dev_desc) +{ + dev_desc->target = 0xff; + dev_desc->lun = 0xff; + dev_desc->log2blksz = + LOG2_INVALID(typeof(dev_desc->log2blksz)); + dev_desc->type = DEV_TYPE_UNKNOWN; + dev_desc->vendor[0] = 0; + dev_desc->product[0] = 0; + dev_desc->revision[0] = 0; + dev_desc->removable = false; +#ifndef CONFIG_BLK + dev_desc->block_read = scsi_read; + dev_desc->block_write = scsi_write; +#endif +} + +#if !defined(CONFIG_DM_SCSI) +/** + * scsi_init_dev_desc - initialize all SCSI specific blk_desc properties + * + * @dev_desc: Block device description pointer + * @devnum: Device number + */ +static void scsi_init_dev_desc(struct blk_desc *dev_desc, int devnum) +{ + dev_desc->lba = 0; + dev_desc->blksz = 0; + dev_desc->if_type = IF_TYPE_SCSI; + dev_desc->devnum = devnum; + dev_desc->part_type = PART_TYPE_UNKNOWN; + + scsi_init_dev_desc_priv(dev_desc); +} +#endif + +/** + * scsi_detect_dev - Detect scsi device + * + * @target: target id + * @lun: target lun + * @dev_desc: block device description + * + * The scsi_detect_dev detects and fills a dev_desc structure when the device is + * detected. + * + * Return: 0 on success, error value otherwise + */ +static int scsi_detect_dev(int target, int lun, struct blk_desc *dev_desc) +{ + unsigned char perq, modi; + lbaint_t capacity; + unsigned long blksz; + ccb *pccb = (ccb *)&tempccb; + + pccb->target = target; + pccb->lun = lun; + pccb->pdata = (unsigned char *)&tempbuff; + pccb->datalen = 512; + scsi_setup_inquiry(pccb); + if (scsi_exec(pccb) != true) { + if (pccb->contr_stat == SCSI_SEL_TIME_OUT) { + /* + * selection timeout => assuming no + * device present + */ + debug("Selection timeout ID %d\n", + pccb->target); + return -ETIMEDOUT; + } + scsi_print_error(pccb); + return -ENODEV; + } + perq = tempbuff[0]; + modi = tempbuff[1]; + if ((perq & 0x1f) == 0x1f) + return -ENODEV; /* skip unknown devices */ + if ((modi & 0x80) == 0x80) /* drive is removable */ + dev_desc->removable = true; + /* get info for this device */ + scsi_ident_cpy((unsigned char *)dev_desc->vendor, + &tempbuff[8], 8); + scsi_ident_cpy((unsigned char *)dev_desc->product, + &tempbuff[16], 16); + scsi_ident_cpy((unsigned char *)dev_desc->revision, + &tempbuff[32], 4); + dev_desc->target = pccb->target; + dev_desc->lun = pccb->lun; + + pccb->datalen = 0; + scsi_setup_test_unit_ready(pccb); + if (scsi_exec(pccb) != true) { + if (dev_desc->removable) { + dev_desc->type = perq; + goto removable; + } + scsi_print_error(pccb); + return -EINVAL; + } + if (scsi_read_capacity(pccb, &capacity, &blksz)) { + scsi_print_error(pccb); + return -EINVAL; + } + dev_desc->lba = capacity; + dev_desc->blksz = blksz; + dev_desc->log2blksz = LOG2(dev_desc->blksz); + dev_desc->type = perq; +removable: + return 0; +} + +/* + * (re)-scan the scsi bus and reports scsi device info + * to the user if mode = 1 + */ +#if defined(CONFIG_DM_SCSI) +static int do_scsi_scan_one(struct udevice *dev, int id, int lun, int mode) +{ + int ret; + struct udevice *bdev; + struct blk_desc bd; + struct blk_desc *bdesc; + char str[10]; + + /* + * detect the scsi driver to get information about its geometry (block + * size, number of blocks) and other parameters (ids, type, ...) + */ + scsi_init_dev_desc_priv(&bd); + if (scsi_detect_dev(id, lun, &bd)) + return -ENODEV; + + /* + * Create only one block device and do detection + * to make sure that there won't be a lot of + * block devices created + */ + snprintf(str, sizeof(str), "id%dlun%d", id, lun); + ret = blk_create_devicef(dev, "scsi_blk", str, IF_TYPE_SCSI, -1, + bd.blksz, bd.blksz * bd.lba, &bdev); + if (ret) { + debug("Can't create device\n"); + return ret; + } + + bdesc = dev_get_uclass_platdata(bdev); + bdesc->target = id; + bdesc->lun = lun; + bdesc->removable = bd.removable; + bdesc->type = bd.type; + memcpy(&bdesc->vendor, &bd.vendor, sizeof(bd.vendor)); + memcpy(&bdesc->product, &bd.product, sizeof(bd.product)); + memcpy(&bdesc->revision, &bd.revision, sizeof(bd.revision)); + part_init(bdesc); + + if (mode == 1) { + printf(" Device %d: ", 0); + dev_print(bdesc); + } + return 0; +} + +int scsi_scan(int mode) +{ + unsigned char i, lun; + struct uclass *uc; + struct udevice *dev; /* SCSI controller */ + int ret; + + if (mode == 1) + printf("scanning bus for devices...\n"); + + blk_unbind_all(IF_TYPE_SCSI); + + ret = uclass_get(UCLASS_SCSI, &uc); + if (ret) + return ret; + + uclass_foreach_dev(dev, uc) { + struct scsi_platdata *plat; /* scsi controller platdata */ + + /* probe SCSI controller driver */ + ret = device_probe(dev); + if (ret) + return ret; + + /* Get controller platdata */ + plat = dev_get_platdata(dev); + + for (i = 0; i < plat->max_id; i++) + for (lun = 0; lun < plat->max_lun; lun++) + do_scsi_scan_one(dev, i, lun, mode); + } + + return 0; +} +#else +int scsi_scan(int mode) +{ + unsigned char i, lun; + int ret; + + if (mode == 1) + printf("scanning bus for devices...\n"); + for (i = 0; i < CONFIG_SYS_SCSI_MAX_DEVICE; i++) + scsi_init_dev_desc(&scsi_dev_desc[i], i); + + scsi_max_devs = 0; + for (i = 0; i < CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) { + for (lun = 0; lun < CONFIG_SYS_SCSI_MAX_LUN; lun++) { + ret = scsi_detect_dev(i, lun, + &scsi_dev_desc[scsi_max_devs]); + if (ret) + continue; + part_init(&scsi_dev_desc[scsi_max_devs]); + + if (mode == 1) { + printf(" Device %d: ", 0); + dev_print(&scsi_dev_desc[scsi_max_devs]); + } /* if mode */ + scsi_max_devs++; + } /* next LUN */ + } + if (scsi_max_devs > 0) + scsi_curr_dev = 0; + else + scsi_curr_dev = -1; + + printf("Found %d device(s).\n", scsi_max_devs); +#ifndef CONFIG_SPL_BUILD + setenv_ulong("scsidevs", scsi_max_devs); +#endif + return 0; +} +#endif + +#ifdef CONFIG_BLK +static const struct blk_ops scsi_blk_ops = { + .read = scsi_read, + .write = scsi_write, +}; + +U_BOOT_DRIVER(scsi_blk) = { + .name = "scsi_blk", + .id = UCLASS_BLK, + .ops = &scsi_blk_ops, +}; +#else +U_BOOT_LEGACY_BLK(scsi) = { + .if_typename = "scsi", + .if_type = IF_TYPE_SCSI, + .max_devs = CONFIG_SYS_SCSI_MAX_DEVICE, + .desc = scsi_dev_desc, +}; +#endif -- cgit v0.10.2 From 043682422c3baccba5a935cfe8a7b856ce076dff Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 14 Jun 2017 21:28:28 -0600 Subject: dm: scsi: Rearrange header file for driver model Put the driver-model declarations first since we are migrating to that. Also drop scsi_init() when driver model is used. Signed-off-by: Simon Glass Reviewed-by: Bin Meng diff --git a/include/scsi.h b/include/scsi.h index 621d938..f94b2ef 100644 --- a/include/scsi.h +++ b/include/scsi.h @@ -158,26 +158,6 @@ typedef struct SCSI_cmd_block{ #define SCSI_WRITE_LONG 0x3F /* Write Long (O) */ #define SCSI_WRITE_SAME 0x41 /* Write Same (O) */ - -/**************************************************************************** - * decleration of functions which have to reside in the LowLevel Part Driver - */ - -int scsi_exec(ccb *pccb); -void scsi_bus_reset(void); -#if !defined(CONFIG_DM_SCSI) -void scsi_low_level_init(int busdevfunc); -#else -void scsi_low_level_init(int busdevfunc, struct udevice *dev); -#endif - -/*************************************************************************** - * functions residing inside cmd_scsi.c - */ -void scsi_init(void); -int scsi_scan(int mode); - -#if defined(CONFIG_DM_SCSI) /** * struct scsi_platdata - stores information about SCSI controller * @@ -190,8 +170,22 @@ struct scsi_platdata { unsigned long max_lun; unsigned long max_id; }; + +#if defined(CONFIG_DM_SCSI) +void scsi_low_level_init(int busdevfunc, struct udevice *dev); +#else +void scsi_low_level_init(int busdevfunc); +void scsi_init(void); #endif +int scsi_exec(ccb *pccb); +void scsi_bus_reset(void); + +/*************************************************************************** + * functions residing inside cmd_scsi.c + */ +int scsi_scan(int mode); + #define SCSI_IDENTIFY 0xC0 /* not used */ /* Hardware errors */ -- cgit v0.10.2 From aae5ec34032610f2144542fd1b30b6a5cc559d79 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 14 Jun 2017 21:28:29 -0600 Subject: dm: scsi: Rename struct SCSI_cmd_block to struct scsi_cmd This name should be lower case. Also the _block suffix is superfluous. Rename it. Signed-off-by: Simon Glass Reviewed-by: Bin Meng diff --git a/drivers/usb/emul/sandbox_flash.c b/drivers/usb/emul/sandbox_flash.c index 73fa82b..98d20c0 100644 --- a/drivers/usb/emul/sandbox_flash.c +++ b/drivers/usb/emul/sandbox_flash.c @@ -244,7 +244,7 @@ static int handle_ufi_command(struct sandbox_flash_plat *plat, struct sandbox_flash_priv *priv, const void *buff, int len) { - const struct SCSI_cmd_block *req = buff; + const struct scsi_cmd *req = buff; switch (*req->cmd) { case SCSI_INQUIRY: { diff --git a/include/scsi.h b/include/scsi.h index f94b2ef..182665d 100644 --- a/include/scsi.h +++ b/include/scsi.h @@ -7,7 +7,7 @@ #ifndef _SCSI_H #define _SCSI_H -typedef struct SCSI_cmd_block{ +typedef struct scsi_cmd{ unsigned char cmd[16]; /* command */ /* for request sense */ unsigned char sense_buf[64] -- cgit v0.10.2 From b9560ad649b8c523bf303cf9ba981e498988c5d9 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 14 Jun 2017 21:28:30 -0600 Subject: dm: scsi: Drop the ccb typedef We should not be using typedefs in U-Boot and 'ccb' is a pretty short name. It is also used with variables. Drop the typedef and use 'struct' instead. Signed-off-by: Simon Glass Reviewed-by: Bin Meng diff --git a/common/usb_storage.c b/common/usb_storage.c index 03171f7..df0b057 100644 --- a/common/usb_storage.c +++ b/common/usb_storage.c @@ -63,7 +63,7 @@ static const unsigned char us_direction[256/8] = { }; #define US_DIRECTION(x) ((us_direction[x>>3] >> (x & 7)) & 1) -static ccb usb_ccb __attribute__((aligned(ARCH_DMA_MINALIGN))); +static struct scsi_cmd usb_ccb __aligned(ARCH_DMA_MINALIGN); static __u32 CBWTag; static int usb_max_devs; /* number of highest available usb device */ @@ -73,7 +73,7 @@ static struct blk_desc usb_dev_desc[USB_MAX_STOR_DEV]; #endif struct us_data; -typedef int (*trans_cmnd)(ccb *cb, struct us_data *data); +typedef int (*trans_cmnd)(struct scsi_cmd *cb, struct us_data *data); typedef int (*trans_reset)(struct us_data *data); struct us_data { @@ -95,7 +95,7 @@ struct us_data { unsigned int irqpipe; /* pipe for release_irq */ unsigned char irqmaxp; /* max packed for irq Pipe */ unsigned char irqinterval; /* Intervall for IRQ Pipe */ - ccb *srb; /* current srb */ + struct scsi_cmd *srb; /* current srb */ trans_reset transport_reset; /* reset routine */ trans_cmnd transport; /* transport routine */ }; @@ -349,7 +349,7 @@ static int usb_stor_irq(struct usb_device *dev) #ifdef DEBUG -static void usb_show_srb(ccb *pccb) +static void usb_show_srb(struct scsi_cmd *pccb) { int i; printf("SRB: len %d datalen 0x%lX\n ", pccb->cmdlen, pccb->datalen); @@ -541,7 +541,7 @@ static int usb_stor_CB_reset(struct us_data *us) * Set up the command for a BBB device. Note that the actual SCSI * command is copied into cbw.CBWCDB. */ -static int usb_stor_BBB_comdat(ccb *srb, struct us_data *us) +static int usb_stor_BBB_comdat(struct scsi_cmd *srb, struct us_data *us) { int result; int actlen; @@ -590,7 +590,7 @@ static int usb_stor_BBB_comdat(ccb *srb, struct us_data *us) /* FIXME: we also need a CBI_command which sets up the completion * interrupt, and waits for it */ -static int usb_stor_CB_comdat(ccb *srb, struct us_data *us) +static int usb_stor_CB_comdat(struct scsi_cmd *srb, struct us_data *us) { int result = 0; int dir_in, retry; @@ -659,7 +659,7 @@ static int usb_stor_CB_comdat(ccb *srb, struct us_data *us) } -static int usb_stor_CBI_get_status(ccb *srb, struct us_data *us) +static int usb_stor_CBI_get_status(struct scsi_cmd *srb, struct us_data *us) { int timeout; @@ -714,7 +714,7 @@ static int usb_stor_BBB_clear_endpt_stall(struct us_data *us, __u8 endpt) endpt, NULL, 0, USB_CNTL_TIMEOUT * 5); } -static int usb_stor_BBB_transport(ccb *srb, struct us_data *us) +static int usb_stor_BBB_transport(struct scsi_cmd *srb, struct us_data *us) { int result, retry; int dir_in; @@ -837,11 +837,11 @@ again: return result; } -static int usb_stor_CB_transport(ccb *srb, struct us_data *us) +static int usb_stor_CB_transport(struct scsi_cmd *srb, struct us_data *us) { int result, status; - ccb *psrb; - ccb reqsrb; + struct scsi_cmd *psrb; + struct scsi_cmd reqsrb; int retry, notready; psrb = &reqsrb; @@ -950,7 +950,7 @@ do_retry: } -static int usb_inquiry(ccb *srb, struct us_data *ss) +static int usb_inquiry(struct scsi_cmd *srb, struct us_data *ss) { int retry, i; retry = 5; @@ -974,7 +974,7 @@ static int usb_inquiry(ccb *srb, struct us_data *ss) return 0; } -static int usb_request_sense(ccb *srb, struct us_data *ss) +static int usb_request_sense(struct scsi_cmd *srb, struct us_data *ss) { char *ptr; @@ -994,7 +994,7 @@ static int usb_request_sense(ccb *srb, struct us_data *ss) return 0; } -static int usb_test_unit_ready(ccb *srb, struct us_data *ss) +static int usb_test_unit_ready(struct scsi_cmd *srb, struct us_data *ss) { int retries = 10; @@ -1025,7 +1025,7 @@ static int usb_test_unit_ready(ccb *srb, struct us_data *ss) return -1; } -static int usb_read_capacity(ccb *srb, struct us_data *ss) +static int usb_read_capacity(struct scsi_cmd *srb, struct us_data *ss) { int retry; /* XXX retries */ @@ -1043,8 +1043,8 @@ static int usb_read_capacity(ccb *srb, struct us_data *ss) return -1; } -static int usb_read_10(ccb *srb, struct us_data *ss, unsigned long start, - unsigned short blocks) +static int usb_read_10(struct scsi_cmd *srb, struct us_data *ss, + unsigned long start, unsigned short blocks) { memset(&srb->cmd[0], 0, 12); srb->cmd[0] = SCSI_READ10; @@ -1060,8 +1060,8 @@ static int usb_read_10(ccb *srb, struct us_data *ss, unsigned long start, return ss->transport(srb, ss); } -static int usb_write_10(ccb *srb, struct us_data *ss, unsigned long start, - unsigned short blocks) +static int usb_write_10(struct scsi_cmd *srb, struct us_data *ss, + unsigned long start, unsigned short blocks) { memset(&srb->cmd[0], 0, 12); srb->cmd[0] = SCSI_WRITE10; @@ -1115,7 +1115,7 @@ static unsigned long usb_stor_read(struct blk_desc *block_dev, lbaint_t blknr, struct usb_device *udev; struct us_data *ss; int retry; - ccb *srb = &usb_ccb; + struct scsi_cmd *srb = &usb_ccb; #ifdef CONFIG_BLK struct blk_desc *block_dev; #endif @@ -1197,7 +1197,7 @@ static unsigned long usb_stor_write(struct blk_desc *block_dev, lbaint_t blknr, struct usb_device *udev; struct us_data *ss; int retry; - ccb *srb = &usb_ccb; + struct scsi_cmd *srb = &usb_ccb; #ifdef CONFIG_BLK struct blk_desc *block_dev; #endif @@ -1395,7 +1395,7 @@ int usb_stor_get_info(struct usb_device *dev, struct us_data *ss, ALLOC_CACHE_ALIGN_BUFFER(u32, cap, 2); ALLOC_CACHE_ALIGN_BUFFER(u8, usb_stor_buf, 36); u32 capacity, blksz; - ccb *pccb = &usb_ccb; + struct scsi_cmd *pccb = &usb_ccb; pccb->pdata = usb_stor_buf; diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index f474471..29835f0 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -689,7 +689,7 @@ static char *ata_id_strcpy(u16 *target, u16 *src, int len) /* * SCSI INQUIRY command operation. */ -static int ata_scsiop_inquiry(ccb *pccb) +static int ata_scsiop_inquiry(struct scsi_cmd *pccb) { static const u8 hdr[] = { 0, @@ -753,7 +753,7 @@ static int ata_scsiop_inquiry(ccb *pccb) /* * SCSI READ10/WRITE10 command operation. */ -static int ata_scsiop_read_write(ccb *pccb, u8 is_write) +static int ata_scsiop_read_write(struct scsi_cmd *pccb, u8 is_write) { lbaint_t lba = 0; u16 blocks = 0; @@ -864,7 +864,7 @@ static int ata_scsiop_read_write(ccb *pccb, u8 is_write) /* * SCSI READ CAPACITY10 command operation. */ -static int ata_scsiop_read_capacity10(ccb *pccb) +static int ata_scsiop_read_capacity10(struct scsi_cmd *pccb) { u32 cap; u64 cap64; @@ -894,7 +894,7 @@ static int ata_scsiop_read_capacity10(ccb *pccb) /* * SCSI READ CAPACITY16 command operation. */ -static int ata_scsiop_read_capacity16(ccb *pccb) +static int ata_scsiop_read_capacity16(struct scsi_cmd *pccb) { u64 cap; u64 block_size; @@ -920,13 +920,13 @@ static int ata_scsiop_read_capacity16(ccb *pccb) /* * SCSI TEST UNIT READY command operation. */ -static int ata_scsiop_test_unit_ready(ccb *pccb) +static int ata_scsiop_test_unit_ready(struct scsi_cmd *pccb) { return (ataid[pccb->target]) ? 0 : -EPERM; } -int scsi_exec(ccb *pccb) +int scsi_exec(struct scsi_cmd *pccb) { int ret; diff --git a/drivers/scsi/sandbox_scsi.c b/drivers/scsi/sandbox_scsi.c index f4004a3..d943d1f 100644 --- a/drivers/scsi/sandbox_scsi.c +++ b/drivers/scsi/sandbox_scsi.c @@ -19,7 +19,7 @@ void scsi_init(void) { } -int scsi_exec(ccb *pccb) +int scsi_exec(struct scsi_cmd *pccb) { return 0; } diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 6175e50..5f5652b 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -32,7 +32,7 @@ #if defined(CONFIG_PCI) && !defined(CONFIG_SCSI_AHCI_PLAT) const struct pci_device_id scsi_device_list[] = { SCSI_DEV_LIST }; #endif -static ccb tempccb; /* temporary scsi command buffer */ +static struct scsi_cmd tempccb; /* temporary scsi command buffer */ static unsigned char tempbuff[512]; /* temporary data buffer */ @@ -48,13 +48,14 @@ static struct blk_desc scsi_dev_desc[CONFIG_SYS_SCSI_MAX_DEVICE]; #define SCSI_MAX_READ_BLK 0xFFFF #define SCSI_LBA48_READ 0xFFFFFFF -static void scsi_print_error(ccb *pccb) +static void scsi_print_error(struct scsi_cmd *pccb) { /* Dummy function that could print an error for debugging */ } #ifdef CONFIG_SYS_64BIT_LBA -void scsi_setup_read16(ccb *pccb, lbaint_t start, unsigned long blocks) +void scsi_setup_read16(struct scsi_cmd *pccb, lbaint_t start, + unsigned long blocks) { pccb->cmd[0] = SCSI_READ16; pccb->cmd[1] = pccb->lun << 5; @@ -82,7 +83,7 @@ void scsi_setup_read16(ccb *pccb, lbaint_t start, unsigned long blocks) } #endif -static void scsi_setup_read_ext(ccb *pccb, lbaint_t start, +static void scsi_setup_read_ext(struct scsi_cmd *pccb, lbaint_t start, unsigned short blocks) { pccb->cmd[0] = SCSI_READ10; @@ -103,7 +104,7 @@ static void scsi_setup_read_ext(ccb *pccb, lbaint_t start, pccb->cmd[7], pccb->cmd[8]); } -static void scsi_setup_write_ext(ccb *pccb, lbaint_t start, +static void scsi_setup_write_ext(struct scsi_cmd *pccb, lbaint_t start, unsigned short blocks) { pccb->cmd[0] = SCSI_WRITE10; @@ -125,7 +126,7 @@ static void scsi_setup_write_ext(ccb *pccb, lbaint_t start, pccb->cmd[7], pccb->cmd[8]); } -static void scsi_setup_inquiry(ccb *pccb) +static void scsi_setup_inquiry(struct scsi_cmd *pccb) { pccb->cmd[0] = SCSI_INQUIRY; pccb->cmd[1] = pccb->lun << 5; @@ -154,7 +155,7 @@ static ulong scsi_read(struct blk_desc *block_dev, lbaint_t blknr, lbaint_t start, blks; uintptr_t buf_addr; unsigned short smallblks = 0; - ccb *pccb = (ccb *)&tempccb; + struct scsi_cmd *pccb = (struct scsi_cmd *)&tempccb; /* Setup device */ pccb->target = block_dev->target; @@ -227,7 +228,7 @@ static ulong scsi_write(struct blk_desc *block_dev, lbaint_t blknr, lbaint_t start, blks; uintptr_t buf_addr; unsigned short smallblks; - ccb *pccb = (ccb *)&tempccb; + struct scsi_cmd *pccb = (struct scsi_cmd *)&tempccb; /* Setup device */ pccb->target = block_dev->target; @@ -349,7 +350,7 @@ static void scsi_ident_cpy(unsigned char *dest, unsigned char *src, *dest = '\0'; } -static int scsi_read_capacity(ccb *pccb, lbaint_t *capacity, +static int scsi_read_capacity(struct scsi_cmd *pccb, lbaint_t *capacity, unsigned long *blksz) { *capacity = 0; @@ -414,7 +415,7 @@ static int scsi_read_capacity(ccb *pccb, lbaint_t *capacity, /* * Some setup (fill-in) routines */ -static void scsi_setup_test_unit_ready(ccb *pccb) +static void scsi_setup_test_unit_ready(struct scsi_cmd *pccb) { pccb->cmd[0] = SCSI_TST_U_RDY; pccb->cmd[1] = pccb->lun << 5; @@ -484,7 +485,7 @@ static int scsi_detect_dev(int target, int lun, struct blk_desc *dev_desc) unsigned char perq, modi; lbaint_t capacity; unsigned long blksz; - ccb *pccb = (ccb *)&tempccb; + struct scsi_cmd *pccb = (struct scsi_cmd *)&tempccb; pccb->target = target; pccb->lun = lun; diff --git a/include/scsi.h b/include/scsi.h index 182665d..bc5be97 100644 --- a/include/scsi.h +++ b/include/scsi.h @@ -7,7 +7,7 @@ #ifndef _SCSI_H #define _SCSI_H -typedef struct scsi_cmd{ +struct scsi_cmd { unsigned char cmd[16]; /* command */ /* for request sense */ unsigned char sense_buf[64] @@ -27,7 +27,7 @@ typedef struct scsi_cmd{ unsigned long trans_bytes; /* tranfered bytes */ unsigned int priv; -}ccb; +}; /*----------------------------------------------------------- ** @@ -178,7 +178,7 @@ void scsi_low_level_init(int busdevfunc); void scsi_init(void); #endif -int scsi_exec(ccb *pccb); +int scsi_exec(struct scsi_cmd *pccb); void scsi_bus_reset(void); /*************************************************************************** -- cgit v0.10.2 From 1dc64f6c00e89f11e3615403459207405ab0efda Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 14 Jun 2017 21:28:31 -0600 Subject: dm: scsi: Use the uclass platform data At present the two driver-model SCSI drivers use device platform data to store information that relates to the uclass. It is better to use uclass platform data in this situation. Update the code to do this. Signed-off-by: Simon Glass Reviewed-by: Bin Meng diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 29835f0..2cc604b 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -479,7 +479,7 @@ static int ahci_init_one(pci_dev_t dev) pci_write_config_byte(dev, 0x41, 0xa1); #endif #else - struct scsi_platdata *plat = dev_get_platdata(dev); + struct scsi_platdata *plat = dev_get_uclass_platdata(dev); probe_ent->mmio_base = (void *)plat->base; #endif diff --git a/drivers/ata/dwc_ahci.c b/drivers/ata/dwc_ahci.c index 3f839bf..e634df5 100644 --- a/drivers/ata/dwc_ahci.c +++ b/drivers/ata/dwc_ahci.c @@ -28,7 +28,7 @@ struct dwc_ahci_priv { static int dwc_ahci_ofdata_to_platdata(struct udevice *dev) { struct dwc_ahci_priv *priv = dev_get_priv(dev); - struct scsi_platdata *plat = dev_get_platdata(dev); + struct scsi_platdata *plat = dev_get_uclass_platdata(dev); fdt_addr_t addr; plat->max_id = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev), @@ -96,6 +96,5 @@ U_BOOT_DRIVER(dwc_ahci) = { .ofdata_to_platdata = dwc_ahci_ofdata_to_platdata, .probe = dwc_ahci_probe, .priv_auto_alloc_size = sizeof(struct dwc_ahci_priv), - .platdata_auto_alloc_size = sizeof(struct scsi_platdata), .flags = DM_FLAG_ALLOC_PRIV_DMA, }; diff --git a/drivers/ata/sata_ceva.c b/drivers/ata/sata_ceva.c index 0c24fce..f55ba59 100644 --- a/drivers/ata/sata_ceva.c +++ b/drivers/ata/sata_ceva.c @@ -113,7 +113,7 @@ static int ceva_init_sata(ulong mmio) static int sata_ceva_probe(struct udevice *dev) { - struct scsi_platdata *plat = dev_get_platdata(dev); + struct scsi_platdata *plat = dev_get_uclass_platdata(dev); ceva_init_sata(plat->base); return 0; @@ -126,7 +126,7 @@ static const struct udevice_id sata_ceva_ids[] = { static int sata_ceva_ofdata_to_platdata(struct udevice *dev) { - struct scsi_platdata *plat = dev_get_platdata(dev); + struct scsi_platdata *plat = dev_get_uclass_platdata(dev); plat->base = devfdt_get_addr(dev); if (plat->base == FDT_ADDR_T_NONE) @@ -145,5 +145,4 @@ U_BOOT_DRIVER(ceva_host_blk) = { .of_match = sata_ceva_ids, .probe = sata_ceva_probe, .ofdata_to_platdata = sata_ceva_ofdata_to_platdata, - .platdata_auto_alloc_size = sizeof(struct scsi_platdata), }; diff --git a/drivers/scsi/scsi-uclass.c b/drivers/scsi/scsi-uclass.c index 05da6cd..e4ee44b 100644 --- a/drivers/scsi/scsi-uclass.c +++ b/drivers/scsi/scsi-uclass.c @@ -24,4 +24,5 @@ UCLASS_DRIVER(scsi) = { .id = UCLASS_SCSI, .name = "scsi", .post_probe = scsi_post_probe, + .per_device_platdata_auto_alloc_size = sizeof(struct scsi_platdata), }; diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 5f5652b..2d0f81a 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -619,7 +619,7 @@ int scsi_scan(int mode) return ret; /* Get controller platdata */ - plat = dev_get_platdata(dev); + plat = dev_get_uclass_platdata(dev); for (i = 0; i < plat->max_id; i++) for (lun = 0; lun < plat->max_lun; lun++) -- cgit v0.10.2 From 2c9f9efb3d43568e5e5843c600e8bfc2d42ac23e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 14 Jun 2017 21:28:32 -0600 Subject: dm: ahci: Rename struct ahci_probe_ent This is not a very useful name since once it is probed it still hangs around. With driver model we will use uclass data for this, so rename the struct. Signed-off-by: Simon Glass Reviewed-by: Bin Meng diff --git a/board/highbank/ahci.c b/board/highbank/ahci.c index 1578a33..dadfbdd 100644 --- a/board/highbank/ahci.c +++ b/board/highbank/ahci.c @@ -172,7 +172,7 @@ static void cphy_override_lane(u8 port) #define WAIT_MS_LINKUP 4 -int ahci_link_up(struct ahci_probe_ent *probe_ent, int port) +int ahci_link_up(struct ahci_uc_priv *probe_ent, int port) { u32 tmp; int j = 0; diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 2cc604b..2caa29b 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -24,7 +24,7 @@ static int ata_io_flush(u8 port); -struct ahci_probe_ent *probe_ent = NULL; +struct ahci_uc_priv *probe_ent = NULL; u16 *ataid[AHCI_MAX_PORTS]; #define writel_with_flush(a,b) do { writel(a,b); readl(b); } while (0) @@ -109,7 +109,7 @@ static int waiting_for_cmd_completed(void __iomem *offset, return (i < timeout_msec) ? 0 : -1; } -int __weak ahci_link_up(struct ahci_probe_ent *probe_ent, u8 port) +int __weak ahci_link_up(struct ahci_uc_priv *probe_ent, u8 port) { u32 tmp; int j = 0; @@ -166,7 +166,7 @@ int ahci_reset(void __iomem *base) return 0; } -static int ahci_host_init(struct ahci_probe_ent *probe_ent) +static int ahci_host_init(struct ahci_uc_priv *probe_ent) { #if !defined(CONFIG_SCSI_AHCI_PLAT) && !defined(CONFIG_DM_SCSI) # ifdef CONFIG_DM_PCI @@ -344,7 +344,7 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent) } -static void ahci_print_info(struct ahci_probe_ent *probe_ent) +static void ahci_print_info(struct ahci_uc_priv *probe_ent) { #if !defined(CONFIG_SCSI_AHCI_PLAT) && !defined(CONFIG_DM_SCSI) # if defined(CONFIG_DM_PCI) @@ -437,13 +437,13 @@ static int ahci_init_one(pci_dev_t dev) #endif int rc; - probe_ent = malloc(sizeof(struct ahci_probe_ent)); + probe_ent = malloc(sizeof(struct ahci_uc_priv)); if (!probe_ent) { printf("%s: No memory for probe_ent\n", __func__); return -ENOMEM; } - memset(probe_ent, 0, sizeof(struct ahci_probe_ent)); + memset(probe_ent, 0, sizeof(struct ahci_uc_priv)); probe_ent->dev = dev; probe_ent->host_flags = ATA_FLAG_SATA @@ -1006,13 +1006,13 @@ int ahci_init(void __iomem *base) int i, rc = 0; u32 linkmap; - probe_ent = malloc(sizeof(struct ahci_probe_ent)); + probe_ent = malloc(sizeof(struct ahci_uc_priv)); if (!probe_ent) { printf("%s: No memory for probe_ent\n", __func__); return -ENOMEM; } - memset(probe_ent, 0, sizeof(struct ahci_probe_ent)); + memset(probe_ent, 0, sizeof(struct ahci_uc_priv)); probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY diff --git a/drivers/ata/dwc_ahsata.c b/drivers/ata/dwc_ahsata.c index c306e92..78572a5 100644 --- a/drivers/ata/dwc_ahsata.c +++ b/drivers/ata/dwc_ahsata.c @@ -100,7 +100,7 @@ static int waiting_for_cmd_completed(u8 *offset, return (i < timeout_msec) ? 0 : -1; } -static int ahci_setup_oobr(struct ahci_probe_ent *probe_ent, +static int ahci_setup_oobr(struct ahci_uc_priv *probe_ent, int clk) { struct sata_host_regs *host_mmio = @@ -112,7 +112,7 @@ static int ahci_setup_oobr(struct ahci_probe_ent *probe_ent, return 0; } -static int ahci_host_init(struct ahci_probe_ent *probe_ent) +static int ahci_host_init(struct ahci_uc_priv *probe_ent) { u32 tmp, cap_save, num_ports; int i, j, timeout = 1000; @@ -275,7 +275,7 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent) return 0; } -static void ahci_print_info(struct ahci_probe_ent *probe_ent) +static void ahci_print_info(struct ahci_uc_priv *probe_ent) { struct sata_host_regs *host_mmio = (struct sata_host_regs *)probe_ent->mmio_base; @@ -331,10 +331,10 @@ static void ahci_print_info(struct ahci_probe_ent *probe_ent) static int ahci_init_one(int pdev) { int rc; - struct ahci_probe_ent *probe_ent = NULL; + struct ahci_uc_priv *probe_ent = NULL; - probe_ent = malloc(sizeof(struct ahci_probe_ent)); - memset(probe_ent, 0, sizeof(struct ahci_probe_ent)); + probe_ent = malloc(sizeof(struct ahci_uc_priv)); + memset(probe_ent, 0, sizeof(struct ahci_uc_priv)); probe_ent->dev = pdev; probe_ent->host_flags = ATA_FLAG_SATA @@ -361,7 +361,7 @@ err_out: return rc; } -static int ahci_fill_sg(struct ahci_probe_ent *probe_ent, +static int ahci_fill_sg(struct ahci_uc_priv *probe_ent, u8 port, unsigned char *buf, int buf_len) { struct ahci_ioports *pp = &(probe_ent->port[port]); @@ -408,7 +408,7 @@ static void ahci_fill_cmd_slot(struct ahci_ioports *pp, u32 cmd_slot, u32 opts) #define AHCI_GET_CMD_SLOT(c) ((c) ? ffs(c) : 0) -static int ahci_exec_ata_cmd(struct ahci_probe_ent *probe_ent, +static int ahci_exec_ata_cmd(struct ahci_uc_priv *probe_ent, u8 port, struct sata_fis_h2d *cfis, u8 *buf, u32 buf_len, s32 is_write) { @@ -461,8 +461,8 @@ static int ahci_exec_ata_cmd(struct ahci_probe_ent *probe_ent, static void ahci_set_feature(u8 dev, u8 port) { - struct ahci_probe_ent *probe_ent = - (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + struct ahci_uc_priv *probe_ent = + (struct ahci_uc_priv *)sata_dev_desc[dev].priv; struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN); struct sata_fis_h2d *cfis = &h2d; @@ -476,7 +476,7 @@ static void ahci_set_feature(u8 dev, u8 port) ahci_exec_ata_cmd(probe_ent, port, cfis, NULL, 0, READ_CMD); } -static int ahci_port_start(struct ahci_probe_ent *probe_ent, +static int ahci_port_start(struct ahci_uc_priv *probe_ent, u8 port) { struct ahci_ioports *pp = &(probe_ent->port[port]); @@ -560,7 +560,7 @@ int init_sata(int dev) { int i; u32 linkmap; - struct ahci_probe_ent *probe_ent = NULL; + struct ahci_uc_priv *probe_ent = NULL; #if defined(CONFIG_MX6) if (!is_mx6dq() && !is_mx6dqp()) @@ -573,7 +573,7 @@ int init_sata(int dev) ahci_init_one(dev); - probe_ent = (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + probe_ent = (struct ahci_uc_priv *)sata_dev_desc[dev].priv; linkmap = probe_ent->link_port_map; if (0 == linkmap) { @@ -597,7 +597,7 @@ int init_sata(int dev) int reset_sata(int dev) { - struct ahci_probe_ent *probe_ent; + struct ahci_uc_priv *probe_ent; struct sata_host_regs *host_mmio; if (dev < 0 || dev > (CONFIG_SYS_SATA_MAX_DEVICE - 1)) { @@ -605,7 +605,7 @@ int reset_sata(int dev) return -1; } - probe_ent = (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + probe_ent = (struct ahci_uc_priv *)sata_dev_desc[dev].priv; if (NULL == probe_ent) /* not initialized, so nothing to reset */ return 0; @@ -636,8 +636,8 @@ static void dwc_ahsata_print_info(int dev) static void dwc_ahsata_identify(int dev, u16 *id) { - struct ahci_probe_ent *probe_ent = - (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + struct ahci_uc_priv *probe_ent = + (struct ahci_uc_priv *)sata_dev_desc[dev].priv; struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN); struct sata_fis_h2d *cfis = &h2d; u8 port = probe_ent->hard_port_no; @@ -655,8 +655,8 @@ static void dwc_ahsata_identify(int dev, u16 *id) static void dwc_ahsata_xfer_mode(int dev, u16 *id) { - struct ahci_probe_ent *probe_ent = - (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + struct ahci_uc_priv *probe_ent = + (struct ahci_uc_priv *)sata_dev_desc[dev].priv; probe_ent->pio_mask = id[ATA_ID_PIO_MODES]; probe_ent->udma_mask = id[ATA_ID_UDMA_MODES]; @@ -667,8 +667,8 @@ static void dwc_ahsata_xfer_mode(int dev, u16 *id) static u32 dwc_ahsata_rw_cmd(int dev, u32 start, u32 blkcnt, u8 *buffer, int is_write) { - struct ahci_probe_ent *probe_ent = - (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + struct ahci_uc_priv *probe_ent = + (struct ahci_uc_priv *)sata_dev_desc[dev].priv; struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN); struct sata_fis_h2d *cfis = &h2d; u8 port = probe_ent->hard_port_no; @@ -698,8 +698,8 @@ static u32 dwc_ahsata_rw_cmd(int dev, u32 start, u32 blkcnt, void dwc_ahsata_flush_cache(int dev) { - struct ahci_probe_ent *probe_ent = - (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + struct ahci_uc_priv *probe_ent = + (struct ahci_uc_priv *)sata_dev_desc[dev].priv; struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN); struct sata_fis_h2d *cfis = &h2d; u8 port = probe_ent->hard_port_no; @@ -716,8 +716,8 @@ void dwc_ahsata_flush_cache(int dev) static u32 dwc_ahsata_rw_cmd_ext(int dev, u32 start, lbaint_t blkcnt, u8 *buffer, int is_write) { - struct ahci_probe_ent *probe_ent = - (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + struct ahci_uc_priv *probe_ent = + (struct ahci_uc_priv *)sata_dev_desc[dev].priv; struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN); struct sata_fis_h2d *cfis = &h2d; u8 port = probe_ent->hard_port_no; @@ -753,8 +753,8 @@ static u32 dwc_ahsata_rw_cmd_ext(int dev, u32 start, lbaint_t blkcnt, u32 dwc_ahsata_rw_ncq_cmd(int dev, u32 start, lbaint_t blkcnt, u8 *buffer, int is_write) { - struct ahci_probe_ent *probe_ent = - (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + struct ahci_uc_priv *probe_ent = + (struct ahci_uc_priv *)sata_dev_desc[dev].priv; struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN); struct sata_fis_h2d *cfis = &h2d; u8 port = probe_ent->hard_port_no; @@ -795,8 +795,8 @@ u32 dwc_ahsata_rw_ncq_cmd(int dev, u32 start, lbaint_t blkcnt, void dwc_ahsata_flush_cache_ext(int dev) { - struct ahci_probe_ent *probe_ent = - (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + struct ahci_uc_priv *probe_ent = + (struct ahci_uc_priv *)sata_dev_desc[dev].priv; struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN); struct sata_fis_h2d *cfis = &h2d; u8 port = probe_ent->hard_port_no; @@ -812,8 +812,8 @@ void dwc_ahsata_flush_cache_ext(int dev) static void dwc_ahsata_init_wcache(int dev, u16 *id) { - struct ahci_probe_ent *probe_ent = - (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + struct ahci_uc_priv *probe_ent = + (struct ahci_uc_priv *)sata_dev_desc[dev].priv; if (ata_id_has_wcache(id) && ata_id_wcache_enabled(id)) probe_ent->flags |= SATA_FLAG_WCACHE; @@ -893,7 +893,7 @@ u32 ata_low_level_rw_lba28(int dev, u32 blknr, lbaint_t blkcnt, int sata_port_status(int dev, int port) { struct sata_port_regs *port_mmio; - struct ahci_probe_ent *probe_ent = NULL; + struct ahci_uc_priv *probe_ent = NULL; if (dev < 0 || dev > (CONFIG_SYS_SATA_MAX_DEVICE - 1)) return -EINVAL; @@ -901,7 +901,7 @@ int sata_port_status(int dev, int port) if (sata_dev_desc[dev].priv == NULL) return -ENODEV; - probe_ent = (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + probe_ent = (struct ahci_uc_priv *)sata_dev_desc[dev].priv; port_mmio = (struct sata_port_regs *)probe_ent->port[port].port_mmio; return readl(&(port_mmio->ssts)) & SATA_PORT_SSTS_DET_MASK; @@ -926,8 +926,8 @@ ulong sata_read(int dev, ulong blknr, lbaint_t blkcnt, void *buffer) ulong sata_write(int dev, ulong blknr, lbaint_t blkcnt, const void *buffer) { u32 rc; - struct ahci_probe_ent *probe_ent = - (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + struct ahci_uc_priv *probe_ent = + (struct ahci_uc_priv *)sata_dev_desc[dev].priv; u32 flags = probe_ent->flags; if (sata_dev_desc[dev].lba48) { @@ -953,8 +953,8 @@ int scan_sata(int dev) u8 product[ATA_ID_PROD_LEN + 1] = { 0 }; u16 *id; u64 n_sectors; - struct ahci_probe_ent *probe_ent = - (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + struct ahci_uc_priv *probe_ent = + (struct ahci_uc_priv *)sata_dev_desc[dev].priv; u8 port = probe_ent->hard_port_no; struct blk_desc *pdev = &(sata_dev_desc[dev]); diff --git a/include/ahci.h b/include/ahci.h index 4876b41..1f441d1 100644 --- a/include/ahci.h +++ b/include/ahci.h @@ -144,8 +144,19 @@ struct ahci_ioports { u32 rx_fis; }; -struct ahci_probe_ent { +/** + * struct ahci_uc_priv - information about an AHCI controller + * + * When driver model is used, this is accessible using dev_get_uclass_priv(dev) + * where dev is the controller (although at present it sometimes stands alone). + */ +struct ahci_uc_priv { #if defined(CONFIG_DM_PCI) || defined(CONFIG_DM_SCSI) + /* + * TODO(sjg@chromium.org): Drop this once this structure is only used + * in a driver-model context (i.e. attached to a device with + * dev_get_uclass_priv() + */ struct udevice *dev; #else pci_dev_t dev; -- cgit v0.10.2 From 4b62b2ff53e48ba31d341507c09951f8de353f99 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 14 Jun 2017 21:28:33 -0600 Subject: dm: sata: Move ataid into struct ahci_uc_priv This array relates to the AHCI controller so should be exist out on its own in the file. Move it into the structure. Adjust functions that need access to this to take the structure as a parameter. Signed-off-by: Simon Glass Reviewed-by: Bin Meng diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 2caa29b..3fb41de 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -25,7 +25,6 @@ static int ata_io_flush(u8 port); struct ahci_uc_priv *probe_ent = NULL; -u16 *ataid[AHCI_MAX_PORTS]; #define writel_with_flush(a,b) do { writel(a,b); readl(b); } while (0) @@ -109,11 +108,11 @@ static int waiting_for_cmd_completed(void __iomem *offset, return (i < timeout_msec) ? 0 : -1; } -int __weak ahci_link_up(struct ahci_uc_priv *probe_ent, u8 port) +int __weak ahci_link_up(struct ahci_uc_priv *uc_priv, u8 port) { u32 tmp; int j = 0; - void __iomem *port_mmio = probe_ent->port[port].port_mmio; + void __iomem *port_mmio = uc_priv->port[port].port_mmio; /* * Bring up SATA link. @@ -555,7 +554,7 @@ static int wait_spinup(void __iomem *port_mmio) return -ETIMEDOUT; } -static int ahci_port_start(u8 port) +static int ahci_port_start(struct ahci_uc_priv *probe_ent, u8 port) { struct ahci_ioports *pp = &(probe_ent->port[port]); void __iomem *port_mmio = pp->port_mmio; @@ -689,7 +688,8 @@ static char *ata_id_strcpy(u16 *target, u16 *src, int len) /* * SCSI INQUIRY command operation. */ -static int ata_scsiop_inquiry(struct scsi_cmd *pccb) +static int ata_scsiop_inquiry(struct ahci_uc_priv *uc_priv, + struct scsi_cmd *pccb) { static const u8 hdr[] = { 0, @@ -726,15 +726,15 @@ static int ata_scsiop_inquiry(struct scsi_cmd *pccb) return -EIO; } - if (!ataid[port]) { - ataid[port] = malloc(ATA_ID_WORDS * 2); - if (!ataid[port]) { + if (!uc_priv->ataid[port]) { + uc_priv->ataid[port] = malloc(ATA_ID_WORDS * 2); + if (!uc_priv->ataid[port]) { printf("%s: No memory for ataid[port]\n", __func__); return -ENOMEM; } } - idbuf = ataid[port]; + idbuf = uc_priv->ataid[port]; memcpy(idbuf, tmpid, ATA_ID_WORDS * 2); ata_swap_buf_le16(idbuf, ATA_ID_WORDS); @@ -864,20 +864,21 @@ static int ata_scsiop_read_write(struct scsi_cmd *pccb, u8 is_write) /* * SCSI READ CAPACITY10 command operation. */ -static int ata_scsiop_read_capacity10(struct scsi_cmd *pccb) +static int ata_scsiop_read_capacity10(struct ahci_uc_priv *uc_priv, + struct scsi_cmd *pccb) { u32 cap; u64 cap64; u32 block_size; - if (!ataid[pccb->target]) { + if (!uc_priv->ataid[pccb->target]) { printf("scsi_ahci: SCSI READ CAPACITY10 command failure. " "\tNo ATA info!\n" "\tPlease run SCSI command INQUIRY first!\n"); return -EPERM; } - cap64 = ata_id_n_sectors(ataid[pccb->target]); + cap64 = ata_id_n_sectors(uc_priv->ataid[pccb->target]); if (cap64 > 0x100000000ULL) cap64 = 0xffffffff; @@ -894,19 +895,20 @@ static int ata_scsiop_read_capacity10(struct scsi_cmd *pccb) /* * SCSI READ CAPACITY16 command operation. */ -static int ata_scsiop_read_capacity16(struct scsi_cmd *pccb) +static int ata_scsiop_read_capacity16(struct ahci_uc_priv *uc_priv, + struct scsi_cmd *pccb) { u64 cap; u64 block_size; - if (!ataid[pccb->target]) { + if (!uc_priv->ataid[pccb->target]) { printf("scsi_ahci: SCSI READ CAPACITY16 command failure. " "\tNo ATA info!\n" "\tPlease run SCSI command INQUIRY first!\n"); return -EPERM; } - cap = ata_id_n_sectors(ataid[pccb->target]); + cap = ata_id_n_sectors(uc_priv->ataid[pccb->target]); cap = cpu_to_be64(cap); memcpy(pccb->pdata, &cap, sizeof(cap)); @@ -920,14 +922,16 @@ static int ata_scsiop_read_capacity16(struct scsi_cmd *pccb) /* * SCSI TEST UNIT READY command operation. */ -static int ata_scsiop_test_unit_ready(struct scsi_cmd *pccb) +static int ata_scsiop_test_unit_ready(struct ahci_uc_priv *uc_priv, + struct scsi_cmd *pccb) { - return (ataid[pccb->target]) ? 0 : -EPERM; + return (uc_priv->ataid[pccb->target]) ? 0 : -EPERM; } int scsi_exec(struct scsi_cmd *pccb) { + struct ahci_uc_priv *uc_priv = probe_ent; int ret; switch (pccb->cmd[0]) { @@ -939,16 +943,16 @@ int scsi_exec(struct scsi_cmd *pccb) ret = ata_scsiop_read_write(pccb, 1); break; case SCSI_RD_CAPAC10: - ret = ata_scsiop_read_capacity10(pccb); + ret = ata_scsiop_read_capacity10(uc_priv, pccb); break; case SCSI_RD_CAPAC16: - ret = ata_scsiop_read_capacity16(pccb); + ret = ata_scsiop_read_capacity16(uc_priv, pccb); break; case SCSI_TST_U_RDY: - ret = ata_scsiop_test_unit_ready(pccb); + ret = ata_scsiop_test_unit_ready(uc_priv, pccb); break; case SCSI_INQUIRY: - ret = ata_scsiop_inquiry(pccb); + ret = ata_scsiop_inquiry(uc_priv, pccb); break; default: printf("Unsupport SCSI command 0x%02x\n", pccb->cmd[0]); @@ -992,7 +996,7 @@ void scsi_low_level_init(int busdevfunc) for (i = 0; i < CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) { if (((linkmap >> i) & 0x01)) { - if (ahci_port_start((u8) i)) { + if (ahci_port_start(probe_ent, (u8) i)) { printf("Can not start port %d\n", i); continue; } @@ -1035,7 +1039,7 @@ int ahci_init(void __iomem *base) for (i = 0; i < CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) { if (((linkmap >> i) & 0x01)) { - if (ahci_port_start((u8) i)) { + if (ahci_port_start(probe_ent, (u8) i)) { printf("Can not start port %d\n", i); continue; } diff --git a/include/ahci.h b/include/ahci.h index 1f441d1..4262ab7 100644 --- a/include/ahci.h +++ b/include/ahci.h @@ -162,6 +162,7 @@ struct ahci_uc_priv { pci_dev_t dev; #endif struct ahci_ioports port[AHCI_MAX_PORTS]; + u16 *ataid[AHCI_MAX_PORTS]; u32 n_ports; u32 hard_port_no; u32 host_flags; -- cgit v0.10.2 From 225b1da7bfaf3c6a6812adb3ed1a85ada76c85f4 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 14 Jun 2017 21:28:34 -0600 Subject: dm: ahci: Refactor to avoid static variables With driver model we need each device to have its own state. As a step towards this, restrict use of the global 'probe_ent' to just a few places in the file. This will allow us to add driver-model functions which can pass the correct data around. Signed-off-by: Simon Glass Reviewed-by: Bin Meng diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 3fb41de..2e51b49 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -22,7 +22,7 @@ #include #include -static int ata_io_flush(u8 port); +static int ata_io_flush(struct ahci_uc_priv *uc_priv, u8 port); struct ahci_uc_priv *probe_ent = NULL; @@ -165,19 +165,19 @@ int ahci_reset(void __iomem *base) return 0; } -static int ahci_host_init(struct ahci_uc_priv *probe_ent) +static int ahci_host_init(struct ahci_uc_priv *uc_priv) { #if !defined(CONFIG_SCSI_AHCI_PLAT) && !defined(CONFIG_DM_SCSI) # ifdef CONFIG_DM_PCI - struct udevice *dev = probe_ent->dev; + struct udevice *dev = uc_priv->dev; struct pci_child_platdata *pplat = dev_get_parent_platdata(dev); # else - pci_dev_t pdev = probe_ent->dev; + pci_dev_t pdev = uc_priv->dev; unsigned short vendor; # endif u16 tmp16; #endif - void __iomem *mmio = probe_ent->mmio_base; + void __iomem *mmio = uc_priv->mmio_base; u32 tmp, cap_save, cmd; int i, j, ret; void __iomem *port_mmio; @@ -189,7 +189,7 @@ static int ahci_host_init(struct ahci_uc_priv *probe_ent) cap_save &= ((1 << 28) | (1 << 17)); cap_save |= (1 << 27); /* Staggered Spin-up. Not needed. */ - ret = ahci_reset(probe_ent->mmio_base); + ret = ahci_reset(uc_priv->mmio_base); if (ret) return ret; @@ -216,23 +216,23 @@ static int ahci_host_init(struct ahci_uc_priv *probe_ent) } # endif #endif - probe_ent->cap = readl(mmio + HOST_CAP); - probe_ent->port_map = readl(mmio + HOST_PORTS_IMPL); - port_map = probe_ent->port_map; - probe_ent->n_ports = (probe_ent->cap & 0x1f) + 1; + uc_priv->cap = readl(mmio + HOST_CAP); + uc_priv->port_map = readl(mmio + HOST_PORTS_IMPL); + port_map = uc_priv->port_map; + uc_priv->n_ports = (uc_priv->cap & 0x1f) + 1; debug("cap 0x%x port_map 0x%x n_ports %d\n", - probe_ent->cap, probe_ent->port_map, probe_ent->n_ports); + uc_priv->cap, uc_priv->port_map, uc_priv->n_ports); - if (probe_ent->n_ports > CONFIG_SYS_SCSI_MAX_SCSI_ID) - probe_ent->n_ports = CONFIG_SYS_SCSI_MAX_SCSI_ID; + if (uc_priv->n_ports > CONFIG_SYS_SCSI_MAX_SCSI_ID) + uc_priv->n_ports = CONFIG_SYS_SCSI_MAX_SCSI_ID; - for (i = 0; i < probe_ent->n_ports; i++) { + for (i = 0; i < uc_priv->n_ports; i++) { if (!(port_map & (1 << i))) continue; - probe_ent->port[i].port_mmio = ahci_port_base(mmio, i); - port_mmio = (u8 *) probe_ent->port[i].port_mmio; - ahci_setup_port(&probe_ent->port[i], mmio, i); + uc_priv->port[i].port_mmio = ahci_port_base(mmio, i); + port_mmio = (u8 *)uc_priv->port[i].port_mmio; + ahci_setup_port(&uc_priv->port[i], mmio, i); /* make sure port is not active */ tmp = readl(port_mmio + PORT_CMD); @@ -261,7 +261,7 @@ static int ahci_host_init(struct ahci_uc_priv *probe_ent) writel_with_flush(cmd, port_mmio + PORT_CMD); /* Bring up SATA link. */ - ret = ahci_link_up(probe_ent, i); + ret = ahci_link_up(uc_priv, i); if (ret) { printf("SATA link %d timeout.\n", i); continue; @@ -318,7 +318,7 @@ static int ahci_host_init(struct ahci_uc_priv *probe_ent) tmp = readl(port_mmio + PORT_SCR_STAT); debug("SATA port %d status: 0x%x\n", i, tmp); if ((tmp & PORT_SCR_STAT_DET_MASK) == PORT_SCR_STAT_DET_PHYRDY) - probe_ent->link_port_map |= (0x01 << i); + uc_priv->link_port_map |= (0x01 << i); } tmp = readl(mmio + HOST_CTL); @@ -343,25 +343,25 @@ static int ahci_host_init(struct ahci_uc_priv *probe_ent) } -static void ahci_print_info(struct ahci_uc_priv *probe_ent) +static void ahci_print_info(struct ahci_uc_priv *uc_priv) { #if !defined(CONFIG_SCSI_AHCI_PLAT) && !defined(CONFIG_DM_SCSI) # if defined(CONFIG_DM_PCI) - struct udevice *dev = probe_ent->dev; + struct udevice *dev = uc_priv->dev; # else - pci_dev_t pdev = probe_ent->dev; + pci_dev_t pdev = uc_priv->dev; # endif u16 cc; #endif - void __iomem *mmio = probe_ent->mmio_base; + void __iomem *mmio = uc_priv->mmio_base; u32 vers, cap, cap2, impl, speed; const char *speed_s; const char *scc_s; vers = readl(mmio + HOST_VERSION); - cap = probe_ent->cap; + cap = uc_priv->cap; cap2 = readl(mmio + HOST_CAP2); - impl = probe_ent->port_map; + impl = uc_priv->port_map; speed = (cap >> 20) & 0xf; if (speed == 1) @@ -431,6 +431,7 @@ static int ahci_init_one(struct udevice *dev) static int ahci_init_one(pci_dev_t dev) # endif { + struct ahci_uc_priv *uc_priv; #if !defined(CONFIG_DM_SCSI) u16 vendor; #endif @@ -438,24 +439,25 @@ static int ahci_init_one(pci_dev_t dev) probe_ent = malloc(sizeof(struct ahci_uc_priv)); if (!probe_ent) { - printf("%s: No memory for probe_ent\n", __func__); + printf("%s: No memory for uc_priv\n", __func__); return -ENOMEM; } - memset(probe_ent, 0, sizeof(struct ahci_uc_priv)); - probe_ent->dev = dev; + uc_priv = probe_ent; + memset(uc_priv, 0, sizeof(struct ahci_uc_priv)); + uc_priv->dev = dev; - probe_ent->host_flags = ATA_FLAG_SATA + uc_priv->host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | ATA_FLAG_NO_ATAPI; - probe_ent->pio_mask = 0x1f; - probe_ent->udma_mask = 0x7f; /*Fixme,assume to support UDMA6 */ + uc_priv->pio_mask = 0x1f; + uc_priv->udma_mask = 0x7f; /*Fixme,assume to support UDMA6 */ #if !defined(CONFIG_DM_SCSI) #ifdef CONFIG_DM_PCI - probe_ent->mmio_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_5, + uc_priv->mmio_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_5, PCI_REGION_MEM); /* Take from kernel: @@ -466,7 +468,7 @@ static int ahci_init_one(pci_dev_t dev) if (vendor == 0x197b) dm_pci_write_config8(dev, 0x41, 0xa1); #else - probe_ent->mmio_base = pci_map_bar(dev, PCI_BASE_ADDRESS_5, + uc_priv->mmio_base = pci_map_bar(dev, PCI_BASE_ADDRESS_5, PCI_REGION_MEM); /* Take from kernel: @@ -479,16 +481,16 @@ static int ahci_init_one(pci_dev_t dev) #endif #else struct scsi_platdata *plat = dev_get_uclass_platdata(dev); - probe_ent->mmio_base = (void *)plat->base; + uc_priv->mmio_base = (void *)plat->base; #endif - debug("ahci mmio_base=0x%p\n", probe_ent->mmio_base); + debug("ahci mmio_base=0x%p\n", uc_priv->mmio_base); /* initialize adapter */ - rc = ahci_host_init(probe_ent); + rc = ahci_host_init(uc_priv); if (rc) goto err_out; - ahci_print_info(probe_ent); + ahci_print_info(uc_priv); return 0; @@ -499,9 +501,10 @@ static int ahci_init_one(pci_dev_t dev) #define MAX_DATA_BYTE_COUNT (4*1024*1024) -static int ahci_fill_sg(u8 port, unsigned char *buf, int buf_len) +static int ahci_fill_sg(struct ahci_uc_priv *uc_priv, u8 port, + unsigned char *buf, int buf_len) { - struct ahci_ioports *pp = &(probe_ent->port[port]); + struct ahci_ioports *pp = &(uc_priv->port[port]); struct ahci_sg *ahci_sg = pp->cmd_tbl_sg; u32 sg_count; int i; @@ -554,9 +557,9 @@ static int wait_spinup(void __iomem *port_mmio) return -ETIMEDOUT; } -static int ahci_port_start(struct ahci_uc_priv *probe_ent, u8 port) +static int ahci_port_start(struct ahci_uc_priv *uc_priv, u8 port) { - struct ahci_ioports *pp = &(probe_ent->port[port]); + struct ahci_ioports *pp = &(uc_priv->port[port]); void __iomem *port_mmio = pp->port_mmio; u32 port_status; void __iomem *mem; @@ -629,11 +632,11 @@ static int ahci_port_start(struct ahci_uc_priv *probe_ent, u8 port) } -static int ahci_device_data_io(u8 port, u8 *fis, int fis_len, u8 *buf, - int buf_len, u8 is_write) +static int ahci_device_data_io(struct ahci_uc_priv *uc_priv, u8 port, u8 *fis, + int fis_len, u8 *buf, int buf_len, u8 is_write) { - struct ahci_ioports *pp = &(probe_ent->port[port]); + struct ahci_ioports *pp = &(uc_priv->port[port]); void __iomem *port_mmio = pp->port_mmio; u32 opts; u32 port_status; @@ -641,7 +644,7 @@ static int ahci_device_data_io(u8 port, u8 *fis, int fis_len, u8 *buf, debug("Enter %s: for port %d\n", __func__, port); - if (port > probe_ent->n_ports) { + if (port > uc_priv->n_ports) { printf("Invalid port number %d\n", port); return -1; } @@ -654,7 +657,7 @@ static int ahci_device_data_io(u8 port, u8 *fis, int fis_len, u8 *buf, memcpy((unsigned char *)pp->cmd_tbl, fis, fis_len); - sg_count = ahci_fill_sg(port, buf, buf_len); + sg_count = ahci_fill_sg(uc_priv, port, buf, buf_len); opts = (fis_len >> 2) | (sg_count << 16) | (is_write << 6); ahci_fill_cmd_slot(pp, opts); @@ -720,8 +723,8 @@ static int ata_scsiop_inquiry(struct ahci_uc_priv *uc_priv, /* Read id from sata */ port = pccb->target; - if (ahci_device_data_io(port, (u8 *) &fis, sizeof(fis), (u8 *)tmpid, - ATA_ID_WORDS * 2, 0)) { + if (ahci_device_data_io(uc_priv, port, (u8 *)&fis, sizeof(fis), + (u8 *)tmpid, ATA_ID_WORDS * 2, 0)) { debug("scsi_ahci: SCSI inquiry command failure.\n"); return -EIO; } @@ -753,7 +756,8 @@ static int ata_scsiop_inquiry(struct ahci_uc_priv *uc_priv, /* * SCSI READ10/WRITE10 command operation. */ -static int ata_scsiop_read_write(struct scsi_cmd *pccb, u8 is_write) +static int ata_scsiop_read_write(struct ahci_uc_priv *uc_priv, + struct scsi_cmd *pccb, u8 is_write) { lbaint_t lba = 0; u16 blocks = 0; @@ -833,8 +837,8 @@ static int ata_scsiop_read_write(struct scsi_cmd *pccb, u8 is_write) fis[13] = (now_blocks >> 8) & 0xff; /* Read/Write from ahci */ - if (ahci_device_data_io(pccb->target, (u8 *) &fis, sizeof(fis), - user_buffer, transfer_size, + if (ahci_device_data_io(uc_priv, pccb->target, (u8 *)&fis, + sizeof(fis), user_buffer, transfer_size, is_write)) { debug("scsi_ahci: SCSI %s10 command failure.\n", is_write ? "WRITE" : "READ"); @@ -848,7 +852,7 @@ static int ata_scsiop_read_write(struct scsi_cmd *pccb, u8 is_write) * usually, one extra flush when the rare writes do happen. */ if (is_write) { - if (-EIO == ata_io_flush(pccb->target)) + if (-EIO == ata_io_flush(uc_priv, pccb->target)) return -EIO; } user_buffer += transfer_size; @@ -937,10 +941,10 @@ int scsi_exec(struct scsi_cmd *pccb) switch (pccb->cmd[0]) { case SCSI_READ16: case SCSI_READ10: - ret = ata_scsiop_read_write(pccb, 0); + ret = ata_scsiop_read_write(uc_priv, pccb, 0); break; case SCSI_WRITE10: - ret = ata_scsiop_read_write(pccb, 1); + ret = ata_scsiop_read_write(uc_priv, pccb, 1); break; case SCSI_RD_CAPAC10: ret = ata_scsiop_read_capacity10(uc_priv, pccb); @@ -973,6 +977,7 @@ void scsi_low_level_init(int busdevfunc, struct udevice *dev) void scsi_low_level_init(int busdevfunc) #endif { + struct ahci_uc_priv *uc_priv; int i; u32 linkmap; @@ -991,12 +996,13 @@ void scsi_low_level_init(int busdevfunc) ahci_init_one(busdevfunc); # endif #endif + uc_priv = probe_ent; - linkmap = probe_ent->link_port_map; + linkmap = uc_priv->link_port_map; for (i = 0; i < CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) { if (((linkmap >> i) & 0x01)) { - if (ahci_port_start(probe_ent, (u8) i)) { + if (ahci_port_start(uc_priv, (u8) i)) { printf("Can not start port %d\n", i); continue; } @@ -1007,39 +1013,41 @@ void scsi_low_level_init(int busdevfunc) #ifdef CONFIG_SCSI_AHCI_PLAT int ahci_init(void __iomem *base) { + struct ahci_uc_priv *uc_priv; int i, rc = 0; u32 linkmap; probe_ent = malloc(sizeof(struct ahci_uc_priv)); if (!probe_ent) { - printf("%s: No memory for probe_ent\n", __func__); + printf("%s: No memory for uc_priv\n", __func__); return -ENOMEM; } - memset(probe_ent, 0, sizeof(struct ahci_uc_priv)); + uc_priv = probe_ent; + memset(uc_priv, 0, sizeof(struct ahci_uc_priv)); - probe_ent->host_flags = ATA_FLAG_SATA + uc_priv->host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | ATA_FLAG_NO_ATAPI; - probe_ent->pio_mask = 0x1f; - probe_ent->udma_mask = 0x7f; /*Fixme,assume to support UDMA6 */ + uc_priv->pio_mask = 0x1f; + uc_priv->udma_mask = 0x7f; /*Fixme,assume to support UDMA6 */ - probe_ent->mmio_base = base; + uc_priv->mmio_base = base; /* initialize adapter */ - rc = ahci_host_init(probe_ent); + rc = ahci_host_init(uc_priv); if (rc) goto err_out; - ahci_print_info(probe_ent); + ahci_print_info(uc_priv); - linkmap = probe_ent->link_port_map; + linkmap = uc_priv->link_port_map; for (i = 0; i < CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) { if (((linkmap >> i) & 0x01)) { - if (ahci_port_start(probe_ent, (u8) i)) { + if (ahci_port_start(uc_priv, (u8) i)) { printf("Can not start port %d\n", i); continue; } @@ -1064,10 +1072,10 @@ void __weak scsi_init(void) * is the last write is difficult. Because writing to the disk in u-boot is * very rare, this flush command will be invoked after every block write. */ -static int ata_io_flush(u8 port) +static int ata_io_flush(struct ahci_uc_priv *uc_priv, u8 port) { u8 fis[20]; - struct ahci_ioports *pp = &(probe_ent->port[port]); + struct ahci_ioports *pp = &(uc_priv->port[port]); void __iomem *port_mmio = pp->port_mmio; u32 cmd_fis_len = 5; /* five dwords */ -- cgit v0.10.2 From 099c239d687cd48cc05f372b9f354ffcfeeba83c Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 14 Jun 2017 21:28:35 -0600 Subject: dm: scsi: Indent the confusing #ifdefs These are very confusing without some sort of indentation. At some point we will be able to remove them, but for now, indent them. Signed-off-by: Simon Glass Reviewed-by: Bin Meng diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 2d0f81a..e3d1690 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -14,19 +14,19 @@ #include #if !defined(CONFIG_DM_SCSI) -#ifdef CONFIG_SCSI_DEV_LIST -#define SCSI_DEV_LIST CONFIG_SCSI_DEV_LIST -#else -#ifdef CONFIG_SATA_ULI5288 - -#define SCSI_VEND_ID 0x10b9 -#define SCSI_DEV_ID 0x5288 - -#elif !defined(CONFIG_SCSI_AHCI_PLAT) -#error no scsi device defined -#endif -#define SCSI_DEV_LIST {SCSI_VEND_ID, SCSI_DEV_ID} -#endif +# ifdef CONFIG_SCSI_DEV_LIST +# define SCSI_DEV_LIST CONFIG_SCSI_DEV_LIST +# else +# ifdef CONFIG_SATA_ULI5288 + +# define SCSI_VEND_ID 0x10b9 +# define SCSI_DEV_ID 0x5288 + +# elif !defined(CONFIG_SCSI_AHCI_PLAT) +# error no scsi device defined +# endif +# define SCSI_DEV_LIST {SCSI_VEND_ID, SCSI_DEV_ID} +# endif #endif #if defined(CONFIG_PCI) && !defined(CONFIG_SCSI_AHCI_PLAT) -- cgit v0.10.2 From 62b4ec8e302c7d616e37f2c2c2836edfea712309 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 14 Jun 2017 21:28:36 -0600 Subject: dm: ahci: Move common code for starting ports into a function This code is duplicated. Create a ahci_start_ports() function to handle this and call it from both places. Signed-off-by: Simon Glass Reviewed-by: Bin Meng diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 2e51b49..4830bcd 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -971,6 +971,25 @@ int scsi_exec(struct scsi_cmd *pccb) } +static int ahci_start_ports(struct ahci_uc_priv *uc_priv) +{ + u32 linkmap; + int i; + + linkmap = uc_priv->link_port_map; + + for (i = 0; i < CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) { + if (((linkmap >> i) & 0x01)) { + if (ahci_port_start(uc_priv, (u8) i)) { + printf("Can not start port %d\n", i); + continue; + } + } + } + + return 0; +} + #if defined(CONFIG_DM_SCSI) void scsi_low_level_init(int busdevfunc, struct udevice *dev) #else @@ -978,8 +997,6 @@ void scsi_low_level_init(int busdevfunc) #endif { struct ahci_uc_priv *uc_priv; - int i; - u32 linkmap; #ifndef CONFIG_SCSI_AHCI_PLAT # if defined(CONFIG_DM_PCI) @@ -998,24 +1015,14 @@ void scsi_low_level_init(int busdevfunc) #endif uc_priv = probe_ent; - linkmap = uc_priv->link_port_map; - - for (i = 0; i < CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) { - if (((linkmap >> i) & 0x01)) { - if (ahci_port_start(uc_priv, (u8) i)) { - printf("Can not start port %d\n", i); - continue; - } - } - } + ahci_start_ports(uc_priv); } #ifdef CONFIG_SCSI_AHCI_PLAT int ahci_init(void __iomem *base) { struct ahci_uc_priv *uc_priv; - int i, rc = 0; - u32 linkmap; + int rc = 0; probe_ent = malloc(sizeof(struct ahci_uc_priv)); if (!probe_ent) { @@ -1043,16 +1050,8 @@ int ahci_init(void __iomem *base) ahci_print_info(uc_priv); - linkmap = uc_priv->link_port_map; + rc = ahci_start_ports(uc_priv); - for (i = 0; i < CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) { - if (((linkmap >> i) & 0x01)) { - if (ahci_port_start(uc_priv, (u8) i)) { - printf("Can not start port %d\n", i); - continue; - } - } - } err_out: return rc; } -- cgit v0.10.2 From 7cf1afce7fa3fe64189020fe14b93f7326dd0758 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 14 Jun 2017 21:28:37 -0600 Subject: dm: ahci: Unwind the confusing init code Two AHCI drivers use SCSI with CONFIG_DM_SCSI. The SCSI uclass calls scsi_low_level_init() which is implemented by ahci.c. If CONFIG_SCSI_AHCI_PLAT is defined it does one thing and if it is not it does something else. We don't need to call through scsi_low_level_init() to get the init completed. Instead, adjust the two drivers to call into AHCI directly. Drop the post-probe init in the SCSI uclass. This means that driver model doesn't need to use scsi_low_level_init(). It is a legacy function and driver model should use a driver's probe() method instead. While we are here, add a comment to the top of the file explaining what ahci.c does. Signed-off-by: Simon Glass Reviewed-by: Bin Meng diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 4830bcd..e986765 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -6,6 +6,8 @@ * SPDX-License-Identifier: GPL-2.0+ * * with the reference on libata and ahci drvier in kernel + * + * This driver provides a SCSI interface to SATA. */ #include @@ -990,11 +992,8 @@ static int ahci_start_ports(struct ahci_uc_priv *uc_priv) return 0; } -#if defined(CONFIG_DM_SCSI) -void scsi_low_level_init(int busdevfunc, struct udevice *dev) -#else +#ifndef CONFIG_DM_SCSI void scsi_low_level_init(int busdevfunc) -#endif { struct ahci_uc_priv *uc_priv; @@ -1007,8 +1006,6 @@ void scsi_low_level_init(int busdevfunc) if (ret) return; ahci_init_one(dev); -# elif defined(CONFIG_DM_SCSI) - ahci_init_one(dev); # else ahci_init_one(busdevfunc); # endif @@ -1017,6 +1014,23 @@ void scsi_low_level_init(int busdevfunc) ahci_start_ports(uc_priv); } +#endif + +#ifndef CONFIG_SCSI_AHCI_PLAT +# if defined(CONFIG_DM_PCI) || defined(CONFIG_DM_SCSI) +int achi_init_one_dm(struct udevice *dev) +{ + return ahci_init_one(dev); +} +#endif +#endif + +int achi_start_ports_dm(struct udevice *dev) +{ + struct ahci_uc_priv *uc_priv = probe_ent; + + return ahci_start_ports(uc_priv); +} #ifdef CONFIG_SCSI_AHCI_PLAT int ahci_init(void __iomem *base) diff --git a/drivers/ata/dwc_ahci.c b/drivers/ata/dwc_ahci.c index e634df5..eadd779 100644 --- a/drivers/ata/dwc_ahci.c +++ b/drivers/ata/dwc_ahci.c @@ -81,7 +81,11 @@ static int dwc_ahci_probe(struct udevice *dev) writel(val, priv->wrapper_base + TI_SATA_SYSCONFIG); } - return ahci_init(priv->base); + ret = ahci_init(priv->base); + if (ret) + return ret; + + return achi_start_ports_dm(dev); } static const struct udevice_id dwc_ahci_ids[] = { diff --git a/drivers/ata/sata_ceva.c b/drivers/ata/sata_ceva.c index f55ba59..7d61a54 100644 --- a/drivers/ata/sata_ceva.c +++ b/drivers/ata/sata_ceva.c @@ -116,7 +116,8 @@ static int sata_ceva_probe(struct udevice *dev) struct scsi_platdata *plat = dev_get_uclass_platdata(dev); ceva_init_sata(plat->base); - return 0; + + return achi_init_one_dm(dev); } static const struct udevice_id sata_ceva_ids[] = { diff --git a/drivers/scsi/scsi-uclass.c b/drivers/scsi/scsi-uclass.c index e4ee44b..40c5044 100644 --- a/drivers/scsi/scsi-uclass.c +++ b/drivers/scsi/scsi-uclass.c @@ -13,16 +13,8 @@ #include #include -static int scsi_post_probe(struct udevice *dev) -{ - debug("%s: device %p\n", __func__, dev); - scsi_low_level_init(0, dev); - return 0; -} - UCLASS_DRIVER(scsi) = { .id = UCLASS_SCSI, .name = "scsi", - .post_probe = scsi_post_probe, .per_device_platdata_auto_alloc_size = sizeof(struct scsi_platdata), }; diff --git a/include/ahci.h b/include/ahci.h index 4262ab7..ec5b0c7 100644 --- a/include/ahci.h +++ b/include/ahci.h @@ -179,4 +179,18 @@ struct ahci_uc_priv { int ahci_init(void __iomem *base); int ahci_reset(void __iomem *base); +/** + * achi_init_one_dm() - set up a single AHCI port + * + * @dev: Controller to init + */ +int achi_init_one_dm(struct udevice *dev); + +/** + * achi_start_ports_dm() - start all AHCI ports for a controller + * + * @dev: Controller containing ports to start + */ +int achi_start_ports_dm(struct udevice *dev); + #endif diff --git a/include/scsi.h b/include/scsi.h index bc5be97..cd1b240 100644 --- a/include/scsi.h +++ b/include/scsi.h @@ -171,9 +171,7 @@ struct scsi_platdata { unsigned long max_id; }; -#if defined(CONFIG_DM_SCSI) -void scsi_low_level_init(int busdevfunc, struct udevice *dev); -#else +#ifndef CONFIG_DM_SCSI void scsi_low_level_init(int busdevfunc); void scsi_init(void); #endif -- cgit v0.10.2 From 4279efc4c949116535bb99f4aa74260d93f82b92 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 14 Jun 2017 21:28:38 -0600 Subject: dm: ahci: Drop use of probe_ent With driver model we cannot have static data or assume that there is only one device of each time. Adjust the code so that 'probe_ent' is not needed with driver model. Add a new ahci_init_dm() function which can init AHCI for driver model without re-allocating the uclass data. Move over the only existing driver to use this new function. Signed-off-by: Simon Glass Reviewed-by: Bin Meng diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index e986765..2f77e60 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -428,25 +428,16 @@ static void ahci_print_info(struct ahci_uc_priv *uc_priv) #ifndef CONFIG_SCSI_AHCI_PLAT # if defined(CONFIG_DM_PCI) || defined(CONFIG_DM_SCSI) -static int ahci_init_one(struct udevice *dev) +static int ahci_init_one(struct ahci_uc_priv *uc_priv, struct udevice *dev) # else -static int ahci_init_one(pci_dev_t dev) +static int ahci_init_one(struct ahci_uc_priv *uc_priv, pci_dev_t dev) # endif { - struct ahci_uc_priv *uc_priv; #if !defined(CONFIG_DM_SCSI) u16 vendor; #endif int rc; - probe_ent = malloc(sizeof(struct ahci_uc_priv)); - if (!probe_ent) { - printf("%s: No memory for uc_priv\n", __func__); - return -ENOMEM; - } - - uc_priv = probe_ent; - memset(uc_priv, 0, sizeof(struct ahci_uc_priv)); uc_priv->dev = dev; uc_priv->host_flags = ATA_FLAG_SATA @@ -998,6 +989,12 @@ void scsi_low_level_init(int busdevfunc) struct ahci_uc_priv *uc_priv; #ifndef CONFIG_SCSI_AHCI_PLAT + probe_ent = calloc(1, sizeof(struct ahci_uc_priv)); + if (!probe_ent) { + printf("%s: No memory for uc_priv\n", __func__); + return; + } + uc_priv = probe_ent; # if defined(CONFIG_DM_PCI) struct udevice *dev; int ret; @@ -1005,12 +1002,13 @@ void scsi_low_level_init(int busdevfunc) ret = dm_pci_bus_find_bdf(busdevfunc, &dev); if (ret) return; - ahci_init_one(dev); + ahci_init_one(uc_priv, dev); # else - ahci_init_one(busdevfunc); + ahci_init_one(uc_priv, busdevfunc); # endif -#endif +#else uc_priv = probe_ent; +#endif ahci_start_ports(uc_priv); } @@ -1020,32 +1018,24 @@ void scsi_low_level_init(int busdevfunc) # if defined(CONFIG_DM_PCI) || defined(CONFIG_DM_SCSI) int achi_init_one_dm(struct udevice *dev) { - return ahci_init_one(dev); + struct ahci_uc_priv *uc_priv = dev_get_uclass_priv(dev); + + return ahci_init_one(uc_priv, dev); } #endif #endif int achi_start_ports_dm(struct udevice *dev) { - struct ahci_uc_priv *uc_priv = probe_ent; + struct ahci_uc_priv *uc_priv = dev_get_uclass_priv(dev); return ahci_start_ports(uc_priv); } #ifdef CONFIG_SCSI_AHCI_PLAT -int ahci_init(void __iomem *base) +static int ahci_init_common(struct ahci_uc_priv *uc_priv, void __iomem *base) { - struct ahci_uc_priv *uc_priv; - int rc = 0; - - probe_ent = malloc(sizeof(struct ahci_uc_priv)); - if (!probe_ent) { - printf("%s: No memory for uc_priv\n", __func__); - return -ENOMEM; - } - - uc_priv = probe_ent; - memset(uc_priv, 0, sizeof(struct ahci_uc_priv)); + int rc; uc_priv->host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY @@ -1070,11 +1060,36 @@ err_out: return rc; } +#ifndef CONFIG_DM_SCSI +int ahci_init(void __iomem *base) +{ + struct ahci_uc_priv *uc_priv; + + probe_ent = malloc(sizeof(struct ahci_uc_priv)); + if (!probe_ent) { + printf("%s: No memory for uc_priv\n", __func__); + return -ENOMEM; + } + + uc_priv = probe_ent; + memset(uc_priv, 0, sizeof(struct ahci_uc_priv)); + + return ahci_init_common(uc_priv, base); +} +#endif + +int ahci_init_dm(struct udevice *dev, void __iomem *base) +{ + struct ahci_uc_priv *uc_priv = dev_get_uclass_priv(dev); + + return ahci_init_common(uc_priv, base); +} + void __weak scsi_init(void) { } -#endif +#endif /* CONFIG_SCSI_AHCI_PLAT */ /* * In the general case of generic rotating media it makes sense to have a diff --git a/drivers/ata/dwc_ahci.c b/drivers/ata/dwc_ahci.c index eadd779..4012017 100644 --- a/drivers/ata/dwc_ahci.c +++ b/drivers/ata/dwc_ahci.c @@ -81,7 +81,7 @@ static int dwc_ahci_probe(struct udevice *dev) writel(val, priv->wrapper_base + TI_SATA_SYSCONFIG); } - ret = ahci_init(priv->base); + ret = ahci_init_dm(dev, priv->base); if (ret) return ret; diff --git a/include/ahci.h b/include/ahci.h index ec5b0c7..3d61ad1 100644 --- a/include/ahci.h +++ b/include/ahci.h @@ -193,4 +193,11 @@ int achi_init_one_dm(struct udevice *dev); */ int achi_start_ports_dm(struct udevice *dev); +/** + * ahci_init_dm() - init AHCI for a controller, finding all ports + * + * @dev: Device to init + */ +int ahci_init_dm(struct udevice *dev, void __iomem *base); + #endif -- cgit v0.10.2 From 322f73f473d921dbdd0fe11bd62db6a00e5b133c Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 14 Jun 2017 21:28:39 -0600 Subject: dm: scsi: Add operations Add operations for SCSI. These are not yet implemented, but we have the struct. Signed-off-by: Simon Glass Reviewed-by: Bin Meng diff --git a/include/scsi.h b/include/scsi.h index cd1b240..d2fa8a5 100644 --- a/include/scsi.h +++ b/include/scsi.h @@ -171,6 +171,26 @@ struct scsi_platdata { unsigned long max_id; }; +/* Operations for SCSI */ +struct scsi_ops { + /** + * exec() - execute a command + * + * @dev: SCSI bus + * @cmd: Command to execute + * @return 0 if OK, -ve on error + */ + int (*exec)(struct udevice *dev, struct scsi_cmd *cmd); + + /** + * bus_reset() - reset the bus + * + * @dev: SCSI bus to reset + * @return 0 if OK, -ve on error + */ + int (*bus_reset)(struct udevice *dev); +}; + #ifndef CONFIG_DM_SCSI void scsi_low_level_init(int busdevfunc); void scsi_init(void); -- cgit v0.10.2 From 4682c8a19b4eb69f7ad51df3f543375583ce878a Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 14 Jun 2017 21:28:40 -0600 Subject: dm: scsi: Add a device pointer to scan_exec(), scsi_bus_reset() With driver model these functions need a device pointer. Add one even when CONFIG_DM_SCSI is not defined. This avoids having ugly conditional function prototypes, When CONFIG_DM_SCSI is not defined we can just ignore the pointer. Signed-off-by: Simon Glass Reviewed-by: Bin Meng diff --git a/arch/arm/mach-omap2/sata.c b/arch/arm/mach-omap2/sata.c index 0c82689..dc68896 100644 --- a/arch/arm/mach-omap2/sata.c +++ b/arch/arm/mach-omap2/sata.c @@ -63,8 +63,10 @@ void scsi_init(void) scsi_scan(1); } -void scsi_bus_reset(void) +int scsi_bus_reset(struct udevice *dev) { ahci_reset((void __iomem *)DWC_AHSATA_BASE); ahci_init((void __iomem *)DWC_AHSATA_BASE); + + return 0; } diff --git a/cmd/scsi.c b/cmd/scsi.c index 4213ec8..46171e5 100644 --- a/cmd/scsi.c +++ b/cmd/scsi.c @@ -36,7 +36,7 @@ static int do_scsi(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) case 2: if (strncmp(argv[1], "res", 3) == 0) { printf("\nReset SCSI\n"); - scsi_bus_reset(); + scsi_bus_reset(NULL); ret = scsi_scan(1); if (ret) return CMD_RET_FAILURE; diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 2f77e60..c3b5f2a 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -26,7 +26,9 @@ static int ata_io_flush(struct ahci_uc_priv *uc_priv, u8 port); +#ifndef CONFIG_DM_SCSI struct ahci_uc_priv *probe_ent = NULL; +#endif #define writel_with_flush(a,b) do { writel(a,b); readl(b); } while (0) @@ -926,9 +928,14 @@ static int ata_scsiop_test_unit_ready(struct ahci_uc_priv *uc_priv, } -int scsi_exec(struct scsi_cmd *pccb) +int scsi_exec(struct udevice *dev, struct scsi_cmd *pccb) { - struct ahci_uc_priv *uc_priv = probe_ent; + struct ahci_uc_priv *uc_priv; +#ifdef CONFIG_DM_SCSI + uc_priv = dev_get_uclass_priv(dev); +#else + uc_priv = probe_ent; +#endif int ret; switch (pccb->cmd[0]) { @@ -1128,7 +1135,9 @@ static int ata_io_flush(struct ahci_uc_priv *uc_priv, u8 port) } -__weak void scsi_bus_reset(void) +__weak int scsi_bus_reset(struct udevice *dev) { /*Not implement*/ + + return 0; } diff --git a/drivers/scsi/sandbox_scsi.c b/drivers/scsi/sandbox_scsi.c index d943d1f..ac60ae0 100644 --- a/drivers/scsi/sandbox_scsi.c +++ b/drivers/scsi/sandbox_scsi.c @@ -11,15 +11,16 @@ #include #include -void scsi_bus_reset(void) +int scsi_bus_reset(struct udevice *dev) { + return 0; } void scsi_init(void) { } -int scsi_exec(struct scsi_cmd *pccb) +int scsi_exec(struct udevice *dev, struct scsi_cmd *pccb) { return 0; } diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index e3d1690..9232f3a 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -151,6 +151,9 @@ static ulong scsi_read(struct blk_desc *block_dev, lbaint_t blknr, { #ifdef CONFIG_BLK struct blk_desc *block_dev = dev_get_uclass_platdata(dev); + struct udevice *bdev = dev->parent; +#else + struct udevice *bdev = NULL; #endif lbaint_t start, blks; uintptr_t buf_addr; @@ -195,7 +198,7 @@ static ulong scsi_read(struct blk_desc *block_dev, lbaint_t blknr, debug("scsi_read_ext: startblk " LBAF ", blccnt %x buffer %" PRIXPTR "\n", start, smallblks, buf_addr); - if (scsi_exec(pccb) != true) { + if (scsi_exec(bdev, pccb)) { scsi_print_error(pccb); blkcnt -= blks; break; @@ -224,6 +227,9 @@ static ulong scsi_write(struct blk_desc *block_dev, lbaint_t blknr, { #ifdef CONFIG_BLK struct blk_desc *block_dev = dev_get_uclass_platdata(dev); + struct udevice *bdev = dev->parent; +#else + struct udevice *bdev = NULL; #endif lbaint_t start, blks; uintptr_t buf_addr; @@ -256,7 +262,7 @@ static ulong scsi_write(struct blk_desc *block_dev, lbaint_t blknr, } debug("%s: startblk " LBAF ", blccnt %x buffer %" PRIXPTR "\n", __func__, start, smallblks, buf_addr); - if (scsi_exec(pccb) != true) { + if (scsi_exec(bdev, pccb)) { scsi_print_error(pccb); blkcnt -= blks; break; @@ -350,8 +356,8 @@ static void scsi_ident_cpy(unsigned char *dest, unsigned char *src, *dest = '\0'; } -static int scsi_read_capacity(struct scsi_cmd *pccb, lbaint_t *capacity, - unsigned long *blksz) +static int scsi_read_capacity(struct udevice *dev, struct scsi_cmd *pccb, + lbaint_t *capacity, unsigned long *blksz) { *capacity = 0; @@ -362,7 +368,7 @@ static int scsi_read_capacity(struct scsi_cmd *pccb, lbaint_t *capacity, pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ pccb->datalen = 8; - if (scsi_exec(pccb) != true) + if (scsi_exec(dev, pccb) != true) return 1; *capacity = ((lbaint_t)pccb->pdata[0] << 24) | @@ -387,7 +393,7 @@ static int scsi_read_capacity(struct scsi_cmd *pccb, lbaint_t *capacity, pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ pccb->datalen = 16; - if (scsi_exec(pccb) != true) + if (scsi_exec(dev, pccb) != true) return 1; *capacity = ((uint64_t)pccb->pdata[0] << 56) | @@ -480,7 +486,8 @@ static void scsi_init_dev_desc(struct blk_desc *dev_desc, int devnum) * * Return: 0 on success, error value otherwise */ -static int scsi_detect_dev(int target, int lun, struct blk_desc *dev_desc) +static int scsi_detect_dev(struct udevice *dev, int target, int lun, + struct blk_desc *dev_desc) { unsigned char perq, modi; lbaint_t capacity; @@ -492,7 +499,7 @@ static int scsi_detect_dev(int target, int lun, struct blk_desc *dev_desc) pccb->pdata = (unsigned char *)&tempbuff; pccb->datalen = 512; scsi_setup_inquiry(pccb); - if (scsi_exec(pccb) != true) { + if (scsi_exec(dev, pccb) != true) { if (pccb->contr_stat == SCSI_SEL_TIME_OUT) { /* * selection timeout => assuming no @@ -523,7 +530,7 @@ static int scsi_detect_dev(int target, int lun, struct blk_desc *dev_desc) pccb->datalen = 0; scsi_setup_test_unit_ready(pccb); - if (scsi_exec(pccb) != true) { + if (scsi_exec(dev, pccb) != true) { if (dev_desc->removable) { dev_desc->type = perq; goto removable; @@ -531,7 +538,7 @@ static int scsi_detect_dev(int target, int lun, struct blk_desc *dev_desc) scsi_print_error(pccb); return -EINVAL; } - if (scsi_read_capacity(pccb, &capacity, &blksz)) { + if (scsi_read_capacity(dev, pccb, &capacity, &blksz)) { scsi_print_error(pccb); return -EINVAL; } @@ -561,7 +568,7 @@ static int do_scsi_scan_one(struct udevice *dev, int id, int lun, int mode) * size, number of blocks) and other parameters (ids, type, ...) */ scsi_init_dev_desc_priv(&bd); - if (scsi_detect_dev(id, lun, &bd)) + if (scsi_detect_dev(dev, id, lun, &bd)) return -ENODEV; /* @@ -642,7 +649,7 @@ int scsi_scan(int mode) scsi_max_devs = 0; for (i = 0; i < CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) { for (lun = 0; lun < CONFIG_SYS_SCSI_MAX_LUN; lun++) { - ret = scsi_detect_dev(i, lun, + ret = scsi_detect_dev(NULL, i, lun, &scsi_dev_desc[scsi_max_devs]); if (ret) continue; diff --git a/include/scsi.h b/include/scsi.h index d2fa8a5..af07dbe 100644 --- a/include/scsi.h +++ b/include/scsi.h @@ -196,8 +196,8 @@ void scsi_low_level_init(int busdevfunc); void scsi_init(void); #endif -int scsi_exec(struct scsi_cmd *pccb); -void scsi_bus_reset(void); +int scsi_exec(struct udevice *dev, struct scsi_cmd *pccb); +int scsi_bus_reset(struct udevice *dev); /*************************************************************************** * functions residing inside cmd_scsi.c -- cgit v0.10.2 From 8eab1a58dd53cbf89dca54f91cf3fbb51d714644 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 14 Jun 2017 21:28:41 -0600 Subject: dm: scsi: Document and rename the scsi_scan() parameter The 'mode' parameter is actually a flag to determine whether to display a list of devices found during the scan. Rename it to reflect this, add a function comment and adjust callers to use a boolean. Signed-off-by: Simon Glass Reviewed-by: Bin Meng diff --git a/arch/arm/cpu/armv7/ls102xa/ls102xa_sata.c b/arch/arm/cpu/armv7/ls102xa/ls102xa_sata.c index 144f2c3..e11d3a1 100644 --- a/arch/arm/cpu/armv7/ls102xa/ls102xa_sata.c +++ b/arch/arm/cpu/armv7/ls102xa/ls102xa_sata.c @@ -36,7 +36,7 @@ int ls1021a_sata_init(void) out_le32(&ccsr_ahci->ptc, AHCI_PORT_TRANS_CFG); ahci_init((void __iomem *)AHCI_BASE_ADDR); - scsi_scan(0); + scsi_scan(false); return 0; } diff --git a/arch/arm/cpu/armv8/fsl-layerscape/soc.c b/arch/arm/cpu/armv8/fsl-layerscape/soc.c index 0943e83..aee1ffa 100644 --- a/arch/arm/cpu/armv8/fsl-layerscape/soc.c +++ b/arch/arm/cpu/armv8/fsl-layerscape/soc.c @@ -225,7 +225,7 @@ int sata_init(void) out_le32(&ccsr_ahci->axicc, AHCI_PORT_AXICC_CFG); ahci_init((void __iomem *)CONFIG_SYS_SATA1); - scsi_scan(0); + scsi_scan(false); return 0; } @@ -244,7 +244,7 @@ int sata_init(void) out_le32(&ccsr_ahci->axicc, AHCI_PORT_AXICC_CFG); ahci_init((void __iomem *)CONFIG_SYS_SATA); - scsi_scan(0); + scsi_scan(false); return 0; } diff --git a/board/highbank/highbank.c b/board/highbank/highbank.c index 55999ed..1af2207 100644 --- a/board/highbank/highbank.c +++ b/board/highbank/highbank.c @@ -67,7 +67,7 @@ void scsi_init(void) cphy_disable_overrides(); if (reg & PWRDOM_STAT_SATA) { ahci_init((void __iomem *)HB_AHCI_BASE); - scsi_scan(1); + scsi_scan(true); } } #endif diff --git a/cmd/scsi.c b/cmd/scsi.c index 46171e5..5709718 100644 --- a/cmd/scsi.c +++ b/cmd/scsi.c @@ -37,7 +37,7 @@ static int do_scsi(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) if (strncmp(argv[1], "res", 3) == 0) { printf("\nReset SCSI\n"); scsi_bus_reset(NULL); - ret = scsi_scan(1); + ret = scsi_scan(true); if (ret) return CMD_RET_FAILURE; return ret; @@ -55,7 +55,7 @@ static int do_scsi(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) return 0; } if (strncmp(argv[1], "scan", 4) == 0) { - ret = scsi_scan(1); + ret = scsi_scan(true); if (ret) return CMD_RET_FAILURE; return ret; diff --git a/common/spl/spl_sata.c b/common/spl/spl_sata.c index 5476206..bac11f6 100644 --- a/common/spl/spl_sata.c +++ b/common/spl/spl_sata.c @@ -34,7 +34,7 @@ static int spl_sata_load_image(struct spl_image_info *spl_image, return err; } else { /* try to recognize storage devices immediately */ - scsi_scan(0); + scsi_scan(false); stor_dev = blk_get_devnum_by_type(IF_TYPE_SCSI, 0); if (!stor_dev) return -ENODEV; diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 9232f3a..f3f8d31 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -326,7 +326,7 @@ void scsi_init(void) #endif bootstage_start(BOOTSTAGE_ID_ACCUM_SCSI, "ahci"); scsi_low_level_init(busdevfunc); - scsi_scan(1); + scsi_scan(true); bootstage_accum(BOOTSTAGE_ID_ACCUM_SCSI); } #endif @@ -555,7 +555,7 @@ removable: * to the user if mode = 1 */ #if defined(CONFIG_DM_SCSI) -static int do_scsi_scan_one(struct udevice *dev, int id, int lun, int mode) +static int do_scsi_scan_one(struct udevice *dev, int id, int lun, bool verbose) { int ret; struct udevice *bdev; @@ -594,21 +594,21 @@ static int do_scsi_scan_one(struct udevice *dev, int id, int lun, int mode) memcpy(&bdesc->revision, &bd.revision, sizeof(bd.revision)); part_init(bdesc); - if (mode == 1) { + if (verbose) { printf(" Device %d: ", 0); dev_print(bdesc); } return 0; } -int scsi_scan(int mode) +int scsi_scan(bool verbose) { unsigned char i, lun; struct uclass *uc; struct udevice *dev; /* SCSI controller */ int ret; - if (mode == 1) + if (verbose) printf("scanning bus for devices...\n"); blk_unbind_all(IF_TYPE_SCSI); @@ -630,18 +630,18 @@ int scsi_scan(int mode) for (i = 0; i < plat->max_id; i++) for (lun = 0; lun < plat->max_lun; lun++) - do_scsi_scan_one(dev, i, lun, mode); + do_scsi_scan_one(dev, i, lun, verbose); } return 0; } #else -int scsi_scan(int mode) +int scsi_scan(bool verbose) { unsigned char i, lun; int ret; - if (mode == 1) + if (verbose) printf("scanning bus for devices...\n"); for (i = 0; i < CONFIG_SYS_SCSI_MAX_DEVICE; i++) scsi_init_dev_desc(&scsi_dev_desc[i], i); @@ -655,10 +655,10 @@ int scsi_scan(int mode) continue; part_init(&scsi_dev_desc[scsi_max_devs]); - if (mode == 1) { + if (verbose) { printf(" Device %d: ", 0); dev_print(&scsi_dev_desc[scsi_max_devs]); - } /* if mode */ + } scsi_max_devs++; } /* next LUN */ } diff --git a/include/scsi.h b/include/scsi.h index af07dbe..20f6932 100644 --- a/include/scsi.h +++ b/include/scsi.h @@ -199,10 +199,12 @@ void scsi_init(void); int scsi_exec(struct udevice *dev, struct scsi_cmd *pccb); int scsi_bus_reset(struct udevice *dev); -/*************************************************************************** - * functions residing inside cmd_scsi.c +/** + * scsi_scan() - Scan all SCSI controllers for available devices + * + * @vebose: true to show information about each device found */ -int scsi_scan(int mode); +int scsi_scan(bool verbose); #define SCSI_IDENTIFY 0xC0 /* not used */ -- cgit v0.10.2 From 4e7490145800ea8da5f67a4fbaa66caab7689ce3 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 14 Jun 2017 21:28:42 -0600 Subject: dm: ahci: Create a local version of two SCSI functions With driver model we need to define implementations of exec() and bus_reset() separately for each SCSI driver. As a first step, create a local version of each function in the AHCI driver and call each from its global version. Signed-off-by: Simon Glass Reviewed-by: Bin Meng diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index c3b5f2a..9c7b043 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -928,7 +928,7 @@ static int ata_scsiop_test_unit_ready(struct ahci_uc_priv *uc_priv, } -int scsi_exec(struct udevice *dev, struct scsi_cmd *pccb) +static int ahci_scsi_exec(struct udevice *dev, struct scsi_cmd *pccb) { struct ahci_uc_priv *uc_priv; #ifdef CONFIG_DM_SCSI @@ -1134,10 +1134,21 @@ static int ata_io_flush(struct ahci_uc_priv *uc_priv, u8 port) return 0; } +static int ahci_scsi_bus_reset(struct udevice *dev) +{ + /* Not implemented */ + + return 0; +} + +int scsi_exec(struct udevice *dev, struct scsi_cmd *pccb) +{ + return ahci_scsi_exec(dev, pccb); +} __weak int scsi_bus_reset(struct udevice *dev) { - /*Not implement*/ + return ahci_scsi_bus_reset(dev); return 0; } -- cgit v0.10.2 From f6ab5a92acc78371fc088075b64bd394d1f0d45f Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 14 Jun 2017 21:28:43 -0600 Subject: dm: scsi: Add operations for SCSI devices The SCSI uclass currently has no operations. It just uses the global SCSI functions. Fix this by adding operations to the only two drivers that use the uclass, and replacing the global functions with those defined locally in the SCSI code. Signed-off-by: Simon Glass Reviewed-by: Bin Meng diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 9c7b043..5a20b97 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1141,6 +1141,12 @@ static int ahci_scsi_bus_reset(struct udevice *dev) return 0; } +#ifdef CONFIG_DM_SCSI +struct scsi_ops scsi_ops = { + .exec = ahci_scsi_exec, + .bus_reset = ahci_scsi_bus_reset, +}; +#else int scsi_exec(struct udevice *dev, struct scsi_cmd *pccb) { return ahci_scsi_exec(dev, pccb); @@ -1152,3 +1158,4 @@ __weak int scsi_bus_reset(struct udevice *dev) return 0; } +#endif diff --git a/drivers/ata/dwc_ahci.c b/drivers/ata/dwc_ahci.c index 4012017..f614798 100644 --- a/drivers/ata/dwc_ahci.c +++ b/drivers/ata/dwc_ahci.c @@ -98,6 +98,7 @@ U_BOOT_DRIVER(dwc_ahci) = { .id = UCLASS_SCSI, .of_match = dwc_ahci_ids, .ofdata_to_platdata = dwc_ahci_ofdata_to_platdata, + .ops = &scsi_ops, .probe = dwc_ahci_probe, .priv_auto_alloc_size = sizeof(struct dwc_ahci_priv), .flags = DM_FLAG_ALLOC_PRIV_DMA, diff --git a/drivers/ata/sata_ceva.c b/drivers/ata/sata_ceva.c index 7d61a54..d582e5b 100644 --- a/drivers/ata/sata_ceva.c +++ b/drivers/ata/sata_ceva.c @@ -144,6 +144,7 @@ U_BOOT_DRIVER(ceva_host_blk) = { .name = "ceva_sata", .id = UCLASS_SCSI, .of_match = sata_ceva_ids, + .ops = &scsi_ops, .probe = sata_ceva_probe, .ofdata_to_platdata = sata_ceva_ofdata_to_platdata, }; diff --git a/drivers/scsi/scsi-uclass.c b/drivers/scsi/scsi-uclass.c index 40c5044..31e8999 100644 --- a/drivers/scsi/scsi-uclass.c +++ b/drivers/scsi/scsi-uclass.c @@ -13,6 +13,26 @@ #include #include +int scsi_exec(struct udevice *dev, struct scsi_cmd *pccb) +{ + struct scsi_ops *ops = scsi_get_ops(dev); + + if (!ops->exec) + return -ENOSYS; + + return ops->exec(dev, pccb); +} + +int scsi_bus_reset(struct udevice *dev) +{ + struct scsi_ops *ops = scsi_get_ops(dev); + + if (!ops->bus_reset) + return -ENOSYS; + + return ops->bus_reset(dev); +} + UCLASS_DRIVER(scsi) = { .id = UCLASS_SCSI, .name = "scsi", diff --git a/include/scsi.h b/include/scsi.h index 20f6932..9cdd13c 100644 --- a/include/scsi.h +++ b/include/scsi.h @@ -191,12 +191,25 @@ struct scsi_ops { int (*bus_reset)(struct udevice *dev); }; -#ifndef CONFIG_DM_SCSI -void scsi_low_level_init(int busdevfunc); -void scsi_init(void); -#endif +#define scsi_get_ops(dev) ((struct scsi_ops *)(dev)->driver->ops) + +extern struct scsi_ops scsi_ops; + +/** + * scsi_exec() - execute a command + * + * @dev: SCSI bus + * @cmd: Command to execute + * @return 0 if OK, -ve on error + */ +int scsi_exec(struct udevice *dev, struct scsi_cmd *cmd); -int scsi_exec(struct udevice *dev, struct scsi_cmd *pccb); +/** + * scsi_bus_reset() - reset the bus + * + * @dev: SCSI bus to reset + * @return 0 if OK, -ve on error + */ int scsi_bus_reset(struct udevice *dev); /** @@ -206,6 +219,11 @@ int scsi_bus_reset(struct udevice *dev); */ int scsi_scan(bool verbose); +#ifndef CONFIG_DM_SCSI +void scsi_low_level_init(int busdevfunc); +void scsi_init(void); +#endif + #define SCSI_IDENTIFY 0xC0 /* not used */ /* Hardware errors */ -- cgit v0.10.2 From f6580ef39b332387f84334d238320ce99115af67 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 14 Jun 2017 21:28:44 -0600 Subject: dm: scsi: Adjust return value of scsi_exec() Change this function to return an error number instead of true/false. This allows us to return a proper error number. Signed-off-by: Simon Glass Reviewed-by: Bin Meng diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 5a20b97..3528a1f 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -960,14 +960,14 @@ static int ahci_scsi_exec(struct udevice *dev, struct scsi_cmd *pccb) break; default: printf("Unsupport SCSI command 0x%02x\n", pccb->cmd[0]); - return false; + return -ENOTSUPP; } if (ret) { debug("SCSI command 0x%02x ret errno %d\n", pccb->cmd[0], ret); - return false; + return ret; } - return true; + return 0; } diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index f3f8d31..80c5ce6 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -368,7 +368,7 @@ static int scsi_read_capacity(struct udevice *dev, struct scsi_cmd *pccb, pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ pccb->datalen = 8; - if (scsi_exec(dev, pccb) != true) + if (scsi_exec(dev, pccb)) return 1; *capacity = ((lbaint_t)pccb->pdata[0] << 24) | @@ -393,7 +393,7 @@ static int scsi_read_capacity(struct udevice *dev, struct scsi_cmd *pccb, pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ pccb->datalen = 16; - if (scsi_exec(dev, pccb) != true) + if (scsi_exec(dev, pccb)) return 1; *capacity = ((uint64_t)pccb->pdata[0] << 56) | @@ -499,7 +499,7 @@ static int scsi_detect_dev(struct udevice *dev, int target, int lun, pccb->pdata = (unsigned char *)&tempbuff; pccb->datalen = 512; scsi_setup_inquiry(pccb); - if (scsi_exec(dev, pccb) != true) { + if (scsi_exec(dev, pccb)) { if (pccb->contr_stat == SCSI_SEL_TIME_OUT) { /* * selection timeout => assuming no @@ -530,7 +530,7 @@ static int scsi_detect_dev(struct udevice *dev, int target, int lun, pccb->datalen = 0; scsi_setup_test_unit_ready(pccb); - if (scsi_exec(dev, pccb) != true) { + if (scsi_exec(dev, pccb)) { if (dev_desc->removable) { dev_desc->type = perq; goto removable; -- cgit v0.10.2 From 5c56176318c8a602fa78813ac273f16a10278a2d Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 14 Jun 2017 21:28:45 -0600 Subject: dm: scsi: Split out the bus scanning code Split out the code that scans a single SCSI bus into a separate function. This will allow it to be used from driver model. Signed-off-by: Simon Glass Reviewed-by: Bin Meng diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 80c5ce6..2b87548 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -601,9 +601,30 @@ static int do_scsi_scan_one(struct udevice *dev, int id, int lun, bool verbose) return 0; } +int scsi_scan_dev(struct udevice *dev, bool verbose) +{ + struct scsi_platdata *uc_plat; /* scsi controller platdata */ + int ret; + int i; + int lun; + + /* probe SCSI controller driver */ + ret = device_probe(dev); + if (ret) + return ret; + + /* Get controller platdata */ + uc_plat = dev_get_uclass_platdata(dev); + + for (i = 0; i < uc_plat->max_id; i++) + for (lun = 0; lun < uc_plat->max_lun; lun++) + do_scsi_scan_one(dev, i, lun, verbose); + + return 0; +} + int scsi_scan(bool verbose) { - unsigned char i, lun; struct uclass *uc; struct udevice *dev; /* SCSI controller */ int ret; @@ -618,19 +639,9 @@ int scsi_scan(bool verbose) return ret; uclass_foreach_dev(dev, uc) { - struct scsi_platdata *plat; /* scsi controller platdata */ - - /* probe SCSI controller driver */ - ret = device_probe(dev); + ret = scsi_scan_dev(dev, verbose); if (ret) return ret; - - /* Get controller platdata */ - plat = dev_get_uclass_platdata(dev); - - for (i = 0; i < plat->max_id; i++) - for (lun = 0; lun < plat->max_lun; lun++) - do_scsi_scan_one(dev, i, lun, verbose); } return 0; diff --git a/include/scsi.h b/include/scsi.h index 9cdd13c..7173912 100644 --- a/include/scsi.h +++ b/include/scsi.h @@ -219,6 +219,14 @@ int scsi_bus_reset(struct udevice *dev); */ int scsi_scan(bool verbose); +/** + * scsi_scan_dev() - scan a SCSI bus and create devices + * + * @dev: SCSI bus + * @verbose: true to show information about each device found + */ +int scsi_scan_dev(struct udevice *dev, bool verbose); + #ifndef CONFIG_DM_SCSI void scsi_low_level_init(int busdevfunc); void scsi_init(void); -- cgit v0.10.2 From 681357ffd9fe4528d020a878ef6ee61f519d8d85 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 14 Jun 2017 21:28:46 -0600 Subject: dm: ahci: Add a driver for SCSI on AHCI Some AHCI drivers use SCSI under the hood. Rather than making the AHCI driver be in the SCSI uclass it makes sense to have the AHCI device create a SCSI device as a child. That way we can handle any AHCI-specific operations rather than trying to pretend tha the device is just SCSI. To handle this we need to provide a way for AHCI drivers to bind a SCSI device as its child, and probe it. Add functions for this. Signed-off-by: Simon Glass Reviewed-by: Bin Meng diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 3528a1f..6da412d 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -19,10 +19,13 @@ #include #include #include +#include #include #include #include #include +#include +#include static int ata_io_flush(struct ahci_uc_priv *uc_priv, u8 port); @@ -1142,10 +1145,64 @@ static int ahci_scsi_bus_reset(struct udevice *dev) } #ifdef CONFIG_DM_SCSI +int ahci_bind_scsi(struct udevice *ahci_dev, struct udevice **devp) +{ + struct udevice *dev; + int ret; + + ret = device_bind_driver(ahci_dev, "ahci_scsi", "ahci_scsi", &dev); + if (ret) + return ret; + *devp = dev; + + return 0; +} + +int ahci_probe_scsi(struct udevice *ahci_dev) +{ +#ifdef CONFIG_SCSI_AHCI_PLAT + return -ENOSYS; /* TODO(sjg@chromium.org): Support non-PCI AHCI */ +#else + struct ahci_uc_priv *uc_priv; + struct scsi_platdata *uc_plat; + struct udevice *dev; + int ret; + + device_find_first_child(ahci_dev, &dev); + if (!dev) + return -ENODEV; + uc_plat = dev_get_uclass_platdata(dev); + uc_plat->base = (ulong)dm_pci_map_bar(ahci_dev, PCI_BASE_ADDRESS_5, + PCI_REGION_MEM); + uc_plat->max_lun = 1; + uc_plat->max_id = 2; + uc_priv = dev_get_uclass_priv(dev); + ret = ahci_init_one(uc_priv, dev); + if (ret) + return ret; + ret = ahci_start_ports(uc_priv); + if (ret) + return ret; + + debug("Scanning %s\n", dev->name); + ret = scsi_scan_dev(dev, true); + if (ret) + return ret; +#endif + + return 0; +} + struct scsi_ops scsi_ops = { .exec = ahci_scsi_exec, .bus_reset = ahci_scsi_bus_reset, }; + +U_BOOT_DRIVER(ahci_scsi) = { + .name = "ahci_scsi", + .id = UCLASS_SCSI, + .ops = &scsi_ops, +}; #else int scsi_exec(struct udevice *dev, struct scsi_cmd *pccb) { diff --git a/include/ahci.h b/include/ahci.h index 3d61ad1..818f344 100644 --- a/include/ahci.h +++ b/include/ahci.h @@ -200,4 +200,26 @@ int achi_start_ports_dm(struct udevice *dev); */ int ahci_init_dm(struct udevice *dev, void __iomem *base); +/** + * ahci_bind_scsi() - bind a new SCSI bus as a child + * + * Note that the SCSI bus device will itself bind block devices + * + * @ahci_dev: AHCI parent device + * @devp: Returns new SCSI bus device + * @return 0 if OK, -ve on error + */ +int ahci_bind_scsi(struct udevice *ahci_dev, struct udevice **devp); + +/** + * ahci_probe_scsi() - probe and scan the attached SCSI bus + * + * Note that the SCSI device will itself bind block devices for any storage + * devices it finds. + * + * @ahci_dev: AHCI parent device + * @return 0 if OK, -ve on error + */ +int ahci_probe_scsi(struct udevice *ahci_dev); + #endif -- cgit v0.10.2 From 7337fcd8c0aeee0a90eb2e986bde5eb7177b8552 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 14 Jun 2017 21:28:47 -0600 Subject: dm: scsi: Drop scsi_init() when driver model is used This function should not be used with driver model. Update the code to reflect this. Signed-off-by: Simon Glass Reviewed-by: Bin Meng diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 2b87548..7ec7ecc 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -29,7 +29,8 @@ # endif #endif -#if defined(CONFIG_PCI) && !defined(CONFIG_SCSI_AHCI_PLAT) +#if defined(CONFIG_PCI) && !defined(CONFIG_SCSI_AHCI_PLAT) && \ + !defined(CONFIG_DM_SCSI) const struct pci_device_id scsi_device_list[] = { SCSI_DEV_LIST }; #endif static struct scsi_cmd tempccb; /* temporary scsi command buffer */ @@ -274,7 +275,8 @@ static ulong scsi_write(struct blk_desc *block_dev, lbaint_t blknr, return blkcnt; } -#if defined(CONFIG_PCI) && !defined(CONFIG_SCSI_AHCI_PLAT) +#if defined(CONFIG_PCI) && !defined(CONFIG_SCSI_AHCI_PLAT) && \ + !defined(CONFIG_DM_SCSI) void scsi_init(void) { int busdevfunc = -1; -- cgit v0.10.2 From 32e9ec1f8812ffe5874a2e3a0a1b8fe85c489ab8 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 14 Jun 2017 21:28:48 -0600 Subject: x86: Move link to use driver model for SCSI As a demonstration of how to use SCSI with driver model, move link over to use this. This patch needs more work, but illustrates the concept. Signed-off-by: Simon Glass Reviewed-by: Bin Meng diff --git a/arch/x86/cpu/ivybridge/sata.c b/arch/x86/cpu/ivybridge/sata.c index 0f5e190..462b7c0 100644 --- a/arch/x86/cpu/ivybridge/sata.c +++ b/arch/x86/cpu/ivybridge/sata.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -208,6 +209,20 @@ static void bd82x6x_sata_enable(struct udevice *dev) dm_pci_write_config16(dev, 0x90, map); } +static int bd82x6x_sata_bind(struct udevice *dev) +{ + struct udevice *scsi_dev; + int ret; + + if (gd->flags & GD_FLG_RELOC) { + ret = ahci_bind_scsi(dev, &scsi_dev); + if (ret) + return ret; + } + + return 0; +} + static int bd82x6x_sata_probe(struct udevice *dev) { struct udevice *pch; @@ -219,8 +234,12 @@ static int bd82x6x_sata_probe(struct udevice *dev) if (!(gd->flags & GD_FLG_RELOC)) bd82x6x_sata_enable(dev); - else + else { bd82x6x_sata_init(dev, pch); + ret = ahci_probe_scsi(dev); + if (ret) + return ret; + } return 0; } @@ -234,5 +253,6 @@ U_BOOT_DRIVER(ahci_ivybridge_drv) = { .name = "ahci_ivybridge", .id = UCLASS_AHCI, .of_match = bd82x6x_ahci_ids, + .bind = bd82x6x_sata_bind, .probe = bd82x6x_sata_probe, }; diff --git a/configs/chromebook_link64_defconfig b/configs/chromebook_link64_defconfig index 8fb4712..557919c 100644 --- a/configs/chromebook_link64_defconfig +++ b/configs/chromebook_link64_defconfig @@ -58,6 +58,8 @@ CONFIG_SPL_REGMAP=y CONFIG_SYSCON=y CONFIG_SPL_SYSCON=y CONFIG_SCSI=y +CONFIG_DM_SCSI=y +CONFIG_BLK=y CONFIG_CPU=y CONFIG_DM_I2C=y CONFIG_SYS_I2C_INTEL=y diff --git a/configs/chromebook_link_defconfig b/configs/chromebook_link_defconfig index 9c0f860..3105fed 100644 --- a/configs/chromebook_link_defconfig +++ b/configs/chromebook_link_defconfig @@ -41,6 +41,8 @@ CONFIG_OF_CONTROL=y CONFIG_REGMAP=y CONFIG_SYSCON=y CONFIG_SCSI=y +CONFIG_DM_SCSI=y +CONFIG_BLK=y CONFIG_CPU=y CONFIG_DM_I2C=y CONFIG_SYS_I2C_INTEL=y diff --git a/configs/chromebox_panther_defconfig b/configs/chromebox_panther_defconfig index 51a934f..30d4019 100644 --- a/configs/chromebox_panther_defconfig +++ b/configs/chromebox_panther_defconfig @@ -37,6 +37,8 @@ CONFIG_OF_CONTROL=y CONFIG_REGMAP=y CONFIG_SYSCON=y CONFIG_SCSI=y +CONFIG_DM_SCSI=y +CONFIG_BLK=y CONFIG_CROS_EC=y CONFIG_CROS_EC_LPC=y CONFIG_SPI_FLASH=y -- cgit v0.10.2 From 6c519f2dc4a59a9d81f087d990e24d1e6444c86d Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 16 Jun 2017 12:51:42 -0600 Subject: display_options: Refactor to allow obtaining the banner Move the display options code into a separate function so that the U-Boot banner can be obtained from other code. Adjust the 'version' command to use it. Signed-off-by: Simon Glass Reviewed-by: Bin Meng Tested-by: Bin Meng Tested-by: Stephen Warren diff --git a/cmd/version.c b/cmd/version.c index 1be0667..15aab5d 100644 --- a/cmd/version.c +++ b/cmd/version.c @@ -17,7 +17,9 @@ const char __weak version_string[] = U_BOOT_VERSION_STRING; static int do_version(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { - printf("\n%s\n", version_string); + char buf[DISPLAY_OPTIONS_BANNER_LENGTH]; + + printf(display_options_get_banner(false, buf, sizeof(buf))); #ifdef CC_VERSION_STRING puts(CC_VERSION_STRING "\n"); #endif diff --git a/include/display_options.h b/include/display_options.h index ac44c45..d9c8f6d 100644 --- a/include/display_options.h +++ b/include/display_options.h @@ -56,4 +56,23 @@ int print_buffer(ulong addr, const void *data, uint width, uint count, */ int display_options(void); +/* Suggested length of the buffer to pass to display_options_get_banner() */ +#define DISPLAY_OPTIONS_BANNER_LENGTH 200 + +/** + * display_options_get_banner() - Get the U-Boot banner as a string + * + * This returns the U-Boot banner string + * + * @newlines: true to include two newlines at the start + * @buf: place to put string + * @size: Size of buf (string is truncated to fit) + * @return buf + */ +char *display_options_get_banner(bool newlines, char *buf, int size); + +/* This function is used for testing only */ +char *display_options_get_banner_priv(bool newlines, const char *build_tag, + char *buf, int size); + #endif diff --git a/lib/display_options.c b/lib/display_options.c index 29343fc..4ea27ca 100644 --- a/lib/display_options.c +++ b/lib/display_options.c @@ -13,13 +13,39 @@ #include #include -int display_options (void) +char *display_options_get_banner_priv(bool newlines, const char *build_tag, + char *buf, int size) { -#if defined(BUILD_TAG) - printf ("\n\n%s, Build: %s\n\n", version_string, BUILD_TAG); -#else - printf ("\n\n%s\n\n", version_string); + int len; + + len = snprintf(buf, size, "%s%s", newlines ? "\n\n" : "", + version_string); + if (build_tag && len < size) + len += snprintf(buf + len, size - len, ", Build: %s", + build_tag); + if (len > size - 3) + len = size - 3; + strcpy(buf + len, "\n\n"); + + return buf; +} + +#ifndef BUILD_TAG +#define BUILD_TAG NULL #endif + +char *display_options_get_banner(bool newlines, char *buf, int size) +{ + return display_options_get_banner_priv(newlines, BUILD_TAG, buf, size); +} + +int display_options(void) +{ + char buf[DISPLAY_OPTIONS_BANNER_LENGTH]; + + display_options_get_banner(true, buf, sizeof(buf)); + printf("%s", buf); + return 0; } -- cgit v0.10.2 From b0895384bebb6a4a2ea5bbdb0941b771b5875012 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 15 Jun 2017 21:37:50 -0600 Subject: Allow displaying the U-Boot banner on a video display At present the U-Boot banner is only displayed on the serial console. If this is not visible to the user, the banner does not show. Some devices have a video display which can usefully display this information. Add a banner which is printed after relocation only on non-serial devices if CONFIG_DISPLAY_BOARDINFO_LATE is defined. Signed-off-by: Simon Glass Reviewed-by: Bin Meng Tested-by: Bin Meng Tested-by: Stephen Warren diff --git a/common/board_r.c b/common/board_r.c index 3341a52..ecca1ed 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -829,6 +829,7 @@ static init_fnc_t init_sequence_r[] = { #endif console_init_r, /* fully init console as a device */ #ifdef CONFIG_DISPLAY_BOARDINFO_LATE + console_announce_r, show_board_info, #endif #ifdef CONFIG_ARCH_MISC_INIT diff --git a/common/console.c b/common/console.c index 1232808..60e7a94 100644 --- a/common/console.c +++ b/common/console.c @@ -202,7 +202,6 @@ static void console_putc(int file, const char c) } } -#if CONFIG_IS_ENABLED(PRE_CONSOLE_BUFFER) static void console_puts_noserial(int file, const char *s) { int i; @@ -214,7 +213,6 @@ static void console_puts_noserial(int file, const char *s) dev->puts(dev, s); } } -#endif static void console_puts(int file, const char *s) { @@ -248,13 +246,11 @@ static inline void console_putc(int file, const char c) stdio_devices[file]->putc(stdio_devices[file], c); } -#if CONFIG_IS_ENABLED(PRE_CONSOLE_BUFFER) static inline void console_puts_noserial(int file, const char *s) { if (strcmp(stdio_devices[file]->name, "serial") != 0) stdio_devices[file]->puts(stdio_devices[file], s); } -#endif static inline void console_puts(int file, const char *s) { @@ -699,6 +695,19 @@ static void console_update_silent(void) #endif } +int console_announce_r(void) +{ +#if !CONFIG_IS_ENABLED(PRE_CONSOLE_BUFFER) + char buf[DISPLAY_OPTIONS_BANNER_LENGTH]; + + display_options_get_banner(false, buf, sizeof(buf)); + + console_puts_noserial(stdout, buf); +#endif + + return 0; +} + /* Called before relocation - use serial functions */ int console_init_f(void) { diff --git a/include/console.h b/include/console.h index 3d37f6a..cea29ed 100644 --- a/include/console.h +++ b/include/console.h @@ -42,6 +42,18 @@ void console_record_reset(void); */ void console_record_reset_enable(void); +/** + * console_announce_r() - print a U-Boot console on non-serial consoles + * + * When U-Boot starts up with a display it generally does not announce itself + * on the display. The banner is instead emitted on the UART before relocation. + * This function prints a banner on devices which (we assume) did not receive + * it before relocation. + * + * @return 0 (meaning no errors) + */ +int console_announce_r(void); + /* * CONSOLE multiplexing. */ -- cgit v0.10.2 From e5a9d27fdbcf59760a7ff69597584229e24ca456 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 15 Jun 2017 21:37:51 -0600 Subject: test: Add a test for snprintf() and the banner/version Add a simple test to make sure that these functions obey the buffer size passed into them. Signed-off-by: Simon Glass Reviewed-by: Bin Meng Tested-by: Stephen Warren diff --git a/test/Makefile b/test/Makefile index 0f5de57..6305afb 100644 --- a/test/Makefile +++ b/test/Makefile @@ -8,4 +8,5 @@ obj-$(CONFIG_UNIT_TEST) += cmd_ut.o obj-$(CONFIG_UNIT_TEST) += ut.o obj-$(CONFIG_SANDBOX) += command_ut.o obj-$(CONFIG_SANDBOX) += compression.o +obj-$(CONFIG_SANDBOX) += print_ut.o obj-$(CONFIG_UT_TIME) += time_ut.o diff --git a/test/print_ut.c b/test/print_ut.c new file mode 100644 index 0000000..baad289 --- /dev/null +++ b/test/print_ut.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2012, The Chromium Authors + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#define DEBUG + +#include +#include +#include + +#define FAKE_BUILD_TAG "jenkins-u-boot-denx_uboot_dm-master-build-aarch64" \ + "and a lot more text to come" + +static int do_ut_print(cmd_tbl_t *cmdtp, int flag, int argc, + char *const argv[]) +{ + char big_str[400]; + int big_str_len; + char str[10], *s; + int len; + + printf("%s: Testing print\n", __func__); + + snprintf(str, sizeof(str), "testing"); + assert(!strcmp("testing", str)); + + snprintf(str, sizeof(str), "testing but too long"); + assert(!strcmp("testing b", str)); + + snprintf(str, 1, "testing none"); + assert(!strcmp("", str)); + + *str = 'x'; + snprintf(str, 0, "testing none"); + assert(*str == 'x'); + + /* Test the banner function */ + s = display_options_get_banner(true, str, sizeof(str)); + assert(s == str); + assert(!strcmp("\n\nU-Boo\n\n", s)); + + s = display_options_get_banner(true, str, 1); + assert(s == str); + assert(!strcmp("", s)); + + s = display_options_get_banner(true, str, 2); + assert(s == str); + assert(!strcmp("\n", s)); + + s = display_options_get_banner(false, str, sizeof(str)); + assert(s == str); + assert(!strcmp("U-Boot \n\n", s)); + + /* Give it enough space for some of the version */ + big_str_len = strlen(version_string) - 5; + s = display_options_get_banner_priv(false, FAKE_BUILD_TAG, big_str, + big_str_len); + assert(s == big_str); + assert(!strncmp(version_string, s, big_str_len - 3)); + assert(!strcmp("\n\n", s + big_str_len - 3)); + + /* Give it enough space for the version and some of the build tag */ + big_str_len = strlen(version_string) + 9 + 20; + s = display_options_get_banner_priv(false, FAKE_BUILD_TAG, big_str, + big_str_len); + assert(s == big_str); + len = strlen(version_string); + assert(!strncmp(version_string, s, len)); + assert(!strncmp(", Build: ", s + len, 9)); + assert(!strncmp(FAKE_BUILD_TAG, s + 9 + len, 12)); + assert(!strcmp("\n\n", s + big_str_len - 3)); + + printf("%s: Everything went swimmingly\n", __func__); + return 0; +} + +U_BOOT_CMD( + ut_print, 1, 1, do_ut_print, + "Very basic test of printf(), etc.", + "" +); -- cgit v0.10.2 From 4e6bafa56807b7ea4ebfb2eebbcf2eae674866e0 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 15 Jun 2017 21:37:52 -0600 Subject: console: Use map_sysmem() for the pre-relocation console At present this feature casts the address to a pointer. Use the map_sysmem() function so that it will work correctly on sandbox. Signed-off-by: Simon Glass Reviewed-by: Bin Meng Tested-by: Bin Meng Tested-by: Stephen Warren diff --git a/common/console.c b/common/console.c index 60e7a94..762d5f2 100644 --- a/common/console.c +++ b/common/console.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -416,9 +417,13 @@ int tstc(void) static void pre_console_putc(const char c) { - char *buffer = (char *)CONFIG_PRE_CON_BUF_ADDR; + char *buffer; + + buffer = map_sysmem(CONFIG_PRE_CON_BUF_ADDR, CONFIG_PRE_CON_BUF_SZ); buffer[CIRC_BUF_IDX(gd->precon_buf_idx++)] = c; + + unmap_sysmem(buffer); } static void pre_console_puts(const char *s) @@ -430,14 +435,16 @@ static void pre_console_puts(const char *s) static void print_pre_console_buffer(int flushpoint) { unsigned long in = 0, out = 0; - char *buf_in = (char *)CONFIG_PRE_CON_BUF_ADDR; char buf_out[CONFIG_PRE_CON_BUF_SZ + 1]; + char *buf_in; + buf_in = map_sysmem(CONFIG_PRE_CON_BUF_ADDR, CONFIG_PRE_CON_BUF_SZ); if (gd->precon_buf_idx > CONFIG_PRE_CON_BUF_SZ) in = gd->precon_buf_idx - CONFIG_PRE_CON_BUF_SZ; while (in < gd->precon_buf_idx) buf_out[out++] = buf_in[CIRC_BUF_IDX(in++)]; + unmap_sysmem(buf_in); buf_out[out] = 0; -- cgit v0.10.2 From d63b5b4fbb401e2ffbce5083c7f3d9f8045651ba Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 15 Jun 2017 21:37:53 -0600 Subject: sandbox: Enable more console options Enable the pre-console buffer, displaying the model and post-relocation console announce on sandbox. Also add a model name to the device tree. This allows testing of these features. Signed-off-by: Simon Glass Reviewed-by: Bin Meng Tested-by: Stephen Warren diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index 40f423d..0aba6c9 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -5,6 +5,7 @@ / { #address-cells = <1>; #size-cells = <1>; + model = "sandbox"; aliases { eth5 = "/eth@90000000"; diff --git a/common/Kconfig b/common/Kconfig index 086b676..361346b 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -488,7 +488,7 @@ config DISPLAY_CPUINFO config DISPLAY_BOARDINFO bool "Display information about the board during start up" - default y if ARM || M68K || MIPS || PPC || XTENSA + default y if ARM || M68K || MIPS || PPC || SANDBOX || XTENSA help Display information about the board that U-Boot is running on when U-Boot starts up. The board function checkboard() is called diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 6a6e774..7a1b9ef 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -14,6 +14,8 @@ CONFIG_BOOTSTAGE_STASH_SIZE=0x4096 CONFIG_CONSOLE_RECORD=y CONFIG_CONSOLE_RECORD_OUT_SIZE=0x1000 CONFIG_SILENT_CONSOLE=y +CONFIG_PRE_CONSOLE_BUFFER=y +CONFIG_PRE_CON_BUF_ADDR=0 CONFIG_CMD_CPU=y CONFIG_CMD_LICENSE=y CONFIG_CMD_BOOTZ=y diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index 9276cf9..1e8404c 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -41,6 +41,7 @@ #define CONFIG_SYS_LONGHELP /* #undef to save memory */ #define CONFIG_SYS_CBSIZE 1024 /* Console I/O Buffer Size */ +#define CONFIG_DISPLAY_BOARDINFO_LATE /* Print Buffer Size */ #define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE + sizeof(CONFIG_SYS_PROMPT) + 16) -- cgit v0.10.2 From d8c6fb8cedbc35eee27730a7fa544e499b3c81cc Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 15 Jun 2017 21:37:54 -0600 Subject: sandbox: Drop special case console code for sandbox At present sandbox has a special case where it directly calls os_putc() when it does not have a console yet. Now that we have the pre-console buffer enabled we can drop this. Any early characters will be buffered and output later. Signed-off-by: Simon Glass Reviewed-by: Bin Meng Tested-by: Stephen Warren diff --git a/common/console.c b/common/console.c index 762d5f2..c6156f3 100644 --- a/common/console.c +++ b/common/console.c @@ -465,13 +465,6 @@ static inline void print_pre_console_buffer(int flushpoint) {} void putc(const char c) { -#ifdef CONFIG_SANDBOX - /* sandbox can send characters to stdout before it has a console */ - if (!gd || !(gd->flags & GD_FLG_SERIAL_READY)) { - os_putc(c); - return; - } -#endif #ifdef CONFIG_DEBUG_UART /* if we don't have a console yet, use the debug UART */ if (!gd || !(gd->flags & GD_FLG_SERIAL_READY)) { @@ -508,12 +501,6 @@ void putc(const char c) void puts(const char *s) { -#ifdef CONFIG_SANDBOX - if (!gd || !(gd->flags & GD_FLG_SERIAL_READY)) { - os_puts(s); - return; - } -#endif #ifdef CONFIG_DEBUG_UART if (!gd || !(gd->flags & GD_FLG_SERIAL_READY)) { while (*s) { -- cgit v0.10.2 From 2ddd85dc34c4b5fdefe363b735d2eea8d9d87c6c Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 15 Jun 2017 21:39:31 -0600 Subject: moveconfig: Allow piping in 'git show --stat' output It is useful to be able to process only a subset of boards to save time. Often that subset is defined by the defconfig files in a git commit. This change allows things like: # Build the database ./tools.moveconfig.py -b # Find some implying configs ./tools/moveconfig.py -i CONFIG_X # Add some 'imply' statements to Kconfig files ./tools/moveconfig.py -i CONFIG_X -a CONFIG_A,CONFIG_B # Reprocess the defconfig files to see if we can drop some changes git show --stat | ./tools/moveconfig.py -s -d - # Update the commit, with fewer defconfig changes gii commit -au Where the commit contains defconfig files, this will reprocess them to take account of the imply statements that you added. Signed-off-by: Simon Glass diff --git a/tools/moveconfig.py b/tools/moveconfig.py index 6fa394a..6921135 100755 --- a/tools/moveconfig.py +++ b/tools/moveconfig.py @@ -404,6 +404,8 @@ def get_matched_defconfigs(defconfigs_file): line = line.strip() if not line: continue # skip blank lines silently + if ' ' in line: + line = line.split(' ')[0] # handle 'git log' input matched = get_matched_defconfig(line) if not matched: print >> sys.stderr, "warning: %s:%d: no defconfig matched '%s'" % \ -- cgit v0.10.2 From 9b2a2e87d2404dad62e4c2f350fd07324bfdadc3 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 15 Jun 2017 21:39:32 -0600 Subject: moveconfig: Allow control of which implying configs are shown Sometimes it is useful to display CONFIG_TARGET or CONFIG_CMD configs. Add an option to control this. Also we generally ignore implying configs which affect fewer than 5 boards. But sometimes it is useful to show those those, so add an option that reduces the minimum to two. ERRATUM configs are never useful for implying things, so ignore those. Signed-off-by: Simon Glass diff --git a/tools/moveconfig.py b/tools/moveconfig.py index 6921135..e765acc 100755 --- a/tools/moveconfig.py +++ b/tools/moveconfig.py @@ -1464,7 +1464,15 @@ def move_config(configs, options, db_queue): slots.show_failed_boards() slots.show_suspicious_boards() -def imply_config(config_list, find_superset=False): +(IMPLY_MIN_2, IMPLY_TARGET, IMPLY_CMD) = (1, 2, 4) + +IMPLY_FLAGS = { + 'min2': [IMPLY_MIN_2, 'Show options which imply >2 boards (normally >5)'], + 'target': [IMPLY_TARGET, 'Allow CONFIG_TARGET_... options to imply'], + 'cmd': [IMPLY_CMD, 'Allow CONFIG_CMD_... to imply'], +}; + +def do_imply_config(config_list, imply_flags, find_superset=False): """Find CONFIG options which imply those in the list Some CONFIG options can be implied by others and this can help to reduce @@ -1489,6 +1497,8 @@ def imply_config(config_list, find_superset=False): Params: config_list: List of CONFIG options to check (each a string) + imply_flags: Flags which control which implying configs are allowed + (IMPLY_...) find_superset: True to look for configs which are a superset of those already found. So for example if CONFIG_EXYNOS5 implies an option, but CONFIG_EXYNOS covers a larger set of defconfigs and also @@ -1549,8 +1559,14 @@ def imply_config(config_list, find_superset=False): # Look at every possible config, except the target one for imply_config in rest_configs: - if 'CONFIG_TARGET' in imply_config: + if 'ERRATUM' in imply_config: continue + if not (imply_flags & IMPLY_CMD): + if 'CONFIG_CMD' in imply_config: + continue + if not (imply_flags & IMPLY_TARGET): + if 'CONFIG_TARGET' in imply_config: + continue # Find set of defconfigs that have this config imply_defconfig = defconfig_db[imply_config] @@ -1597,7 +1613,7 @@ def imply_config(config_list, find_superset=False): num_common = len(imply_configs[config]) # Don't bother if there are less than 5 defconfigs affected. - if num_common < 5: + if num_common < (2 if imply_flags & IMPLY_MIN_2 else 5): continue missing = defconfigs - imply_configs[config] missing_str = ', '.join(missing) if missing else 'all' @@ -1626,6 +1642,8 @@ def main(): "or '-' to read from stdin") parser.add_option('-i', '--imply', action='store_true', default=False, help='find options which imply others') + parser.add_option('-I', '--imply-flags', type='string', default='', + help="control the -i option ('help' for help") parser.add_option('-n', '--dry-run', action='store_true', default=False, help='perform a trial run (show log with no changes)') parser.add_option('-e', '--exit-on-error', action='store_true', @@ -1662,7 +1680,17 @@ def main(): check_top_directory() if options.imply: - imply_config(configs) + imply_flags = 0 + for flag in options.imply_flags.split(): + if flag == 'help' or flag not in IMPLY_FLAGS: + print "Imply flags: (separate with ',')" + for name, info in IMPLY_FLAGS.iteritems(): + print ' %-15s: %s' % (name, info[1]) + parser.print_usage() + sys.exit(1) + imply_flags |= IMPLY_FLAGS[flag][0] + + do_imply_config(configs, imply_flags) return config_db = {} -- cgit v0.10.2 From cb008830aa10214c5e924d8fe15deaeca190d71a Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 15 Jun 2017 21:39:33 -0600 Subject: moveconfig: Allow automatic location and adding of 'imply' By using a Kconfig parser we can find the location of each option in the Kconfig tree. Using the information from the database we can then automatically add an 'imply' option into the right place if requested by the user. Add a -a option to support adding 'imply' options. Display the location of any existing 'imply' option so that progress can be examined. Add a -A option to hide any existing 'imply' options so that already-completed additions need not be considered further. Also add documentation for this feature. Signed-off-by: Simon Glass diff --git a/tools/moveconfig.py b/tools/moveconfig.py index e765acc..eb4927f 100755 --- a/tools/moveconfig.py +++ b/tools/moveconfig.py @@ -194,6 +194,48 @@ CMD_EEPROM. Using this search you can reduce the size of moveconfig patches. +You can automatically add 'imply' statements in the Kconfig with the -a +option: + + ./tools/moveconfig.py -s -i CONFIG_SCSI \ + -a CONFIG_ARCH_LS1021A,CONFIG_ARCH_LS1043A + +This will add 'imply SCSI' to the two CONFIG options mentioned, assuming that +the database indicates that they do actually imply CONFIG_SCSI and do not +already have an 'imply SCSI'. + +The output shows where the imply is added: + + 18 : CONFIG_ARCH_LS1021A arch/arm/cpu/armv7/ls102xa/Kconfig:1 + 13 : CONFIG_ARCH_LS1043A arch/arm/cpu/armv8/fsl-layerscape/Kconfig:11 + 12 : CONFIG_ARCH_LS1046A arch/arm/cpu/armv8/fsl-layerscape/Kconfig:31 + +The first number is the number of boards which can avoid having a special +CONFIG_SCSI option in their defconfig file if this 'imply' is added. +The location at the right is the Kconfig file and line number where the config +appears. For example, adding 'imply CONFIG_SCSI' to the 'config ARCH_LS1021A' +in arch/arm/cpu/armv7/ls102xa/Kconfig at line 1 will help 18 boards to reduce +the size of their defconfig files. + +If you want to add an 'imply' to every imply config in the list, you can use + + ./tools/moveconfig.py -s -i CONFIG_SCSI -a all + +To control which ones are displayed, use -I where list is a list of +options (use '-I help' to see possible options and their meaning). + +To skip showing you options that already have an 'imply' attached, use -A. + +When you have finished adding 'imply' options you can regenerate the +defconfig files for affected boards with something like: + + git show --stat | ./tools/moveconfig.py -s -d - + +This will regenerate only those defconfigs changed in the current commit. +If you start with (say) 100 defconfigs being changed in the commit, and add +a few 'imply' options as above, then regenerate, hopefully you can reduce the +number of defconfigs changed in the commit. + Available options ----------------- @@ -276,6 +318,9 @@ import tempfile import threading import time +sys.path.append(os.path.join(os.path.dirname(__file__), 'buildman')) +import kconfiglib + SHOW_GNU_MAKE = 'scripts/show-gnu-make' SLEEP_TIME=0.03 @@ -331,6 +376,7 @@ COLOR_WHITE = '1;37' AUTO_CONF_PATH = 'include/config/auto.conf' CONFIG_DATABASE = 'moveconfig.db' +CONFIG_LEN = len('CONFIG_') ### helper functions ### def get_devnull(): @@ -802,6 +848,19 @@ class Progress: print ' %d defconfigs out of %d\r' % (self.current, self.total), sys.stdout.flush() + +class KconfigScanner: + """Kconfig scanner.""" + + def __init__(self): + """Scan all the Kconfig files and create a Config object.""" + # Define environment variables referenced from Kconfig + os.environ['srctree'] = os.getcwd() + os.environ['UBOOTVERSION'] = 'dummy' + os.environ['KCONFIG_OBJDIR'] = '' + self.conf = kconfiglib.Config() + + class KconfigParser: """A parser of .config and include/autoconf.mk.""" @@ -1464,15 +1523,98 @@ def move_config(configs, options, db_queue): slots.show_failed_boards() slots.show_suspicious_boards() -(IMPLY_MIN_2, IMPLY_TARGET, IMPLY_CMD) = (1, 2, 4) +def find_kconfig_rules(kconf, config, imply_config): + """Check whether a config has a 'select' or 'imply' keyword + + Args: + kconf: Kconfig.Config object + config: Name of config to check (without CONFIG_ prefix) + imply_config: Implying config (without CONFIG_ prefix) which may or + may not have an 'imply' for 'config') + + Returns: + Symbol object for 'config' if found, else None + """ + sym = kconf.get_symbol(imply_config) + if sym: + for sel in sym.get_selected_symbols(): + if sel.get_name() == config: + return sym + return None + +def check_imply_rule(kconf, config, imply_config): + """Check if we can add an 'imply' option + + This finds imply_config in the Kconfig and looks to see if it is possible + to add an 'imply' for 'config' to that part of the Kconfig. + + Args: + kconf: Kconfig.Config object + config: Name of config to check (without CONFIG_ prefix) + imply_config: Implying config (without CONFIG_ prefix) which may or + may not have an 'imply' for 'config') + + Returns: + tuple: + filename of Kconfig file containing imply_config, or None if none + line number within the Kconfig file, or 0 if none + message indicating the result + """ + sym = kconf.get_symbol(imply_config) + if not sym: + return 'cannot find sym' + locs = sym.get_def_locations() + if len(locs) != 1: + return '%d locations' % len(locs) + fname, linenum = locs[0] + cwd = os.getcwd() + if cwd and fname.startswith(cwd): + fname = fname[len(cwd) + 1:] + file_line = ' at %s:%d' % (fname, linenum) + with open(fname) as fd: + data = fd.read().splitlines() + if data[linenum - 1] != 'config %s' % imply_config: + return None, 0, 'bad sym format %s%s' % (data[linenum], file_line) + return fname, linenum, 'adding%s' % file_line + +def add_imply_rule(config, fname, linenum): + """Add a new 'imply' option to a Kconfig + + Args: + config: config option to add an imply for (without CONFIG_ prefix) + fname: Kconfig filename to update + linenum: Line number to place the 'imply' before + + Returns: + Message indicating the result + """ + file_line = ' at %s:%d' % (fname, linenum) + data = open(fname).read().splitlines() + linenum -= 1 + + for offset, line in enumerate(data[linenum:]): + if line.strip().startswith('help') or not line: + data.insert(linenum + offset, '\timply %s' % config) + with open(fname, 'w') as fd: + fd.write('\n'.join(data) + '\n') + return 'added%s' % file_line + + return 'could not insert%s' + +(IMPLY_MIN_2, IMPLY_TARGET, IMPLY_CMD, IMPLY_NON_ARCH_BOARD) = ( + 1, 2, 4, 8) IMPLY_FLAGS = { 'min2': [IMPLY_MIN_2, 'Show options which imply >2 boards (normally >5)'], 'target': [IMPLY_TARGET, 'Allow CONFIG_TARGET_... options to imply'], 'cmd': [IMPLY_CMD, 'Allow CONFIG_CMD_... to imply'], + 'non-arch-board': [ + IMPLY_NON_ARCH_BOARD, + 'Allow Kconfig options outside arch/ and /board/ to imply'], }; -def do_imply_config(config_list, imply_flags, find_superset=False): +def do_imply_config(config_list, add_imply, imply_flags, skip_added, + check_kconfig=True, find_superset=False): """Find CONFIG options which imply those in the list Some CONFIG options can be implied by others and this can help to reduce @@ -1497,8 +1639,12 @@ def do_imply_config(config_list, imply_flags, find_superset=False): Params: config_list: List of CONFIG options to check (each a string) + add_imply: Automatically add an 'imply' for each config. imply_flags: Flags which control which implying configs are allowed (IMPLY_...) + skip_added: Don't show options which already have an imply added. + check_kconfig: Check if implied symbols already have an 'imply' or + 'select' for the target config, and show this information if so. find_superset: True to look for configs which are a superset of those already found. So for example if CONFIG_EXYNOS5 implies an option, but CONFIG_EXYNOS covers a larger set of defconfigs and also @@ -1509,6 +1655,10 @@ def do_imply_config(config_list, imply_flags, find_superset=False): config - a CONFIG_XXX options (a string, e.g. 'CONFIG_CMD_EEPROM') defconfig - a defconfig file (a string, e.g. 'configs/snow_defconfig') """ + kconf = KconfigScanner().conf if check_kconfig else None + if add_imply and add_imply != 'all': + add_imply = add_imply.split() + # key is defconfig name, value is dict of (CONFIG_xxx, value) config_db = {} @@ -1607,19 +1757,68 @@ def do_imply_config(config_list, imply_flags, find_superset=False): # The value of each dict item is the set of defconfigs containing that # config. Rank them so that we print the configs that imply the largest # number of defconfigs first. - ranked_configs = sorted(imply_configs, + ranked_iconfigs = sorted(imply_configs, key=lambda k: len(imply_configs[k]), reverse=True) - for config in ranked_configs: - num_common = len(imply_configs[config]) + kconfig_info = '' + cwd = os.getcwd() + add_list = collections.defaultdict(list) + for iconfig in ranked_iconfigs: + num_common = len(imply_configs[iconfig]) # Don't bother if there are less than 5 defconfigs affected. if num_common < (2 if imply_flags & IMPLY_MIN_2 else 5): continue - missing = defconfigs - imply_configs[config] + missing = defconfigs - imply_configs[iconfig] missing_str = ', '.join(missing) if missing else 'all' missing_str = '' - print ' %d : %-30s%s' % (num_common, config.ljust(30), - missing_str) + show = True + if kconf: + sym = find_kconfig_rules(kconf, config[CONFIG_LEN:], + iconfig[CONFIG_LEN:]) + kconfig_info = '' + if sym: + locs = sym.get_def_locations() + if len(locs) == 1: + fname, linenum = locs[0] + if cwd and fname.startswith(cwd): + fname = fname[len(cwd) + 1:] + kconfig_info = '%s:%d' % (fname, linenum) + if skip_added: + show = False + else: + sym = kconf.get_symbol(iconfig[CONFIG_LEN:]) + fname = '' + if sym: + locs = sym.get_def_locations() + if len(locs) == 1: + fname, linenum = locs[0] + if cwd and fname.startswith(cwd): + fname = fname[len(cwd) + 1:] + in_arch_board = not sym or (fname.startswith('arch') or + fname.startswith('board')) + if (not in_arch_board and + not (imply_flags & IMPLY_NON_ARCH_BOARD)): + continue + + if add_imply and (add_imply == 'all' or + iconfig in add_imply): + fname, linenum, kconfig_info = (check_imply_rule(kconf, + config[CONFIG_LEN:], iconfig[CONFIG_LEN:])) + if fname: + add_list[fname].append(linenum) + + if show and kconfig_info != 'skip': + print '%5d : %-30s%-25s %s' % (num_common, iconfig.ljust(30), + kconfig_info, missing_str) + + # Having collected a list of things to add, now we add them. We process + # each file from the largest line number to the smallest so that + # earlier additions do not affect our line numbers. E.g. if we added an + # imply at line 20 it would change the position of each line after + # that. + for fname, linenums in add_list.iteritems(): + for linenum in sorted(linenums, reverse=True): + add_imply_rule(config[CONFIG_LEN:], fname, linenum) def main(): @@ -1630,6 +1829,12 @@ def main(): parser = optparse.OptionParser() # Add options here + parser.add_option('-a', '--add-imply', type='string', default='', + help='comma-separated list of CONFIG options to add ' + "an 'imply' statement to for the CONFIG in -i") + parser.add_option('-A', '--skip-added', action='store_true', default=False, + help="don't show options which are already marked as " + 'implying others') parser.add_option('-b', '--build-db', action='store_true', default=False, help='build a CONFIG database') parser.add_option('-c', '--color', action='store_true', default=False, @@ -1690,7 +1895,8 @@ def main(): sys.exit(1) imply_flags |= IMPLY_FLAGS[flag][0] - do_imply_config(configs, imply_flags) + do_imply_config(configs, options.add_imply, imply_flags, + options.skip_added) return config_db = {} -- cgit v0.10.2 From 418355cbaa4dfe1a202538c1584f0b7b147f59c0 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 18 Jun 2017 22:08:56 -0600 Subject: dtoc: Use self._options instead of the global options This class should use the options object passed to it rather than finding the global one. Fix it. Signed-off-by: Simon Glass diff --git a/tools/dtoc/dtoc.py b/tools/dtoc/dtoc.py index c0ab13a..056f515 100755 --- a/tools/dtoc/dtoc.py +++ b/tools/dtoc/dtoc.py @@ -177,7 +177,7 @@ class DtbPlatdata: for node in root.subnodes: if 'compatible' in node.props: status = node.props.get('status') - if (not options.include_disabled and not status or + if (not self._options.include_disabled and not status or status.value != 'disabled'): self._valid_nodes.append(node) phandle_prop = node.props.get('phandle') @@ -203,7 +203,7 @@ class DtbPlatdata: for node in self.fdt.GetRoot().subnodes: if 'compatible' in node.props: status = node.props.get('status') - if (not options.include_disabled and not status or + if (not self._options.include_disabled and not status or status.value != 'disabled'): node_list.append(node) phandle_prop = node.props.get('phandle') -- cgit v0.10.2 From 14f5acfc5b0c133cbe5e7f5bffc0519f994abbfa Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 18 Jun 2017 22:08:57 -0600 Subject: dtoc: Add a comment at the top Add a description of the dtoc tool at the top of the file. Signed-off-by: Simon Glass diff --git a/tools/dtoc/dtoc.py b/tools/dtoc/dtoc.py index 056f515..7977947 100755 --- a/tools/dtoc/dtoc.py +++ b/tools/dtoc/dtoc.py @@ -6,6 +6,26 @@ # SPDX-License-Identifier: GPL-2.0+ # +"""Device tree to C tool + +This tool converts a device tree binary file (.dtb) into two C files. The +indent is to allow a C program to access data from the device tree without +having to link against libfdt. By putting the data from the device tree into +C structures, normal C code can be used. This helps to reduce the size of the +compiled program. + +Dtoc produces two output files: + + dt-structs.h - contains struct definitions + dt-platdata.c - contains data from the device tree using the struct + definitions, as well as U-Boot driver definitions. + +This tool is used in U-Boot to provide device tree data to SPL without +increasing the code size of SPL. This supports the CONFIG_SPL_OF_PLATDATA +options. For more information about the use of this options and tool please +see doc/driver-model/of-plat.txt +""" + import copy from optparse import OptionError, OptionParser import os -- cgit v0.10.2 From 7581c01a159ce04101798a39c04b5fa37ac718d2 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 18 Jun 2017 22:08:58 -0600 Subject: dtoc: Split out the main class into its own file To simplify running tests we should move this class into its own file. This allows the tests to import it without having to import dtoc.py, which runs the tests. Signed-off-by: Simon Glass diff --git a/tools/dtoc/dtb_platdata.py b/tools/dtoc/dtb_platdata.py new file mode 100644 index 0000000..94db274 --- /dev/null +++ b/tools/dtoc/dtb_platdata.py @@ -0,0 +1,411 @@ +#!/usr/bin/python +# +# Copyright (C) 2017 Google, Inc +# Written by Simon Glass +# +# SPDX-License-Identifier: GPL-2.0+ +# + +import copy + +import fdt +import fdt_util + +# When we see these properties we ignore them - i.e. do not create a structure member +PROP_IGNORE_LIST = [ + '#address-cells', + '#gpio-cells', + '#size-cells', + 'compatible', + 'linux,phandle', + "status", + 'phandle', + 'u-boot,dm-pre-reloc', + 'u-boot,dm-tpl', + 'u-boot,dm-spl', +] + +# C type declarations for the tyues we support +TYPE_NAMES = { + fdt.TYPE_INT: 'fdt32_t', + fdt.TYPE_BYTE: 'unsigned char', + fdt.TYPE_STRING: 'const char *', + fdt.TYPE_BOOL: 'bool', +}; + +STRUCT_PREFIX = 'dtd_' +VAL_PREFIX = 'dtv_' + +def Conv_name_to_c(name): + """Convert a device-tree name to a C identifier + + Args: + name: Name to convert + Return: + String containing the C version of this name + """ + str = name.replace('@', '_at_') + str = str.replace('-', '_') + str = str.replace(',', '_') + str = str.replace('.', '_') + str = str.replace('/', '__') + return str + +def TabTo(num_tabs, str): + if len(str) >= num_tabs * 8: + return str + ' ' + return str + '\t' * (num_tabs - len(str) // 8) + +class DtbPlatdata: + """Provide a means to convert device tree binary data to platform data + + The output of this process is C structures which can be used in space- + constrained encvironments where the ~3KB code overhead of device tree + code is not affordable. + + Properties: + fdt: Fdt object, referencing the device tree + _dtb_fname: Filename of the input device tree binary file + _valid_nodes: A list of Node object with compatible strings + _options: Command-line options + _phandle_node: A dict of nodes indexed by phandle number (1, 2...) + _outfile: The current output file (sys.stdout or a real file) + _lines: Stashed list of output lines for outputting in the future + _phandle_node: A dict of Nodes indexed by phandle (an integer) + """ + def __init__(self, dtb_fname, options): + self._dtb_fname = dtb_fname + self._valid_nodes = None + self._options = options + self._phandle_node = {} + self._outfile = None + self._lines = [] + self._aliases = {} + + def SetupOutput(self, fname): + """Set up the output destination + + Once this is done, future calls to self.Out() will output to this + file. + + Args: + fname: Filename to send output to, or '-' for stdout + """ + if fname == '-': + self._outfile = sys.stdout + else: + self._outfile = open(fname, 'w') + + def Out(self, str): + """Output a string to the output file + + Args: + str: String to output + """ + self._outfile.write(str) + + def Buf(self, str): + """Buffer up a string to send later + + Args: + str: String to add to our 'buffer' list + """ + self._lines.append(str) + + def GetBuf(self): + """Get the contents of the output buffer, and clear it + + Returns: + The output buffer, which is then cleared for future use + """ + lines = self._lines + self._lines = [] + return lines + + def GetValue(self, type, value): + """Get a value as a C expression + + For integers this returns a byte-swapped (little-endian) hex string + For bytes this returns a hex string, e.g. 0x12 + For strings this returns a literal string enclosed in quotes + For booleans this return 'true' + + Args: + type: Data type (fdt_util) + value: Data value, as a string of bytes + """ + if type == fdt.TYPE_INT: + return '%#x' % fdt_util.fdt32_to_cpu(value) + elif type == fdt.TYPE_BYTE: + return '%#x' % ord(value[0]) + elif type == fdt.TYPE_STRING: + return '"%s"' % value + elif type == fdt.TYPE_BOOL: + return 'true' + + def GetCompatName(self, node): + """Get a node's first compatible string as a C identifier + + Args: + node: Node object to check + Return: + C identifier for the first compatible string + """ + compat = node.props['compatible'].value + aliases = [] + if type(compat) == list: + compat, aliases = compat[0], compat[1:] + return Conv_name_to_c(compat), [Conv_name_to_c(a) for a in aliases] + + def ScanDtb(self): + """Scan the device tree to obtain a tree of notes and properties + + Once this is done, self.fdt.GetRoot() can be called to obtain the + device tree root node, and progress from there. + """ + self.fdt = fdt.FdtScan(self._dtb_fname) + + def ScanNode(self, root): + for node in root.subnodes: + if 'compatible' in node.props: + status = node.props.get('status') + if (not self._options.include_disabled and not status or + status.value != 'disabled'): + self._valid_nodes.append(node) + phandle_prop = node.props.get('phandle') + if phandle_prop: + phandle = phandle_prop.GetPhandle() + self._phandle_node[phandle] = node + + # recurse to handle any subnodes + self.ScanNode(node); + + def ScanTree(self): + """Scan the device tree for useful information + + This fills in the following properties: + _phandle_node: A dict of Nodes indexed by phandle (an integer) + _valid_nodes: A list of nodes we wish to consider include in the + platform data + """ + self._phandle_node = {} + self._valid_nodes = [] + return self.ScanNode(self.fdt.GetRoot()); + + for node in self.fdt.GetRoot().subnodes: + if 'compatible' in node.props: + status = node.props.get('status') + if (not self._options.include_disabled and not status or + status.value != 'disabled'): + node_list.append(node) + phandle_prop = node.props.get('phandle') + if phandle_prop: + phandle = phandle_prop.GetPhandle() + self._phandle_node[phandle] = node + + self._valid_nodes = node_list + + def IsPhandle(self, prop): + """Check if a node contains phandles + + We have no reliable way of detecting whether a node uses a phandle + or not. As an interim measure, use a list of known property names. + + Args: + prop: Prop object to check + Return: + True if the object value contains phandles, else False + """ + if prop.name in ['clocks']: + return True + return False + + def ScanStructs(self): + """Scan the device tree building up the C structures we will use. + + Build a dict keyed by C struct name containing a dict of Prop + object for each struct field (keyed by property name). Where the + same struct appears multiple times, try to use the 'widest' + property, i.e. the one with a type which can express all others. + + Once the widest property is determined, all other properties are + updated to match that width. + """ + structs = {} + for node in self._valid_nodes: + node_name, _ = self.GetCompatName(node) + fields = {} + + # Get a list of all the valid properties in this node. + for name, prop in node.props.items(): + if name not in PROP_IGNORE_LIST and name[0] != '#': + fields[name] = copy.deepcopy(prop) + + # If we've seen this node_name before, update the existing struct. + if node_name in structs: + struct = structs[node_name] + for name, prop in fields.items(): + oldprop = struct.get(name) + if oldprop: + oldprop.Widen(prop) + else: + struct[name] = prop + + # Otherwise store this as a new struct. + else: + structs[node_name] = fields + + upto = 0 + for node in self._valid_nodes: + node_name, _ = self.GetCompatName(node) + struct = structs[node_name] + for name, prop in node.props.items(): + if name not in PROP_IGNORE_LIST and name[0] != '#': + prop.Widen(struct[name]) + upto += 1 + + struct_name, aliases = self.GetCompatName(node) + for alias in aliases: + self._aliases[alias] = struct_name + + return structs + + def ScanPhandles(self): + """Figure out what phandles each node uses + + We need to be careful when outputing nodes that use phandles since + they must come after the declaration of the phandles in the C file. + Otherwise we get a compiler error since the phandle struct is not yet + declared. + + This function adds to each node a list of phandle nodes that the node + depends on. This allows us to output things in the right order. + """ + for node in self._valid_nodes: + node.phandles = set() + for pname, prop in node.props.items(): + if pname in PROP_IGNORE_LIST or pname[0] == '#': + continue + if type(prop.value) == list: + if self.IsPhandle(prop): + # Process the list as pairs of (phandle, id) + it = iter(prop.value) + for phandle_cell, id_cell in zip(it, it): + phandle = fdt_util.fdt32_to_cpu(phandle_cell) + id = fdt_util.fdt32_to_cpu(id_cell) + target_node = self._phandle_node[phandle] + node.phandles.add(target_node) + + + def GenerateStructs(self, structs): + """Generate struct defintions for the platform data + + This writes out the body of a header file consisting of structure + definitions for node in self._valid_nodes. See the documentation in + README.of-plat for more information. + """ + self.Out('#include \n') + self.Out('#include \n') + + # Output the struct definition + for name in sorted(structs): + self.Out('struct %s%s {\n' % (STRUCT_PREFIX, name)); + for pname in sorted(structs[name]): + prop = structs[name][pname] + if self.IsPhandle(prop): + # For phandles, include a reference to the target + self.Out('\t%s%s[%d]' % (TabTo(2, 'struct phandle_2_cell'), + Conv_name_to_c(prop.name), + len(prop.value) / 2)) + else: + ptype = TYPE_NAMES[prop.type] + self.Out('\t%s%s' % (TabTo(2, ptype), + Conv_name_to_c(prop.name))) + if type(prop.value) == list: + self.Out('[%d]' % len(prop.value)) + self.Out(';\n') + self.Out('};\n') + + for alias, struct_name in self._aliases.iteritems(): + self.Out('#define %s%s %s%s\n'% (STRUCT_PREFIX, alias, + STRUCT_PREFIX, struct_name)) + + def OutputNode(self, node): + """Output the C code for a node + + Args: + node: node to output + """ + struct_name, _ = self.GetCompatName(node) + var_name = Conv_name_to_c(node.name) + self.Buf('static struct %s%s %s%s = {\n' % + (STRUCT_PREFIX, struct_name, VAL_PREFIX, var_name)) + for pname, prop in node.props.items(): + if pname in PROP_IGNORE_LIST or pname[0] == '#': + continue + ptype = TYPE_NAMES[prop.type] + member_name = Conv_name_to_c(prop.name) + self.Buf('\t%s= ' % TabTo(3, '.' + member_name)) + + # Special handling for lists + if type(prop.value) == list: + self.Buf('{') + vals = [] + # For phandles, output a reference to the platform data + # of the target node. + if self.IsPhandle(prop): + # Process the list as pairs of (phandle, id) + it = iter(prop.value) + for phandle_cell, id_cell in zip(it, it): + phandle = fdt_util.fdt32_to_cpu(phandle_cell) + id = fdt_util.fdt32_to_cpu(id_cell) + target_node = self._phandle_node[phandle] + name = Conv_name_to_c(target_node.name) + vals.append('{&%s%s, %d}' % (VAL_PREFIX, name, id)) + else: + for val in prop.value: + vals.append(self.GetValue(prop.type, val)) + self.Buf(', '.join(vals)) + self.Buf('}') + else: + self.Buf(self.GetValue(prop.type, prop.value)) + self.Buf(',\n') + self.Buf('};\n') + + # Add a device declaration + self.Buf('U_BOOT_DEVICE(%s) = {\n' % var_name) + self.Buf('\t.name\t\t= "%s",\n' % struct_name) + self.Buf('\t.platdata\t= &%s%s,\n' % (VAL_PREFIX, var_name)) + self.Buf('\t.platdata_size\t= sizeof(%s%s),\n' % + (VAL_PREFIX, var_name)) + self.Buf('};\n') + self.Buf('\n') + + self.Out(''.join(self.GetBuf())) + + def GenerateTables(self): + """Generate device defintions for the platform data + + This writes out C platform data initialisation data and + U_BOOT_DEVICE() declarations for each valid node. Where a node has + multiple compatible strings, a #define is used to make them equivalent. + + See the documentation in doc/driver-model/of-plat.txt for more + information. + """ + self.Out('#include \n') + self.Out('#include \n') + self.Out('#include \n') + self.Out('\n') + nodes_to_output = list(self._valid_nodes) + + # Keep outputing nodes until there is none left + while nodes_to_output: + node = nodes_to_output[0] + # Output all the node's dependencies first + for req_node in node.phandles: + if req_node in nodes_to_output: + self.OutputNode(req_node) + nodes_to_output.remove(req_node) + self.OutputNode(node) + nodes_to_output.remove(node) diff --git a/tools/dtoc/dtoc.py b/tools/dtoc/dtoc.py index 7977947..8fc717a 100755 --- a/tools/dtoc/dtoc.py +++ b/tools/dtoc/dtoc.py @@ -26,417 +26,15 @@ options. For more information about the use of this options and tool please see doc/driver-model/of-plat.txt """ -import copy -from optparse import OptionError, OptionParser +from optparse import OptionParser import os -import struct import sys # Bring in the patman libraries our_path = os.path.dirname(os.path.realpath(__file__)) sys.path.append(os.path.join(our_path, '../patman')) -import fdt -import fdt_util - -# When we see these properties we ignore them - i.e. do not create a structure member -PROP_IGNORE_LIST = [ - '#address-cells', - '#gpio-cells', - '#size-cells', - 'compatible', - 'linux,phandle', - "status", - 'phandle', - 'u-boot,dm-pre-reloc', - 'u-boot,dm-tpl', - 'u-boot,dm-spl', -] - -# C type declarations for the tyues we support -TYPE_NAMES = { - fdt.TYPE_INT: 'fdt32_t', - fdt.TYPE_BYTE: 'unsigned char', - fdt.TYPE_STRING: 'const char *', - fdt.TYPE_BOOL: 'bool', -}; - -STRUCT_PREFIX = 'dtd_' -VAL_PREFIX = 'dtv_' - -def Conv_name_to_c(name): - """Convert a device-tree name to a C identifier - - Args: - name: Name to convert - Return: - String containing the C version of this name - """ - str = name.replace('@', '_at_') - str = str.replace('-', '_') - str = str.replace(',', '_') - str = str.replace('.', '_') - str = str.replace('/', '__') - return str - -def TabTo(num_tabs, str): - if len(str) >= num_tabs * 8: - return str + ' ' - return str + '\t' * (num_tabs - len(str) // 8) - -class DtbPlatdata: - """Provide a means to convert device tree binary data to platform data - - The output of this process is C structures which can be used in space- - constrained encvironments where the ~3KB code overhead of device tree - code is not affordable. - - Properties: - fdt: Fdt object, referencing the device tree - _dtb_fname: Filename of the input device tree binary file - _valid_nodes: A list of Node object with compatible strings - _options: Command-line options - _phandle_node: A dict of nodes indexed by phandle number (1, 2...) - _outfile: The current output file (sys.stdout or a real file) - _lines: Stashed list of output lines for outputting in the future - _phandle_node: A dict of Nodes indexed by phandle (an integer) - """ - def __init__(self, dtb_fname, options): - self._dtb_fname = dtb_fname - self._valid_nodes = None - self._options = options - self._phandle_node = {} - self._outfile = None - self._lines = [] - self._aliases = {} - - def SetupOutput(self, fname): - """Set up the output destination - - Once this is done, future calls to self.Out() will output to this - file. - - Args: - fname: Filename to send output to, or '-' for stdout - """ - if fname == '-': - self._outfile = sys.stdout - else: - self._outfile = open(fname, 'w') - - def Out(self, str): - """Output a string to the output file - - Args: - str: String to output - """ - self._outfile.write(str) - - def Buf(self, str): - """Buffer up a string to send later - - Args: - str: String to add to our 'buffer' list - """ - self._lines.append(str) - - def GetBuf(self): - """Get the contents of the output buffer, and clear it - - Returns: - The output buffer, which is then cleared for future use - """ - lines = self._lines - self._lines = [] - return lines - - def GetValue(self, type, value): - """Get a value as a C expression - - For integers this returns a byte-swapped (little-endian) hex string - For bytes this returns a hex string, e.g. 0x12 - For strings this returns a literal string enclosed in quotes - For booleans this return 'true' - - Args: - type: Data type (fdt_util) - value: Data value, as a string of bytes - """ - if type == fdt.TYPE_INT: - return '%#x' % fdt_util.fdt32_to_cpu(value) - elif type == fdt.TYPE_BYTE: - return '%#x' % ord(value[0]) - elif type == fdt.TYPE_STRING: - return '"%s"' % value - elif type == fdt.TYPE_BOOL: - return 'true' - - def GetCompatName(self, node): - """Get a node's first compatible string as a C identifier - - Args: - node: Node object to check - Return: - C identifier for the first compatible string - """ - compat = node.props['compatible'].value - aliases = [] - if type(compat) == list: - compat, aliases = compat[0], compat[1:] - return Conv_name_to_c(compat), [Conv_name_to_c(a) for a in aliases] - - def ScanDtb(self): - """Scan the device tree to obtain a tree of notes and properties - - Once this is done, self.fdt.GetRoot() can be called to obtain the - device tree root node, and progress from there. - """ - self.fdt = fdt.FdtScan(self._dtb_fname) - - def ScanNode(self, root): - for node in root.subnodes: - if 'compatible' in node.props: - status = node.props.get('status') - if (not self._options.include_disabled and not status or - status.value != 'disabled'): - self._valid_nodes.append(node) - phandle_prop = node.props.get('phandle') - if phandle_prop: - phandle = phandle_prop.GetPhandle() - self._phandle_node[phandle] = node - - # recurse to handle any subnodes - self.ScanNode(node); - - def ScanTree(self): - """Scan the device tree for useful information - - This fills in the following properties: - _phandle_node: A dict of Nodes indexed by phandle (an integer) - _valid_nodes: A list of nodes we wish to consider include in the - platform data - """ - self._phandle_node = {} - self._valid_nodes = [] - return self.ScanNode(self.fdt.GetRoot()); - - for node in self.fdt.GetRoot().subnodes: - if 'compatible' in node.props: - status = node.props.get('status') - if (not self._options.include_disabled and not status or - status.value != 'disabled'): - node_list.append(node) - phandle_prop = node.props.get('phandle') - if phandle_prop: - phandle = phandle_prop.GetPhandle() - self._phandle_node[phandle] = node - - self._valid_nodes = node_list - - def IsPhandle(self, prop): - """Check if a node contains phandles - - We have no reliable way of detecting whether a node uses a phandle - or not. As an interim measure, use a list of known property names. - - Args: - prop: Prop object to check - Return: - True if the object value contains phandles, else False - """ - if prop.name in ['clocks']: - return True - return False - - def ScanStructs(self): - """Scan the device tree building up the C structures we will use. - - Build a dict keyed by C struct name containing a dict of Prop - object for each struct field (keyed by property name). Where the - same struct appears multiple times, try to use the 'widest' - property, i.e. the one with a type which can express all others. - - Once the widest property is determined, all other properties are - updated to match that width. - """ - structs = {} - for node in self._valid_nodes: - node_name, _ = self.GetCompatName(node) - fields = {} - - # Get a list of all the valid properties in this node. - for name, prop in node.props.items(): - if name not in PROP_IGNORE_LIST and name[0] != '#': - fields[name] = copy.deepcopy(prop) - - # If we've seen this node_name before, update the existing struct. - if node_name in structs: - struct = structs[node_name] - for name, prop in fields.items(): - oldprop = struct.get(name) - if oldprop: - oldprop.Widen(prop) - else: - struct[name] = prop - - # Otherwise store this as a new struct. - else: - structs[node_name] = fields - - upto = 0 - for node in self._valid_nodes: - node_name, _ = self.GetCompatName(node) - struct = structs[node_name] - for name, prop in node.props.items(): - if name not in PROP_IGNORE_LIST and name[0] != '#': - prop.Widen(struct[name]) - upto += 1 - - struct_name, aliases = self.GetCompatName(node) - for alias in aliases: - self._aliases[alias] = struct_name - - return structs - - def ScanPhandles(self): - """Figure out what phandles each node uses - - We need to be careful when outputing nodes that use phandles since - they must come after the declaration of the phandles in the C file. - Otherwise we get a compiler error since the phandle struct is not yet - declared. - - This function adds to each node a list of phandle nodes that the node - depends on. This allows us to output things in the right order. - """ - for node in self._valid_nodes: - node.phandles = set() - for pname, prop in node.props.items(): - if pname in PROP_IGNORE_LIST or pname[0] == '#': - continue - if type(prop.value) == list: - if self.IsPhandle(prop): - # Process the list as pairs of (phandle, id) - it = iter(prop.value) - for phandle_cell, id_cell in zip(it, it): - phandle = fdt_util.fdt32_to_cpu(phandle_cell) - id = fdt_util.fdt32_to_cpu(id_cell) - target_node = self._phandle_node[phandle] - node.phandles.add(target_node) - - - def GenerateStructs(self, structs): - """Generate struct defintions for the platform data - - This writes out the body of a header file consisting of structure - definitions for node in self._valid_nodes. See the documentation in - README.of-plat for more information. - """ - self.Out('#include \n') - self.Out('#include \n') - - # Output the struct definition - for name in sorted(structs): - self.Out('struct %s%s {\n' % (STRUCT_PREFIX, name)); - for pname in sorted(structs[name]): - prop = structs[name][pname] - if self.IsPhandle(prop): - # For phandles, include a reference to the target - self.Out('\t%s%s[%d]' % (TabTo(2, 'struct phandle_2_cell'), - Conv_name_to_c(prop.name), - len(prop.value) / 2)) - else: - ptype = TYPE_NAMES[prop.type] - self.Out('\t%s%s' % (TabTo(2, ptype), - Conv_name_to_c(prop.name))) - if type(prop.value) == list: - self.Out('[%d]' % len(prop.value)) - self.Out(';\n') - self.Out('};\n') - - for alias, struct_name in self._aliases.iteritems(): - self.Out('#define %s%s %s%s\n'% (STRUCT_PREFIX, alias, - STRUCT_PREFIX, struct_name)) - - def OutputNode(self, node): - """Output the C code for a node - - Args: - node: node to output - """ - struct_name, _ = self.GetCompatName(node) - var_name = Conv_name_to_c(node.name) - self.Buf('static struct %s%s %s%s = {\n' % - (STRUCT_PREFIX, struct_name, VAL_PREFIX, var_name)) - for pname, prop in node.props.items(): - if pname in PROP_IGNORE_LIST or pname[0] == '#': - continue - ptype = TYPE_NAMES[prop.type] - member_name = Conv_name_to_c(prop.name) - self.Buf('\t%s= ' % TabTo(3, '.' + member_name)) - - # Special handling for lists - if type(prop.value) == list: - self.Buf('{') - vals = [] - # For phandles, output a reference to the platform data - # of the target node. - if self.IsPhandle(prop): - # Process the list as pairs of (phandle, id) - it = iter(prop.value) - for phandle_cell, id_cell in zip(it, it): - phandle = fdt_util.fdt32_to_cpu(phandle_cell) - id = fdt_util.fdt32_to_cpu(id_cell) - target_node = self._phandle_node[phandle] - name = Conv_name_to_c(target_node.name) - vals.append('{&%s%s, %d}' % (VAL_PREFIX, name, id)) - else: - for val in prop.value: - vals.append(self.GetValue(prop.type, val)) - self.Buf(', '.join(vals)) - self.Buf('}') - else: - self.Buf(self.GetValue(prop.type, prop.value)) - self.Buf(',\n') - self.Buf('};\n') - - # Add a device declaration - self.Buf('U_BOOT_DEVICE(%s) = {\n' % var_name) - self.Buf('\t.name\t\t= "%s",\n' % struct_name) - self.Buf('\t.platdata\t= &%s%s,\n' % (VAL_PREFIX, var_name)) - self.Buf('\t.platdata_size\t= sizeof(%s%s),\n' % - (VAL_PREFIX, var_name)) - self.Buf('};\n') - self.Buf('\n') - - self.Out(''.join(self.GetBuf())) - - def GenerateTables(self): - """Generate device defintions for the platform data - - This writes out C platform data initialisation data and - U_BOOT_DEVICE() declarations for each valid node. Where a node has - multiple compatible strings, a #define is used to make them equivalent. - - See the documentation in doc/driver-model/of-plat.txt for more - information. - """ - self.Out('#include \n') - self.Out('#include \n') - self.Out('#include \n') - self.Out('\n') - nodes_to_output = list(self._valid_nodes) - - # Keep outputing nodes until there is none left - while nodes_to_output: - node = nodes_to_output[0] - # Output all the node's dependencies first - for req_node in node.phandles: - if req_node in nodes_to_output: - self.OutputNode(req_node) - nodes_to_output.remove(req_node) - self.OutputNode(node) - nodes_to_output.remove(node) +import dtb_platdata if __name__ != "__main__": @@ -454,7 +52,7 @@ parser.add_option('-o', '--output', action='store', default='-', if not args: raise ValueError('Please specify a command: struct, platdata') -plat = DtbPlatdata(options.dtb_file, options) +plat = dtb_platdata.DtbPlatdata(options.dtb_file, options) plat.ScanDtb() plat.ScanTree() plat.SetupOutput(options.output) -- cgit v0.10.2 From 2be282ca01dba237504fe2887fbd4539865093c3 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 18 Jun 2017 22:08:59 -0600 Subject: dtoc: Fix pylint warnings Unfortunately I neglected to run pylint on this tool with its initial submission. Fix the warnings. Signed-off-by: Simon Glass diff --git a/tools/dtoc/dtb_platdata.py b/tools/dtoc/dtb_platdata.py index 94db274..75adf48 100644 --- a/tools/dtoc/dtb_platdata.py +++ b/tools/dtoc/dtb_platdata.py @@ -6,7 +6,14 @@ # SPDX-License-Identifier: GPL-2.0+ # +"""Device tree to platform data class + +This supports converting device tree data to C structures definitions and +static data. +""" + import copy +import sys import fdt import fdt_util @@ -31,12 +38,12 @@ TYPE_NAMES = { fdt.TYPE_BYTE: 'unsigned char', fdt.TYPE_STRING: 'const char *', fdt.TYPE_BOOL: 'bool', -}; +} STRUCT_PREFIX = 'dtd_' VAL_PREFIX = 'dtv_' -def Conv_name_to_c(name): +def conv_name_to_c(name): """Convert a device-tree name to a C identifier Args: @@ -44,19 +51,29 @@ def Conv_name_to_c(name): Return: String containing the C version of this name """ - str = name.replace('@', '_at_') - str = str.replace('-', '_') - str = str.replace(',', '_') - str = str.replace('.', '_') - str = str.replace('/', '__') - return str - -def TabTo(num_tabs, str): - if len(str) >= num_tabs * 8: - return str + ' ' - return str + '\t' * (num_tabs - len(str) // 8) - -class DtbPlatdata: + new = name.replace('@', '_at_') + new = new.replace('-', '_') + new = new.replace(',', '_') + new = new.replace('.', '_') + new = new.replace('/', '__') + return new + +def tab_to(num_tabs, line): + """Append tabs to a line of text to reach a tab stop. + + Args: + num_tabs: Tab stop to obtain (0 = column 0, 1 = column 8, etc.) + line: Line of text to append to + + Returns: + line with the correct number of tabs appeneded. If the line already + extends past that tab stop then a single space is appended. + """ + if len(line) >= num_tabs * 8: + return line + ' ' + return line + '\t' * (num_tabs - len(line) // 8) + +class DtbPlatdata(object): """Provide a means to convert device tree binary data to platform data The output of this process is C structures which can be used in space- @@ -64,28 +81,29 @@ class DtbPlatdata: code is not affordable. Properties: - fdt: Fdt object, referencing the device tree + _fdt: Fdt object, referencing the device tree _dtb_fname: Filename of the input device tree binary file _valid_nodes: A list of Node object with compatible strings _options: Command-line options - _phandle_node: A dict of nodes indexed by phandle number (1, 2...) + _phandle_nodes: A dict of nodes indexed by phandle number (1, 2...) _outfile: The current output file (sys.stdout or a real file) _lines: Stashed list of output lines for outputting in the future - _phandle_node: A dict of Nodes indexed by phandle (an integer) + _phandle_nodes: A dict of Nodes indexed by phandle (an integer) """ def __init__(self, dtb_fname, options): + self._fdt = None self._dtb_fname = dtb_fname self._valid_nodes = None self._options = options - self._phandle_node = {} + self._phandle_nodes = {} self._outfile = None self._lines = [] self._aliases = {} - def SetupOutput(self, fname): + def setup_output(self, fname): """Set up the output destination - Once this is done, future calls to self.Out() will output to this + Once this is done, future calls to self.out() will output to this file. Args: @@ -96,23 +114,23 @@ class DtbPlatdata: else: self._outfile = open(fname, 'w') - def Out(self, str): + def out(self, line): """Output a string to the output file Args: - str: String to output + line: String to output """ - self._outfile.write(str) + self._outfile.write(line) - def Buf(self, str): + def buf(self, line): """Buffer up a string to send later Args: - str: String to add to our 'buffer' list + line: String to add to our 'buffer' list """ - self._lines.append(str) + self._lines.append(line) - def GetBuf(self): + def get_buf(self): """Get the contents of the output buffer, and clear it Returns: @@ -122,7 +140,8 @@ class DtbPlatdata: self._lines = [] return lines - def GetValue(self, type, value): + @staticmethod + def get_value(ftype, value): """Get a value as a C expression For integers this returns a byte-swapped (little-endian) hex string @@ -134,16 +153,17 @@ class DtbPlatdata: type: Data type (fdt_util) value: Data value, as a string of bytes """ - if type == fdt.TYPE_INT: + if ftype == fdt.TYPE_INT: return '%#x' % fdt_util.fdt32_to_cpu(value) - elif type == fdt.TYPE_BYTE: + elif ftype == fdt.TYPE_BYTE: return '%#x' % ord(value[0]) - elif type == fdt.TYPE_STRING: + elif ftype == fdt.TYPE_STRING: return '"%s"' % value - elif type == fdt.TYPE_BOOL: + elif ftype == fdt.TYPE_BOOL: return 'true' - def GetCompatName(self, node): + @staticmethod + def get_compat_name(node): """Get a node's first compatible string as a C identifier Args: @@ -153,59 +173,55 @@ class DtbPlatdata: """ compat = node.props['compatible'].value aliases = [] - if type(compat) == list: + if isinstance(compat, list): compat, aliases = compat[0], compat[1:] - return Conv_name_to_c(compat), [Conv_name_to_c(a) for a in aliases] + return conv_name_to_c(compat), [conv_name_to_c(a) for a in aliases] - def ScanDtb(self): + def scan_dtb(self): """Scan the device tree to obtain a tree of notes and properties - Once this is done, self.fdt.GetRoot() can be called to obtain the + Once this is done, self._fdt.GetRoot() can be called to obtain the device tree root node, and progress from there. """ - self.fdt = fdt.FdtScan(self._dtb_fname) + self._fdt = fdt.FdtScan(self._dtb_fname) + + def scan_node(self, root): + """Scan a node and subnodes to build a tree of node and phandle info + + This adds each node to self._valid_nodes and each phandle to + self._phandle_nodes. - def ScanNode(self, root): + Args: + root: Root node for scan + """ for node in root.subnodes: if 'compatible' in node.props: status = node.props.get('status') if (not self._options.include_disabled and not status or - status.value != 'disabled'): + status.value != 'disabled'): self._valid_nodes.append(node) phandle_prop = node.props.get('phandle') if phandle_prop: phandle = phandle_prop.GetPhandle() - self._phandle_node[phandle] = node + self._phandle_nodes[phandle] = node # recurse to handle any subnodes - self.ScanNode(node); + self.scan_node(node) - def ScanTree(self): + def scan_tree(self): """Scan the device tree for useful information This fills in the following properties: - _phandle_node: A dict of Nodes indexed by phandle (an integer) + _phandle_nodes: A dict of Nodes indexed by phandle (an integer) _valid_nodes: A list of nodes we wish to consider include in the platform data """ - self._phandle_node = {} + self._phandle_nodes = {} self._valid_nodes = [] - return self.ScanNode(self.fdt.GetRoot()); - - for node in self.fdt.GetRoot().subnodes: - if 'compatible' in node.props: - status = node.props.get('status') - if (not self._options.include_disabled and not status or - status.value != 'disabled'): - node_list.append(node) - phandle_prop = node.props.get('phandle') - if phandle_prop: - phandle = phandle_prop.GetPhandle() - self._phandle_node[phandle] = node - - self._valid_nodes = node_list + return self.scan_node(self._fdt.GetRoot()) - def IsPhandle(self, prop): + @staticmethod + def is_phandle(prop): """Check if a node contains phandles We have no reliable way of detecting whether a node uses a phandle @@ -220,7 +236,7 @@ class DtbPlatdata: return True return False - def ScanStructs(self): + def scan_structs(self): """Scan the device tree building up the C structures we will use. Build a dict keyed by C struct name containing a dict of Prop @@ -233,7 +249,7 @@ class DtbPlatdata: """ structs = {} for node in self._valid_nodes: - node_name, _ = self.GetCompatName(node) + node_name, _ = self.get_compat_name(node) fields = {} # Get a list of all the valid properties in this node. @@ -257,20 +273,20 @@ class DtbPlatdata: upto = 0 for node in self._valid_nodes: - node_name, _ = self.GetCompatName(node) + node_name, _ = self.get_compat_name(node) struct = structs[node_name] for name, prop in node.props.items(): if name not in PROP_IGNORE_LIST and name[0] != '#': prop.Widen(struct[name]) upto += 1 - struct_name, aliases = self.GetCompatName(node) + struct_name, aliases = self.get_compat_name(node) for alias in aliases: self._aliases[alias] = struct_name return structs - def ScanPhandles(self): + def scan_phandles(self): """Figure out what phandles each node uses We need to be careful when outputing nodes that use phandles since @@ -286,104 +302,101 @@ class DtbPlatdata: for pname, prop in node.props.items(): if pname in PROP_IGNORE_LIST or pname[0] == '#': continue - if type(prop.value) == list: - if self.IsPhandle(prop): + if isinstance(prop.value, list): + if self.is_phandle(prop): # Process the list as pairs of (phandle, id) - it = iter(prop.value) - for phandle_cell, id_cell in zip(it, it): + value_it = iter(prop.value) + for phandle_cell, _ in zip(value_it, value_it): phandle = fdt_util.fdt32_to_cpu(phandle_cell) - id = fdt_util.fdt32_to_cpu(id_cell) - target_node = self._phandle_node[phandle] + target_node = self._phandle_nodes[phandle] node.phandles.add(target_node) - def GenerateStructs(self, structs): + def generate_structs(self, structs): """Generate struct defintions for the platform data This writes out the body of a header file consisting of structure definitions for node in self._valid_nodes. See the documentation in README.of-plat for more information. """ - self.Out('#include \n') - self.Out('#include \n') + self.out('#include \n') + self.out('#include \n') # Output the struct definition for name in sorted(structs): - self.Out('struct %s%s {\n' % (STRUCT_PREFIX, name)); + self.out('struct %s%s {\n' % (STRUCT_PREFIX, name)) for pname in sorted(structs[name]): prop = structs[name][pname] - if self.IsPhandle(prop): + if self.is_phandle(prop): # For phandles, include a reference to the target - self.Out('\t%s%s[%d]' % (TabTo(2, 'struct phandle_2_cell'), - Conv_name_to_c(prop.name), + self.out('\t%s%s[%d]' % (tab_to(2, 'struct phandle_2_cell'), + conv_name_to_c(prop.name), len(prop.value) / 2)) else: ptype = TYPE_NAMES[prop.type] - self.Out('\t%s%s' % (TabTo(2, ptype), - Conv_name_to_c(prop.name))) - if type(prop.value) == list: - self.Out('[%d]' % len(prop.value)) - self.Out(';\n') - self.Out('};\n') + self.out('\t%s%s' % (tab_to(2, ptype), + conv_name_to_c(prop.name))) + if isinstance(prop.value, list): + self.out('[%d]' % len(prop.value)) + self.out(';\n') + self.out('};\n') for alias, struct_name in self._aliases.iteritems(): - self.Out('#define %s%s %s%s\n'% (STRUCT_PREFIX, alias, + self.out('#define %s%s %s%s\n'% (STRUCT_PREFIX, alias, STRUCT_PREFIX, struct_name)) - def OutputNode(self, node): + def output_node(self, node): """Output the C code for a node Args: node: node to output """ - struct_name, _ = self.GetCompatName(node) - var_name = Conv_name_to_c(node.name) - self.Buf('static struct %s%s %s%s = {\n' % - (STRUCT_PREFIX, struct_name, VAL_PREFIX, var_name)) + struct_name, _ = self.get_compat_name(node) + var_name = conv_name_to_c(node.name) + self.buf('static struct %s%s %s%s = {\n' % + (STRUCT_PREFIX, struct_name, VAL_PREFIX, var_name)) for pname, prop in node.props.items(): if pname in PROP_IGNORE_LIST or pname[0] == '#': continue - ptype = TYPE_NAMES[prop.type] - member_name = Conv_name_to_c(prop.name) - self.Buf('\t%s= ' % TabTo(3, '.' + member_name)) + member_name = conv_name_to_c(prop.name) + self.buf('\t%s= ' % tab_to(3, '.' + member_name)) # Special handling for lists - if type(prop.value) == list: - self.Buf('{') + if isinstance(prop.value, list): + self.buf('{') vals = [] # For phandles, output a reference to the platform data # of the target node. - if self.IsPhandle(prop): + if self.is_phandle(prop): # Process the list as pairs of (phandle, id) - it = iter(prop.value) - for phandle_cell, id_cell in zip(it, it): + value_it = iter(prop.value) + for phandle_cell, id_cell in zip(value_it, value_it): phandle = fdt_util.fdt32_to_cpu(phandle_cell) - id = fdt_util.fdt32_to_cpu(id_cell) - target_node = self._phandle_node[phandle] - name = Conv_name_to_c(target_node.name) - vals.append('{&%s%s, %d}' % (VAL_PREFIX, name, id)) + id_num = fdt_util.fdt32_to_cpu(id_cell) + target_node = self._phandle_nodes[phandle] + name = conv_name_to_c(target_node.name) + vals.append('{&%s%s, %d}' % (VAL_PREFIX, name, id_num)) else: for val in prop.value: - vals.append(self.GetValue(prop.type, val)) - self.Buf(', '.join(vals)) - self.Buf('}') + vals.append(self.get_value(prop.type, val)) + self.buf(', '.join(vals)) + self.buf('}') else: - self.Buf(self.GetValue(prop.type, prop.value)) - self.Buf(',\n') - self.Buf('};\n') + self.buf(self.get_value(prop.type, prop.value)) + self.buf(',\n') + self.buf('};\n') # Add a device declaration - self.Buf('U_BOOT_DEVICE(%s) = {\n' % var_name) - self.Buf('\t.name\t\t= "%s",\n' % struct_name) - self.Buf('\t.platdata\t= &%s%s,\n' % (VAL_PREFIX, var_name)) - self.Buf('\t.platdata_size\t= sizeof(%s%s),\n' % - (VAL_PREFIX, var_name)) - self.Buf('};\n') - self.Buf('\n') + self.buf('U_BOOT_DEVICE(%s) = {\n' % var_name) + self.buf('\t.name\t\t= "%s",\n' % struct_name) + self.buf('\t.platdata\t= &%s%s,\n' % (VAL_PREFIX, var_name)) + self.buf('\t.platdata_size\t= sizeof(%s%s),\n' % (VAL_PREFIX, var_name)) + self.buf('};\n') + self.buf('\n') - self.Out(''.join(self.GetBuf())) + self.out(''.join(self.get_buf())) - def GenerateTables(self): + def generate_tables(self): """Generate device defintions for the platform data This writes out C platform data initialisation data and @@ -393,10 +406,10 @@ class DtbPlatdata: See the documentation in doc/driver-model/of-plat.txt for more information. """ - self.Out('#include \n') - self.Out('#include \n') - self.Out('#include \n') - self.Out('\n') + self.out('#include \n') + self.out('#include \n') + self.out('#include \n') + self.out('\n') nodes_to_output = list(self._valid_nodes) # Keep outputing nodes until there is none left @@ -405,7 +418,7 @@ class DtbPlatdata: # Output all the node's dependencies first for req_node in node.phandles: if req_node in nodes_to_output: - self.OutputNode(req_node) + self.output_node(req_node) nodes_to_output.remove(req_node) - self.OutputNode(node) + self.output_node(node) nodes_to_output.remove(node) diff --git a/tools/dtoc/dtoc.py b/tools/dtoc/dtoc.py index 8fc717a..abda919 100755 --- a/tools/dtoc/dtoc.py +++ b/tools/dtoc/dtoc.py @@ -53,16 +53,16 @@ if not args: raise ValueError('Please specify a command: struct, platdata') plat = dtb_platdata.DtbPlatdata(options.dtb_file, options) -plat.ScanDtb() -plat.ScanTree() -plat.SetupOutput(options.output) -structs = plat.ScanStructs() -plat.ScanPhandles() +plat.scan_dtb() +plat.scan_tree() +plat.setup_output(options.output) +structs = plat.scan_structs() +plat.scan_phandles() for cmd in args[0].split(','): if cmd == 'struct': - plat.GenerateStructs(structs) + plat.generate_structs(structs) elif cmd == 'platdata': - plat.GenerateTables() + plat.generate_tables() else: raise ValueError("Unknown command '%s': (use: struct, platdata)" % cmd) -- cgit v0.10.2 From 86290ce40e76ad2e09da096cc7686cdc86756ee1 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 18 Jun 2017 22:09:00 -0600 Subject: dtoc: Don't handle properties with / in them This conversion appears to not be needed as it does not occur in practice. Drop it. Signed-off-by: Simon Glass diff --git a/tools/dtoc/dtb_platdata.py b/tools/dtoc/dtb_platdata.py index 75adf48..d86651b 100644 --- a/tools/dtoc/dtb_platdata.py +++ b/tools/dtoc/dtb_platdata.py @@ -55,7 +55,6 @@ def conv_name_to_c(name): new = new.replace('-', '_') new = new.replace(',', '_') new = new.replace('.', '_') - new = new.replace('/', '__') return new def tab_to(num_tabs, line): -- cgit v0.10.2 From e36024b05ff64937be65a74c156e9c83ad315a4c Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 18 Jun 2017 22:09:01 -0600 Subject: dtoc: Pass include_disabled explicitly This option is the only one actually used by the dtb_platdata class. Pass it explicitly to avoid needing to pass the whole option object to the constructor. Signed-off-by: Simon Glass diff --git a/tools/dtoc/dtb_platdata.py b/tools/dtoc/dtb_platdata.py index d86651b..de4a88b 100644 --- a/tools/dtoc/dtb_platdata.py +++ b/tools/dtoc/dtb_platdata.py @@ -83,17 +83,17 @@ class DtbPlatdata(object): _fdt: Fdt object, referencing the device tree _dtb_fname: Filename of the input device tree binary file _valid_nodes: A list of Node object with compatible strings - _options: Command-line options + _include_disabled: true to include nodes marked status = "disabled" _phandle_nodes: A dict of nodes indexed by phandle number (1, 2...) _outfile: The current output file (sys.stdout or a real file) _lines: Stashed list of output lines for outputting in the future _phandle_nodes: A dict of Nodes indexed by phandle (an integer) """ - def __init__(self, dtb_fname, options): + def __init__(self, dtb_fname, include_disabled): self._fdt = None self._dtb_fname = dtb_fname self._valid_nodes = None - self._options = options + self._include_disabled = include_disabled self._phandle_nodes = {} self._outfile = None self._lines = [] @@ -196,7 +196,7 @@ class DtbPlatdata(object): for node in root.subnodes: if 'compatible' in node.props: status = node.props.get('status') - if (not self._options.include_disabled and not status or + if (not self._include_disabled and not status or status.value != 'disabled'): self._valid_nodes.append(node) phandle_prop = node.props.get('phandle') diff --git a/tools/dtoc/dtoc.py b/tools/dtoc/dtoc.py index abda919..1f17ea4 100755 --- a/tools/dtoc/dtoc.py +++ b/tools/dtoc/dtoc.py @@ -52,7 +52,7 @@ parser.add_option('-o', '--output', action='store', default='-', if not args: raise ValueError('Please specify a command: struct, platdata') -plat = dtb_platdata.DtbPlatdata(options.dtb_file, options) +plat = dtb_platdata.DtbPlatdata(options.dtb_file, options.include_disabled) plat.scan_dtb() plat.scan_tree() plat.setup_output(options.output) -- cgit v0.10.2 From 56e0bbe0577f33d5bb2486a60267ba759e2ea643 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 18 Jun 2017 22:09:02 -0600 Subject: dtoc: Move static functions out of the class Rather than using static functions within the class, move them out of the class. This will make it slightly easier for tests to call them. Signed-off-by: Simon Glass diff --git a/tools/dtoc/dtb_platdata.py b/tools/dtoc/dtb_platdata.py index de4a88b..a1f32e1 100644 --- a/tools/dtoc/dtb_platdata.py +++ b/tools/dtoc/dtb_platdata.py @@ -72,6 +72,60 @@ def tab_to(num_tabs, line): return line + ' ' return line + '\t' * (num_tabs - len(line) // 8) +def get_value(ftype, value): + """Get a value as a C expression + + For integers this returns a byte-swapped (little-endian) hex string + For bytes this returns a hex string, e.g. 0x12 + For strings this returns a literal string enclosed in quotes + For booleans this return 'true' + + Args: + type: Data type (fdt_util) + value: Data value, as a string of bytes + """ + if ftype == fdt.TYPE_INT: + return '%#x' % fdt_util.fdt32_to_cpu(value) + elif ftype == fdt.TYPE_BYTE: + return '%#x' % ord(value[0]) + elif ftype == fdt.TYPE_STRING: + return '"%s"' % value + elif ftype == fdt.TYPE_BOOL: + return 'true' + +def get_compat_name(node): + """Get a node's first compatible string as a C identifier + + Args: + node: Node object to check + Return: + Tuple: + C identifier for the first compatible string + List of C identifiers for all the other compatible strings + (possibly empty) + """ + compat = node.props['compatible'].value + aliases = [] + if isinstance(compat, list): + compat, aliases = compat[0], compat[1:] + return conv_name_to_c(compat), [conv_name_to_c(a) for a in aliases] + +def is_phandle(prop): + """Check if a node contains phandles + + We have no reliable way of detecting whether a node uses a phandle + or not. As an interim measure, use a list of known property names. + + Args: + prop: Prop object to check + Return: + True if the object value contains phandles, else False + """ + if prop.name in ['clocks']: + return True + return False + + class DtbPlatdata(object): """Provide a means to convert device tree binary data to platform data @@ -139,43 +193,6 @@ class DtbPlatdata(object): self._lines = [] return lines - @staticmethod - def get_value(ftype, value): - """Get a value as a C expression - - For integers this returns a byte-swapped (little-endian) hex string - For bytes this returns a hex string, e.g. 0x12 - For strings this returns a literal string enclosed in quotes - For booleans this return 'true' - - Args: - type: Data type (fdt_util) - value: Data value, as a string of bytes - """ - if ftype == fdt.TYPE_INT: - return '%#x' % fdt_util.fdt32_to_cpu(value) - elif ftype == fdt.TYPE_BYTE: - return '%#x' % ord(value[0]) - elif ftype == fdt.TYPE_STRING: - return '"%s"' % value - elif ftype == fdt.TYPE_BOOL: - return 'true' - - @staticmethod - def get_compat_name(node): - """Get a node's first compatible string as a C identifier - - Args: - node: Node object to check - Return: - C identifier for the first compatible string - """ - compat = node.props['compatible'].value - aliases = [] - if isinstance(compat, list): - compat, aliases = compat[0], compat[1:] - return conv_name_to_c(compat), [conv_name_to_c(a) for a in aliases] - def scan_dtb(self): """Scan the device tree to obtain a tree of notes and properties @@ -219,22 +236,6 @@ class DtbPlatdata(object): self._valid_nodes = [] return self.scan_node(self._fdt.GetRoot()) - @staticmethod - def is_phandle(prop): - """Check if a node contains phandles - - We have no reliable way of detecting whether a node uses a phandle - or not. As an interim measure, use a list of known property names. - - Args: - prop: Prop object to check - Return: - True if the object value contains phandles, else False - """ - if prop.name in ['clocks']: - return True - return False - def scan_structs(self): """Scan the device tree building up the C structures we will use. @@ -248,7 +249,7 @@ class DtbPlatdata(object): """ structs = {} for node in self._valid_nodes: - node_name, _ = self.get_compat_name(node) + node_name, _ = get_compat_name(node) fields = {} # Get a list of all the valid properties in this node. @@ -272,14 +273,14 @@ class DtbPlatdata(object): upto = 0 for node in self._valid_nodes: - node_name, _ = self.get_compat_name(node) + node_name, _ = get_compat_name(node) struct = structs[node_name] for name, prop in node.props.items(): if name not in PROP_IGNORE_LIST and name[0] != '#': prop.Widen(struct[name]) upto += 1 - struct_name, aliases = self.get_compat_name(node) + struct_name, aliases = get_compat_name(node) for alias in aliases: self._aliases[alias] = struct_name @@ -302,7 +303,7 @@ class DtbPlatdata(object): if pname in PROP_IGNORE_LIST or pname[0] == '#': continue if isinstance(prop.value, list): - if self.is_phandle(prop): + if is_phandle(prop): # Process the list as pairs of (phandle, id) value_it = iter(prop.value) for phandle_cell, _ in zip(value_it, value_it): @@ -326,7 +327,7 @@ class DtbPlatdata(object): self.out('struct %s%s {\n' % (STRUCT_PREFIX, name)) for pname in sorted(structs[name]): prop = structs[name][pname] - if self.is_phandle(prop): + if is_phandle(prop): # For phandles, include a reference to the target self.out('\t%s%s[%d]' % (tab_to(2, 'struct phandle_2_cell'), conv_name_to_c(prop.name), @@ -350,7 +351,7 @@ class DtbPlatdata(object): Args: node: node to output """ - struct_name, _ = self.get_compat_name(node) + struct_name, _ = get_compat_name(node) var_name = conv_name_to_c(node.name) self.buf('static struct %s%s %s%s = {\n' % (STRUCT_PREFIX, struct_name, VAL_PREFIX, var_name)) @@ -366,7 +367,7 @@ class DtbPlatdata(object): vals = [] # For phandles, output a reference to the platform data # of the target node. - if self.is_phandle(prop): + if is_phandle(prop): # Process the list as pairs of (phandle, id) value_it = iter(prop.value) for phandle_cell, id_cell in zip(value_it, value_it): @@ -377,11 +378,11 @@ class DtbPlatdata(object): vals.append('{&%s%s, %d}' % (VAL_PREFIX, name, id_num)) else: for val in prop.value: - vals.append(self.get_value(prop.type, val)) + vals.append(get_value(prop.type, val)) self.buf(', '.join(vals)) self.buf('}') else: - self.buf(self.get_value(prop.type, prop.value)) + self.buf(get_value(prop.type, prop.value)) self.buf(',\n') self.buf('};\n') -- cgit v0.10.2 From fa0ea5b09ead2b0fa17754c0bf99249533fd36a3 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 18 Jun 2017 22:09:03 -0600 Subject: dtoc: Move the main logic into the dtb_platdata file Collect the main logic of dtoc into a function and put it into dtb_platdata. This will allow tests to use this function instead of duplicating the code themselves. Signed-off-by: Simon Glass diff --git a/tools/dtoc/dtb_platdata.py b/tools/dtoc/dtb_platdata.py index a1f32e1..9923892 100644 --- a/tools/dtoc/dtb_platdata.py +++ b/tools/dtoc/dtb_platdata.py @@ -422,3 +422,32 @@ class DtbPlatdata(object): nodes_to_output.remove(req_node) self.output_node(node) nodes_to_output.remove(node) + + +def run_steps(args, dtb_file, include_disabled, output): + """Run all the steps of the dtoc tool + + Args: + args: List of non-option arguments provided to the problem + dtb_file: Filename of dtb file to process + include_disabled: True to include disabled nodes + output: Name of output file + """ + if not args: + raise ValueError('Please specify a command: struct, platdata') + + plat = DtbPlatdata(dtb_file, include_disabled) + plat.scan_dtb() + plat.scan_tree() + plat.setup_output(output) + structs = plat.scan_structs() + plat.scan_phandles() + + for cmd in args[0].split(','): + if cmd == 'struct': + plat.generate_structs(structs) + elif cmd == 'platdata': + plat.generate_tables() + else: + raise ValueError("Unknown command '%s': (use: struct, platdata)" % + cmd) diff --git a/tools/dtoc/dtoc.py b/tools/dtoc/dtoc.py index 1f17ea4..140a19e 100755 --- a/tools/dtoc/dtoc.py +++ b/tools/dtoc/dtoc.py @@ -49,20 +49,5 @@ parser.add_option('-o', '--output', action='store', default='-', help='Select output filename') (options, args) = parser.parse_args() -if not args: - raise ValueError('Please specify a command: struct, platdata') - -plat = dtb_platdata.DtbPlatdata(options.dtb_file, options.include_disabled) -plat.scan_dtb() -plat.scan_tree() -plat.setup_output(options.output) -structs = plat.scan_structs() -plat.scan_phandles() - -for cmd in args[0].split(','): - if cmd == 'struct': - plat.generate_structs(structs) - elif cmd == 'platdata': - plat.generate_tables() - else: - raise ValueError("Unknown command '%s': (use: struct, platdata)" % cmd) +dtb_platdata.run_steps(args, options.dtb_file, options.include_disabled, + options.output) -- cgit v0.10.2 From 30107b08d7df87e4c92e413d92896a847f1c74dd Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 18 Jun 2017 22:09:04 -0600 Subject: dtoc: Add a comment about string replace in conv_name_to_c() This function uses several separate string replaces where a regular expression might seem more reasonable. Add a comment justifying the way it is currently done. Signed-off-by: Simon Glass diff --git a/tools/dtoc/dtb_platdata.py b/tools/dtoc/dtb_platdata.py index 9923892..1f85343 100644 --- a/tools/dtoc/dtb_platdata.py +++ b/tools/dtoc/dtb_platdata.py @@ -46,6 +46,9 @@ VAL_PREFIX = 'dtv_' def conv_name_to_c(name): """Convert a device-tree name to a C identifier + This uses multiple replace() calls instead of re.sub() since it is faster + (400ms for 1m calls versus 1000ms for the 're' version). + Args: name: Name to convert Return: -- cgit v0.10.2 From 2028cc59f7b904f8e91a99439aa630b20932baa5 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 18 Jun 2017 22:09:05 -0600 Subject: sandbox: Stop printing platdata at the start of SPL Currently we have code which prints out platform data at the start of SPL. Now that we have tests for dtoc this is probably not necessary. Drop it. Update test_ofplatdata to check for empty output since it is useful to check that sandbox_spl works as expected. Signed-off-by: Simon Glass diff --git a/arch/sandbox/cpu/spl.c b/arch/sandbox/cpu/spl.c index 7cc76d4..2495fa9 100644 --- a/arch/sandbox/cpu/spl.c +++ b/arch/sandbox/cpu/spl.c @@ -44,16 +44,5 @@ SPL_LOAD_IMAGE_METHOD("sandbox", 0, BOOT_DEVICE_BOARD, spl_board_load_image); void spl_board_init(void) { - struct udevice *dev; - preloader_console_init(); - - /* - * Scan all the devices so that we can output their platform data. See - * sandbox_spl_probe(). - */ - for (uclass_first_device(UCLASS_MISC, &dev); - dev; - uclass_next_device(&dev)) - ; } diff --git a/test/py/tests/test_ofplatdata.py b/test/py/tests/test_ofplatdata.py index 457c405..0660ce4 100644 --- a/test/py/tests/test_ofplatdata.py +++ b/test/py/tests/test_ofplatdata.py @@ -4,35 +4,7 @@ import pytest -OF_PLATDATA_OUTPUT = ''' -of-platdata probe: -bool 1 -byte 05 -bytearray 06 00 00 -int 1 -intarray 2 3 4 0 -longbytearray 09 0a 0b 0c 0d 0e 0f 10 11 -string message -stringarray "multi-word" "message" "" -of-platdata probe: -bool 0 -byte 08 -bytearray 01 23 34 -int 3 -intarray 5 0 0 0 -longbytearray 09 00 00 00 00 00 00 00 00 -string message2 -stringarray "another" "multi-word" "message" -of-platdata probe: -bool 0 -byte 00 -bytearray 00 00 00 -int 0 -intarray 0 0 0 0 -longbytearray 00 00 00 00 00 00 00 00 00 -string -stringarray "one" "" "" -''' +OF_PLATDATA_OUTPUT = '' @pytest.mark.buildconfigspec('spl_of_platdata') def test_ofplatdata(u_boot_console): -- cgit v0.10.2 From c07919281c521c57d34eba8bfbac910c9632beda Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 18 Jun 2017 22:09:06 -0600 Subject: dtoc: Add tests Add some tests of dtoc's functionality to make it easier to expand and enhance the tool. Signed-off-by: Simon Glass diff --git a/tools/dtoc/dtoc.py b/tools/dtoc/dtoc.py index 140a19e..ce7bc05 100755 --- a/tools/dtoc/dtoc.py +++ b/tools/dtoc/dtoc.py @@ -29,6 +29,7 @@ see doc/driver-model/of-plat.txt from optparse import OptionParser import os import sys +import unittest # Bring in the patman libraries our_path = os.path.dirname(os.path.realpath(__file__)) @@ -36,9 +37,24 @@ sys.path.append(os.path.join(our_path, '../patman')) import dtb_platdata +def run_tests(): + """Run all the test we have for dtoc""" + import test_dtoc -if __name__ != "__main__": - pass + result = unittest.TestResult() + sys.argv = [sys.argv[0]] + for module in (test_dtoc.TestDtoc,): + suite = unittest.TestLoader().loadTestsFromTestCase(module) + suite.run(result) + + print result + for _, err in result.errors: + print err + for _, err in result.failures: + print err + +if __name__ != '__main__': + sys.exit(1) parser = OptionParser() parser.add_option('-d', '--dtb-file', action='store', @@ -47,7 +63,14 @@ parser.add_option('--include-disabled', action='store_true', help='Include disabled nodes') parser.add_option('-o', '--output', action='store', default='-', help='Select output filename') +parser.add_option('-t', '--test', action='store_true', dest='test', + default=False, help='run tests') (options, args) = parser.parse_args() -dtb_platdata.run_steps(args, options.dtb_file, options.include_disabled, - options.output) +# Run our meagre tests +if options.test: + run_tests() + +else: + dtb_platdata.run_steps(args, options.dtb_file, options.include_disabled, + options.output) diff --git a/tools/dtoc/dtoc_test.dts b/tools/dtoc/dtoc_test.dts new file mode 100644 index 0000000..1e86655 --- /dev/null +++ b/tools/dtoc/dtoc_test.dts @@ -0,0 +1,12 @@ +/* + * Test device tree file for dtoc + * + * Copyright 2017 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + + /dts-v1/; + +/ { +}; diff --git a/tools/dtoc/dtoc_test_aliases.dts b/tools/dtoc/dtoc_test_aliases.dts new file mode 100644 index 0000000..c727f18 --- /dev/null +++ b/tools/dtoc/dtoc_test_aliases.dts @@ -0,0 +1,18 @@ +/* + * Test device tree file for dtoc + * + * Copyright 2017 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + + /dts-v1/; + +/ { + spl-test { + u-boot,dm-pre-reloc; + compatible = "compat1", "compat2.1-fred", "compat3"; + intval = <1>; + }; + +}; diff --git a/tools/dtoc/dtoc_test_empty.dts b/tools/dtoc/dtoc_test_empty.dts new file mode 100644 index 0000000..1e86655 --- /dev/null +++ b/tools/dtoc/dtoc_test_empty.dts @@ -0,0 +1,12 @@ +/* + * Test device tree file for dtoc + * + * Copyright 2017 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + + /dts-v1/; + +/ { +}; diff --git a/tools/dtoc/dtoc_test_phandle.dts b/tools/dtoc/dtoc_test_phandle.dts new file mode 100644 index 0000000..e9828a6 --- /dev/null +++ b/tools/dtoc/dtoc_test_phandle.dts @@ -0,0 +1,23 @@ +/* + * Test device tree file for dtoc + * + * Copyright 2017 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + + /dts-v1/; + +/ { + phandle: phandle-target { + u-boot,dm-pre-reloc; + compatible = "target"; + intval = <1>; + }; + + phandle-source { + u-boot,dm-pre-reloc; + compatible = "source"; + clocks = <&phandle 1>; + }; +}; diff --git a/tools/dtoc/dtoc_test_simple.dts b/tools/dtoc/dtoc_test_simple.dts new file mode 100644 index 0000000..c736686 --- /dev/null +++ b/tools/dtoc/dtoc_test_simple.dts @@ -0,0 +1,48 @@ +/* + * Test device tree file for dtoc + * + * Copyright 2017 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + + /dts-v1/; + +/ { + spl-test { + u-boot,dm-pre-reloc; + compatible = "sandbox,spl-test"; + boolval; + intval = <1>; + intarray = <2 3 4>; + byteval = [05]; + bytearray = [06]; + longbytearray = [09 0a 0b 0c 0d 0e 0f 10 11]; + stringval = "message"; + stringarray = "multi-word", "message"; + }; + + spl-test2 { + u-boot,dm-pre-reloc; + compatible = "sandbox,spl-test"; + intval = <3>; + intarray = <5>; + byteval = [08]; + bytearray = [01 23 34]; + longbytearray = [09 0a 0b 0c]; + stringval = "message2"; + stringarray = "another", "multi-word", "message"; + }; + + spl-test3 { + u-boot,dm-pre-reloc; + compatible = "sandbox,spl-test"; + stringarray = "one"; + }; + + spl-test4 { + u-boot,dm-pre-reloc; + compatible = "sandbox,spl-test.2"; + }; + +}; diff --git a/tools/dtoc/test_dtoc.py b/tools/dtoc/test_dtoc.py new file mode 100644 index 0000000..8b95c41 --- /dev/null +++ b/tools/dtoc/test_dtoc.py @@ -0,0 +1,271 @@ +# +# Copyright (c) 2012 The Chromium OS Authors. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +"""Tests for the dtb_platdata module + +This includes unit tests for some functions and functional tests for +""" + +import collections +import os +import struct +import unittest + +import dtb_platdata +from dtb_platdata import conv_name_to_c +from dtb_platdata import get_compat_name +from dtb_platdata import get_value +from dtb_platdata import tab_to +import fdt +import fdt_util +import tools + +our_path = os.path.dirname(os.path.realpath(__file__)) + + +def get_dtb_file(dts_fname): + """Compile a .dts file to a .dtb + + Args: + dts_fname: Filename of .dts file in the current directory + + Returns: + Filename of compiled file in output directory + """ + return fdt_util.EnsureCompiled(os.path.join(our_path, dts_fname)) + + +class TestDtoc(unittest.TestCase): + """Tests for dtoc""" + @classmethod + def setUpClass(cls): + tools.PrepareOutputDir(None) + + @classmethod + def tearDownClass(cls): + tools._RemoveOutputDir() + + def test_name(self): + """Test conversion of device tree names to C identifiers""" + self.assertEqual('serial_at_0x12', conv_name_to_c('serial@0x12')) + self.assertEqual('vendor_clock_frequency', + conv_name_to_c('vendor,clock-frequency')) + self.assertEqual('rockchip_rk3399_sdhci_5_1', + conv_name_to_c('rockchip,rk3399-sdhci-5.1')) + + def test_tab_to(self): + """Test operation of tab_to() function""" + self.assertEqual('fred ', tab_to(0, 'fred')) + self.assertEqual('fred\t', tab_to(1, 'fred')) + self.assertEqual('fred was here ', tab_to(1, 'fred was here')) + self.assertEqual('fred was here\t\t', tab_to(3, 'fred was here')) + self.assertEqual('exactly8 ', tab_to(1, 'exactly8')) + self.assertEqual('exactly8\t', tab_to(2, 'exactly8')) + + def test_get_value(self): + """Test operation of get_value() function""" + self.assertEqual('0x45', + get_value(fdt.TYPE_INT, struct.pack('>I', 0x45))) + self.assertEqual('0x45', + get_value(fdt.TYPE_BYTE, struct.pack('I', 0x45))) + self.assertEqual('"test"', get_value(fdt.TYPE_STRING, 'test')) + self.assertEqual('true', get_value(fdt.TYPE_BOOL, None)) + + def test_get_compat_name(self): + """Test operation of get_compat_name() function""" + Prop = collections.namedtuple('Prop', ['value']) + Node = collections.namedtuple('Node', ['props']) + + prop = Prop(['rockchip,rk3399-sdhci-5.1', 'arasan,sdhci-5.1']) + node = Node({'compatible': prop}) + self.assertEqual(('rockchip_rk3399_sdhci_5_1', ['arasan_sdhci_5_1']), + get_compat_name(node)) + + prop = Prop(['rockchip,rk3399-sdhci-5.1']) + node = Node({'compatible': prop}) + self.assertEqual(('rockchip_rk3399_sdhci_5_1', []), + get_compat_name(node)) + + prop = Prop(['rockchip,rk3399-sdhci-5.1', 'arasan,sdhci-5.1', 'third']) + node = Node({'compatible': prop}) + self.assertEqual(('rockchip_rk3399_sdhci_5_1', + ['arasan_sdhci_5_1', 'third']), + get_compat_name(node)) + + def test_empty_file(self): + """Test output from a device tree file with no nodes""" + dtb_file = get_dtb_file('dtoc_test_empty.dts') + output = tools.GetOutputFilename('output') + dtb_platdata.run_steps(['struct'], dtb_file, False, output) + with open(output) as infile: + lines = infile.read().splitlines() + self.assertEqual(['#include ', '#include '], lines) + + dtb_platdata.run_steps(['platdata'], dtb_file, False, output) + with open(output) as infile: + lines = infile.read().splitlines() + self.assertEqual(['#include ', '#include ', + '#include ', ''], lines) + + def test_simple(self): + """Test output from some simple nodes with various types of data""" + dtb_file = get_dtb_file('dtoc_test_simple.dts') + output = tools.GetOutputFilename('output') + dtb_platdata.run_steps(['struct'], dtb_file, False, output) + with open(output) as infile: + data = infile.read() + self.assertEqual('''#include +#include +struct dtd_sandbox_spl_test { +\tbool\t\tboolval; +\tunsigned char\tbytearray[3]; +\tunsigned char\tbyteval; +\tfdt32_t\t\tintarray[4]; +\tfdt32_t\t\tintval; +\tunsigned char\tlongbytearray[9]; +\tconst char *\tstringarray[3]; +\tconst char *\tstringval; +}; +struct dtd_sandbox_spl_test_2 { +}; +''', data) + + dtb_platdata.run_steps(['platdata'], dtb_file, False, output) + with open(output) as infile: + data = infile.read() + self.assertEqual('''#include +#include +#include + +static struct dtd_sandbox_spl_test dtv_spl_test = { +\t.bytearray\t\t= {0x6, 0x0, 0x0}, +\t.byteval\t\t= 0x5, +\t.intval\t\t\t= 0x1, +\t.longbytearray\t\t= {0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11}, +\t.stringval\t\t= "message", +\t.boolval\t\t= true, +\t.intarray\t\t= {0x2, 0x3, 0x4, 0x0}, +\t.stringarray\t\t= {"multi-word", "message", ""}, +}; +U_BOOT_DEVICE(spl_test) = { +\t.name\t\t= "sandbox_spl_test", +\t.platdata\t= &dtv_spl_test, +\t.platdata_size\t= sizeof(dtv_spl_test), +}; + +static struct dtd_sandbox_spl_test dtv_spl_test2 = { +\t.bytearray\t\t= {0x1, 0x23, 0x34}, +\t.byteval\t\t= 0x8, +\t.intval\t\t\t= 0x3, +\t.longbytearray\t\t= {0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, +\t.stringval\t\t= "message2", +\t.intarray\t\t= {0x5, 0x0, 0x0, 0x0}, +\t.stringarray\t\t= {"another", "multi-word", "message"}, +}; +U_BOOT_DEVICE(spl_test2) = { +\t.name\t\t= "sandbox_spl_test", +\t.platdata\t= &dtv_spl_test2, +\t.platdata_size\t= sizeof(dtv_spl_test2), +}; + +static struct dtd_sandbox_spl_test dtv_spl_test3 = { +\t.stringarray\t\t= {"one", "", ""}, +}; +U_BOOT_DEVICE(spl_test3) = { +\t.name\t\t= "sandbox_spl_test", +\t.platdata\t= &dtv_spl_test3, +\t.platdata_size\t= sizeof(dtv_spl_test3), +}; + +static struct dtd_sandbox_spl_test_2 dtv_spl_test4 = { +}; +U_BOOT_DEVICE(spl_test4) = { +\t.name\t\t= "sandbox_spl_test_2", +\t.platdata\t= &dtv_spl_test4, +\t.platdata_size\t= sizeof(dtv_spl_test4), +}; + +''', data) + + def test_phandle(self): + """Test output from a node containing a phandle reference""" + dtb_file = get_dtb_file('dtoc_test_phandle.dts') + output = tools.GetOutputFilename('output') + dtb_platdata.run_steps(['struct'], dtb_file, False, output) + with open(output) as infile: + data = infile.read() + self.assertEqual('''#include +#include +struct dtd_source { +\tstruct phandle_2_cell clocks[1]; +}; +struct dtd_target { +\tfdt32_t\t\tintval; +}; +''', data) + + dtb_platdata.run_steps(['platdata'], dtb_file, False, output) + with open(output) as infile: + data = infile.read() + self.assertEqual('''#include +#include +#include + +static struct dtd_target dtv_phandle_target = { +\t.intval\t\t\t= 0x1, +}; +U_BOOT_DEVICE(phandle_target) = { +\t.name\t\t= "target", +\t.platdata\t= &dtv_phandle_target, +\t.platdata_size\t= sizeof(dtv_phandle_target), +}; + +static struct dtd_source dtv_phandle_source = { +\t.clocks\t\t\t= {{&dtv_phandle_target, 1}}, +}; +U_BOOT_DEVICE(phandle_source) = { +\t.name\t\t= "source", +\t.platdata\t= &dtv_phandle_source, +\t.platdata_size\t= sizeof(dtv_phandle_source), +}; + +''', data) + + def test_aliases(self): + """Test output from a node with multiple compatible strings""" + dtb_file = get_dtb_file('dtoc_test_aliases.dts') + output = tools.GetOutputFilename('output') + dtb_platdata.run_steps(['struct'], dtb_file, False, output) + with open(output) as infile: + data = infile.read() + self.assertEqual('''#include +#include +struct dtd_compat1 { +\tfdt32_t\t\tintval; +}; +#define dtd_compat2_1_fred dtd_compat1 +#define dtd_compat3 dtd_compat1 +''', data) + + dtb_platdata.run_steps(['platdata'], dtb_file, False, output) + with open(output) as infile: + data = infile.read() + self.assertEqual('''#include +#include +#include + +static struct dtd_compat1 dtv_spl_test = { +\t.intval\t\t\t= 0x1, +}; +U_BOOT_DEVICE(spl_test) = { +\t.name\t\t= "compat1", +\t.platdata\t= &dtv_spl_test, +\t.platdata_size\t= sizeof(dtv_spl_test), +}; + +''', data) -- cgit v0.10.2 From 7feccfdc45d5708ffd682a025d6d6e8907f1a97a Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 20 Jun 2017 21:28:49 -0600 Subject: binman: Put our local modules ahead of system modules If a system module is named the same as one of those used by binman we currently pick the system module. Adjust the ordering so that our modules are chosen instead. The module conflict reported was 'tools' from jira-python. I cannot access that package to test it. Signed-off-by: Simon Glass Reported-by: Kevin Hilman Acked-by: Kevin Hilman diff --git a/tools/binman/binman.py b/tools/binman/binman.py index 95d3a048..09dc36a 100755 --- a/tools/binman/binman.py +++ b/tools/binman/binman.py @@ -17,15 +17,14 @@ import unittest # Bring in the patman and dtoc libraries our_path = os.path.dirname(os.path.realpath(__file__)) -sys.path.append(os.path.join(our_path, '../patman')) -sys.path.append(os.path.join(our_path, '../dtoc')) -sys.path.append(os.path.join(our_path, '../')) +for dirname in ['../patman', '../dtoc', '..']: + sys.path.insert(0, os.path.join(our_path, dirname)) # Bring in the libfdt module -sys.path.append('tools') +sys.path.insert(0, 'tools') # Also allow entry-type modules to be brought in from the etype directory. -sys.path.append(os.path.join(our_path, 'etype')) +sys.path.insert(0, os.path.join(our_path, 'etype')) import cmdline import command -- cgit v0.10.2 From 8c293d6ac9c9f698a2b5db8def9d1cef725b5011 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 12 Jun 2017 06:21:28 -0600 Subject: dm: core: Add ofnode_read_string_count() This provides a way to find the number of strings in a string list. Add it and also fix up the comment for ofnode_read_string_index(). Signed-off-by: Simon Glass Tested-by: Marcel Ziswiler Tested-on: Beaver, Jetson-TK1 diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index ac312d6..79c80df 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -260,6 +260,16 @@ int ofnode_read_string_index(ofnode node, const char *property, int index, } } +int ofnode_read_string_count(ofnode node, const char *property) +{ + if (ofnode_is_np(node)) { + return of_property_count_strings(ofnode_to_np(node), property); + } else { + return fdt_stringlist_count(gd->fdt_blob, + ofnode_to_offset(node), property); + } +} + static void ofnode_from_fdtdec_phandle_args(struct fdtdec_phandle_args *in, struct ofnode_phandle_args *out) { diff --git a/include/dm/of_access.h b/include/dm/of_access.h index 142f0f4..d282700 100644 --- a/include/dm/of_access.h +++ b/include/dm/of_access.h @@ -261,6 +261,24 @@ static inline int of_property_read_string_index(const struct device_node *np, } /** + * of_property_count_strings() - Find and return the number of strings from a + * multiple strings property. + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * + * Search for a property in a device tree node and retrieve the number of null + * terminated string contain in it. Returns the number of strings on + * success, -EINVAL if the property does not exist, -ENODATA if property + * does not have a value, and -EILSEQ if the string is not null-terminated + * within the length of the property data. + */ +static inline int of_property_count_strings(const struct device_node *np, + const char *propname) +{ + return of_property_read_string_helper(np, propname, NULL, 0, 0); +} + +/** * of_parse_phandle - Resolve a phandle property to a device_node pointer * @np: Pointer to device node holding phandle property * @phandle_name: Name of property holding a phandle value diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h index 149622a..d261a61 100644 --- a/include/dm/ofnode.h +++ b/include/dm/ofnode.h @@ -359,7 +359,7 @@ int ofnode_stringlist_search(ofnode node, const char *propname, const char *string); /** - * fdt_stringlist_get() - obtain the string at a given index in a string list + * ofnode_read_string_index() - obtain an indexed string from a string list * * Note that this will successfully extract strings from properties with * non-NUL-terminated values. For example on small-valued cell properties @@ -380,6 +380,16 @@ int ofnode_read_string_index(ofnode node, const char *propname, int index, const char **outp); /** + * ofnode_read_string_count() - find the number of strings in a string list + * + * @node: node to check + * @propname: name of the property containing the string list + * @return: + * number of strings in the list, or -ve error value if not found + */ +int ofnode_read_string_count(ofnode node, const char *property); + +/** * ofnode_parse_phandle_with_args() - Find a node pointed by phandle in a list * * This function is useful to parse lists of phandles and their arguments. -- cgit v0.10.2 From a44810123f9ef069587beacdce7d6f488cf42973 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 12 Jun 2017 06:21:29 -0600 Subject: dm: core: Add dev_read_resource() to read device resources Add a function which reads resources from a device, such as the device hardware address. This uses the "reg" property in the device. Unlike other functions there is little sense in inlining this when livetree is not being used because it has some logic in it and this would just bloat the code size. Signed-off-by: Simon Glass Tested-by: Marcel Ziswiler Tested-on: Beaver, Jetson-TK1 diff --git a/drivers/core/Makefile b/drivers/core/Makefile index 435cf98..fd2d4de 100644 --- a/drivers/core/Makefile +++ b/drivers/core/Makefile @@ -15,4 +15,4 @@ obj-$(CONFIG_OF_LIVE) += of_access.o of_addr.o ifndef CONFIG_DM_DEV_READ_INLINE obj-$(CONFIG_OF_CONTROL) += read.o endif -obj-$(CONFIG_OF_CONTROL) += of_extra.o ofnode.o +obj-$(CONFIG_OF_CONTROL) += of_extra.o ofnode.o read_extra.o diff --git a/drivers/core/read_extra.c b/drivers/core/read_extra.c new file mode 100644 index 0000000..a6d2f34 --- /dev/null +++ b/drivers/core/read_extra.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2017 Google, Inc + * Written by Simon Glass + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +int dev_read_resource(struct udevice *dev, uint index, struct resource *res) +{ + ofnode node = dev_ofnode(dev); + +#ifdef CONFIG_OF_LIVE + if (ofnode_is_np(node)) { + return of_address_to_resource(ofnode_to_np(node), index, res); + } else +#endif + { + struct fdt_resource fres; + int ret; + + ret = fdt_get_resource(gd->fdt_blob, ofnode_to_offset(node), + "reg", index, &fres); + if (ret < 0) + return -EINVAL; + memset(res, '\0', sizeof(*res)); + res->start = fres.start; + res->end = fres.end; + + return 0; + } +} diff --git a/include/dm/read.h b/include/dm/read.h index 8c9846e..65d5d1f 100644 --- a/include/dm/read.h +++ b/include/dm/read.h @@ -14,6 +14,8 @@ #include #include +struct resource; + #if CONFIG_IS_ENABLED(OF_LIVE) static inline const struct device_node *dev_np(struct udevice *dev) { @@ -42,6 +44,16 @@ static inline bool dev_of_valid(struct udevice *dev) return ofnode_valid(dev_ofnode(dev)); } +/** + * dev_read_resource() - obtain an indexed resource from a device. + * + * @dev: devuce to examine + * @index index of the resource to retrieve (0 = first) + * @res returns the resource + * @return 0 if ok, negative on error + */ +int dev_read_resource(struct udevice *dev, uint index, struct resource *res); + #ifndef CONFIG_DM_DEV_READ_INLINE /** * dev_read_u32_default() - read a 32-bit integer from a device's DT property -- cgit v0.10.2 From f7d6fcf7aead384ea39bc7aba581e912c3759eaa Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 12 Jun 2017 06:21:30 -0600 Subject: dm: core: Add dev_read_enabled() to check if a device is enabled This function allows a device's status to be read. This indicates whether the device should be enabled or disabled. Note: In normal operation disabled devices will not be present in the driver-model tree. Signed-off-by: Simon Glass Tested-by: Marcel Ziswiler Tested-on: Beaver, Jetson-TK1 diff --git a/drivers/core/read.c b/drivers/core/read.c index 3131e53..1080767 100644 --- a/drivers/core/read.c +++ b/drivers/core/read.c @@ -138,3 +138,14 @@ const uint8_t *dev_read_u8_array_ptr(struct udevice *dev, const char *propname, { return ofnode_read_u8_array_ptr(dev_ofnode(dev), propname, sz); } + +int dev_read_enabled(struct udevice *dev) +{ + ofnode node = dev_ofnode(dev); + + if (ofnode_is_np(node)) + return of_device_is_available(ofnode_to_np(node)); + else + return fdtdec_get_is_enabled(gd->fdt_blob, + ofnode_to_offset(node)); +} diff --git a/include/dm/read.h b/include/dm/read.h index 65d5d1f..cea1c16 100644 --- a/include/dm/read.h +++ b/include/dm/read.h @@ -315,6 +315,19 @@ ofnode dev_read_next_subnode(ofnode node); const uint8_t *dev_read_u8_array_ptr(struct udevice *dev, const char *propname, size_t sz); +/** + * dev_read_enabled() - check whether a node is enabled + * + * This looks for a 'status' property. If this exists, then returns 1 if + * the status is 'ok' and 0 otherwise. If there is no status property, + * it returns 1 on the assumption that anything mentioned should be enabled + * by default. + * + * @dev: device to examine + * @return integer value 0 (not enabled) or 1 (enabled) + */ +int dev_read_enabled(struct udevice *dev); + #else /* CONFIG_DM_DEV_READ_INLINE is enabled */ static inline int dev_read_u32_default(struct udevice *dev, @@ -432,6 +445,11 @@ static inline const uint8_t *dev_read_u8_array_ptr(struct udevice *dev, return ofnode_read_u8_array_ptr(dev_ofnode(dev), propname, sz); } +static inline int dev_read_enabled(struct udevice *dev) +{ + return fdtdec_get_is_enabled(gd->fdt_blob, dev_of_offset(dev)); +} + #endif /* CONFIG_DM_DEV_READ_INLINE */ /** -- cgit v0.10.2 From 878d68c0c357ff62120d5783d950f34ecd1065d9 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 12 Jun 2017 06:21:31 -0600 Subject: dm: core: Add functions to obtain node's address/size cells The of_n_addr_cells() and of_n_size_cells() functions are useful for getting the size of addresses in a node, but in a few places U-Boot needs to obtain the actual property value for a node without walking up the stack. Add functions for this and just the existing code to use it. Add a comment to the existing ofnode functions which do not do the right thing with a flat tree. This fixes a problem reading PCI addresses. Signed-off-by: Simon Glass Tested-by: Marcel Ziswiler Tested-on: Beaver, Jetson-TK1 diff --git a/drivers/core/of_access.c b/drivers/core/of_access.c index 93a6560..2bb23ee 100644 --- a/drivers/core/of_access.c +++ b/drivers/core/of_access.c @@ -96,6 +96,30 @@ int of_n_size_cells(const struct device_node *np) return OF_ROOT_NODE_SIZE_CELLS_DEFAULT; } +int of_simple_addr_cells(const struct device_node *np) +{ + const __be32 *ip; + + ip = of_get_property(np, "#address-cells", NULL); + if (ip) + return be32_to_cpup(ip); + + /* Return a default of 2 to match fdt_address_cells()*/ + return 2; +} + +int of_simple_size_cells(const struct device_node *np) +{ + const __be32 *ip; + + ip = of_get_property(np, "#size-cells", NULL); + if (ip) + return be32_to_cpup(ip); + + /* Return a default of 2 to match fdt_size_cells()*/ + return 2; +} + struct property *of_find_property(const struct device_node *np, const char *name, int *lenp) { diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index 79c80df..da7c477 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -552,7 +552,7 @@ int ofnode_read_addr_cells(ofnode node) { if (ofnode_is_np(node)) return of_n_addr_cells(ofnode_to_np(node)); - else + else /* NOTE: this call should walk up the parent stack */ return fdt_address_cells(gd->fdt_blob, ofnode_to_offset(node)); } @@ -560,6 +560,22 @@ int ofnode_read_size_cells(ofnode node) { if (ofnode_is_np(node)) return of_n_size_cells(ofnode_to_np(node)); + else /* NOTE: this call should walk up the parent stack */ + return fdt_size_cells(gd->fdt_blob, ofnode_to_offset(node)); +} + +int ofnode_read_simple_addr_cells(ofnode node) +{ + if (ofnode_is_np(node)) + return of_simple_addr_cells(ofnode_to_np(node)); + else + return fdt_address_cells(gd->fdt_blob, ofnode_to_offset(node)); +} + +int ofnode_read_simple_size_cells(ofnode node) +{ + if (ofnode_is_np(node)) + return of_simple_size_cells(ofnode_to_np(node)); else return fdt_size_cells(gd->fdt_blob, ofnode_to_offset(node)); } diff --git a/drivers/core/read.c b/drivers/core/read.c index 1080767..36293ba 100644 --- a/drivers/core/read.c +++ b/drivers/core/read.c @@ -94,6 +94,16 @@ int dev_read_size_cells(struct udevice *dev) return ofnode_read_size_cells(dev_ofnode(dev)); } +int dev_read_simple_addr_cells(struct udevice *dev) +{ + return ofnode_read_simple_addr_cells(dev_ofnode(dev)); +} + +int dev_read_simple_size_cells(struct udevice *dev) +{ + return ofnode_read_simple_size_cells(dev_ofnode(dev)); +} + int dev_read_phandle(struct udevice *dev) { ofnode node = dev_ofnode(dev); diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c index 749d913..d4e16a2 100644 --- a/drivers/core/regmap.c +++ b/drivers/core/regmap.c @@ -72,8 +72,8 @@ int regmap_init_mem(struct udevice *dev, struct regmap **mapp) ofnode node = dev_ofnode(dev); struct resource r; - addr_len = dev_read_addr_cells(dev->parent); - size_len = dev_read_size_cells(dev->parent); + addr_len = dev_read_simple_addr_cells(dev->parent); + size_len = dev_read_simple_size_cells(dev->parent); both_len = addr_len + size_len; len = dev_read_size(dev, "reg"); diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index b36ef33..4223040 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -766,9 +766,9 @@ static int decode_regions(struct pci_controller *hose, ofnode parent_node, prop = ofnode_read_prop(node, "ranges", &len); if (!prop) return -EINVAL; - pci_addr_cells = ofnode_read_addr_cells(node); - addr_cells = ofnode_read_addr_cells(parent_node); - size_cells = ofnode_read_size_cells(node); + pci_addr_cells = ofnode_read_simple_addr_cells(node); + addr_cells = ofnode_read_simple_addr_cells(parent_node); + size_cells = ofnode_read_simple_size_cells(node); /* PCI addresses are always 3-cells */ len /= sizeof(u32); diff --git a/include/dm/of_access.h b/include/dm/of_access.h index d282700..c5ea391 100644 --- a/include/dm/of_access.h +++ b/include/dm/of_access.h @@ -61,6 +61,26 @@ int of_n_addr_cells(const struct device_node *np); int of_n_size_cells(const struct device_node *np); /** + * of_simple_addr_cells() - Get the address cells property in a node + * + * This function matches fdt_address_cells(). + * + * @np: Node pointer to check + * @return value of #address-cells property in this node, or 2 if none + */ +int of_simple_addr_cells(const struct device_node *np); + +/** + * of_simple_size_cells() - Get the size cells property in a node + * + * This function matches fdt_size_cells(). + * + * @np: Node pointer to check + * @return value of #size-cells property in this node, or 2 if none + */ +int of_simple_size_cells(const struct device_node *np); + +/** * of_find_property() - find a property in a node * * @np: Pointer to device node holding property diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h index d261a61..c3d8db5 100644 --- a/include/dm/ofnode.h +++ b/include/dm/ofnode.h @@ -562,6 +562,26 @@ int ofnode_read_addr_cells(ofnode node); int ofnode_read_size_cells(ofnode node); /** + * ofnode_read_simple_addr_cells() - Get the address cells property in a node + * + * This function matches fdt_address_cells(). + * + * @np: Node pointer to check + * @return value of #address-cells property in this node, or 2 if none + */ +int ofnode_read_simple_addr_cells(ofnode node); + +/** + * ofnode_read_simple_size_cells() - Get the size cells property in a node + * + * This function matches fdt_size_cells(). + * + * @np: Node pointer to check + * @return value of #size-cells property in this node, or 2 if none + */ +int ofnode_read_simple_size_cells(ofnode node); + +/** * ofnode_pre_reloc() - check if a node should be bound before relocation * * Device tree nodes can be marked as needing-to-be-bound in the loader stages diff --git a/include/dm/read.h b/include/dm/read.h index cea1c16..6dd1634 100644 --- a/include/dm/read.h +++ b/include/dm/read.h @@ -231,6 +231,26 @@ int dev_read_addr_cells(struct udevice *dev); int dev_read_size_cells(struct udevice *dev); /** + * dev_read_addr_cells() - Get the address cells property in a node + * + * This function matches fdt_address_cells(). + * + * @dev: devioe to check + * @return number of address cells this node uses + */ +int dev_read_simple_addr_cells(struct udevice *dev); + +/** + * dev_read_size_cells() - Get the size cells property in a node + * + * This function matches fdt_size_cells(). + * + * @dev: devioe to check + * @return number of size cells this node uses + */ +int dev_read_simple_size_cells(struct udevice *dev); + +/** * dev_read_phandle() - Get the phandle from a device * * @dev: device to check @@ -398,11 +418,23 @@ static inline int dev_read_phandle_with_args(struct udevice *dev, static inline int dev_read_addr_cells(struct udevice *dev) { + /* NOTE: this call should walk up the parent stack */ return fdt_address_cells(gd->fdt_blob, dev_of_offset(dev)); } static inline int dev_read_size_cells(struct udevice *dev) { + /* NOTE: this call should walk up the parent stack */ + return fdt_size_cells(gd->fdt_blob, dev_of_offset(dev)); +} + +static inline int dev_read_simple_addr_cells(struct udevice *dev) +{ + return fdt_address_cells(gd->fdt_blob, dev_of_offset(dev)); +} + +static inline int dev_read_simple_size_cells(struct udevice *dev) +{ return fdt_size_cells(gd->fdt_blob, dev_of_offset(dev)); } -- cgit v0.10.2 From 23acc48d8499944f41e4608b5683b1cdce95ec9b Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 12 Jun 2017 06:21:32 -0600 Subject: tegra: video: Time the LCD init Calculate the time taken to set up the LCD. Signed-off-by: Simon Glass Tested-by: Marcel Ziswiler Tested-on: Beaver, Jetson-TK1 diff --git a/drivers/video/tegra124/display.c b/drivers/video/tegra124/display.c index bbbca13..47752b2 100644 --- a/drivers/video/tegra124/display.c +++ b/drivers/video/tegra124/display.c @@ -471,7 +471,9 @@ static int tegra124_lcd_probe(struct udevice *dev) int ret; start = get_timer(0); + bootstage_start(BOOTSTAGE_ID_ACCUM_LCD, "lcd"); ret = tegra124_lcd_init(dev, (void *)plat->base, VIDEO_BPP16); + bootstage_accum(BOOTSTAGE_ID_ACCUM_LCD); debug("LCD init took %lu ms\n", get_timer(start)); if (ret) printf("%s: Error %d\n", __func__, ret); -- cgit v0.10.2 From 0be3a3b4732a0d66ff12b5e3abb1644fb884f13f Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 12 Jun 2017 06:21:33 -0600 Subject: tegra: nyan-big: Enable the debug UART Enable this to allow debugging when the serial UART driver is misconfigured. Signed-off-by: Simon Glass Tested-by: Marcel Ziswiler Tested-on: Beaver, Jetson-TK1 diff --git a/configs/nyan-big_defconfig b/configs/nyan-big_defconfig index fb2e479..8ecb56b 100644 --- a/configs/nyan-big_defconfig +++ b/configs/nyan-big_defconfig @@ -46,6 +46,10 @@ CONFIG_PMIC_AS3722=y CONFIG_DM_REGULATOR=y CONFIG_DM_REGULATOR_FIXED=y CONFIG_PWM_TEGRA=y +CONFIG_DEBUG_UART=y +CONFIG_DEBUG_UART_BASE=0x70006000 +CONFIG_DEBUG_UART_CLOCK=408000000 +CONFIG_DEBUG_UART_SHIFT=2 CONFIG_SYS_NS16550=y CONFIG_TEGRA114_SPI=y CONFIG_TPM_TIS_INFINEON=y -- cgit v0.10.2 From c1eb3d59662b27de6030413e819c2bc46c6156fe Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 12 Jun 2017 06:21:34 -0600 Subject: dm: Fix error handling when unflattening the DT The error handling code does not current detect an error right away. Adjust it to return immediately. Signed-off-by: Simon Glass Tested-by: Marcel Ziswiler Tested-on: Beaver, Jetson-TK1 diff --git a/lib/of_live.c b/lib/of_live.c index 51927f9..f351483 100644 --- a/lib/of_live.c +++ b/lib/of_live.c @@ -216,9 +216,12 @@ static void *unflatten_dt_node(const void *blob, void *mem, int *poffset, *poffset = fdt_next_node(blob, *poffset, &depth); if (depth < 0) depth = 0; - while (*poffset > 0 && depth > old_depth) + while (*poffset > 0 && depth > old_depth) { mem = unflatten_dt_node(blob, mem, poffset, np, NULL, fpsize, dryrun); + if (!mem) + return NULL; + } if (*poffset < 0 && *poffset != -FDT_ERR_NOTFOUND) { debug("unflatten: error %d processing FDT\n", *poffset); @@ -286,6 +289,8 @@ static int unflatten_device_tree(const void *blob, start = 0; size = (unsigned long)unflatten_dt_node(blob, NULL, &start, NULL, NULL, 0, true); + if (!size) + return -EFAULT; size = ALIGN(size, 4); debug(" size is %lx, allocating...\n", size); -- cgit v0.10.2 From 2f0dd5cafe6e6f59e4d798ca2ec0a6bae3a19aa5 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 12 Jun 2017 06:21:35 -0600 Subject: tegra: nyan-big: Enable bootstage Enable full bootstage support so we can time SPL and U-Boot. Signed-off-by: Simon Glass Tested-by: Marcel Ziswiler Tested-on: Beaver, Jetson-TK1 diff --git a/configs/nyan-big_defconfig b/configs/nyan-big_defconfig index 8ecb56b..cb3b0a8 100644 --- a/configs/nyan-big_defconfig +++ b/configs/nyan-big_defconfig @@ -6,6 +6,10 @@ CONFIG_DEFAULT_DEVICE_TREE="tegra124-nyan-big" CONFIG_FIT=y CONFIG_FIT_BEST_MATCH=y CONFIG_OF_SYSTEM_SETUP=y +CONFIG_BOOTSTAGE=y +CONFIG_SPL_BOOTSTAGE=y +CONFIG_BOOTSTAGE_STASH=y +CONFIG_BOOTSTAGE_STASH_ADDR=0x83000000 CONFIG_SYS_STDIO_DEREGISTER=y CONFIG_SYS_PROMPT="Tegra124 (Nyan-big) # " # CONFIG_CMD_IMI is not set @@ -23,6 +27,7 @@ CONFIG_CMD_GPIO=y # CONFIG_CMD_SETEXPR is not set # CONFIG_CMD_NFS is not set CONFIG_CMD_BMP=y +CONFIG_CMD_BOOTSTAGE=y CONFIG_CMD_CACHE=y CONFIG_CMD_PMIC=y CONFIG_CMD_REGULATOR=y -- cgit v0.10.2 From fb0b709effab16b0d73cfc6130e0b28bfea6ace2 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 12 Jun 2017 06:21:36 -0600 Subject: dm: video: Sync display on backspace We should sync the display (e.g. flush cache) when backspace is pressed to ensure that the character is erased correctly. Signed-off-by: Simon Glass Acked-by: Anatolij Gustschin Tested-by: Marcel Ziswiler Tested-on: Beaver, Jetson-TK1 diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c index e9a90b1..b5afd72 100644 --- a/drivers/video/vidconsole-uclass.c +++ b/drivers/video/vidconsole-uclass.c @@ -77,6 +77,7 @@ static int vidconsole_back(struct udevice *dev) if (priv->ycur < 0) priv->ycur = 0; } + video_sync(dev->parent); return 0; } -- cgit v0.10.2 From 7cf208d73bd0ad08d486d3e338f44087dee9b755 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 12 Jun 2017 06:21:37 -0600 Subject: dm: video: Update pwm_backlight to support livetree Update this driver to support a live device tree. Signed-off-by: Simon Glass Acked-by: Anatolij Gustschin Tested-by: Marcel Ziswiler Tested-on: Beaver, Jetson-TK1 diff --git a/drivers/video/pwm_backlight.c b/drivers/video/pwm_backlight.c index 3697f49..fbd7bf7 100644 --- a/drivers/video/pwm_backlight.c +++ b/drivers/video/pwm_backlight.c @@ -28,11 +28,13 @@ struct pwm_backlight_priv { static int pwm_backlight_enable(struct udevice *dev) { struct pwm_backlight_priv *priv = dev_get_priv(dev); + struct dm_regulator_uclass_platdata *plat; uint duty_cycle; int ret; - debug("%s: Enable '%s', regulator '%s'\n", __func__, dev->name, - priv->reg->name); + plat = dev_get_uclass_platdata(priv->reg); + debug("%s: Enable '%s', regulator '%s'/'%s'\n", __func__, dev->name, + priv->reg->name, plat->name); ret = regulator_set_enable(priv->reg, true); if (ret) { debug("%s: Cannot enable regulator for PWM '%s'\n", __func__, @@ -59,12 +61,11 @@ static int pwm_backlight_enable(struct udevice *dev) static int pwm_backlight_ofdata_to_platdata(struct udevice *dev) { struct pwm_backlight_priv *priv = dev_get_priv(dev); - struct fdtdec_phandle_args args; - const void *blob = gd->fdt_blob; - int node = dev_of_offset(dev); + struct ofnode_phandle_args args; int index, ret, count, len; const u32 *cell; + debug("%s: start\n", __func__); ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev, "power-supply", &priv->reg); if (ret) { @@ -79,14 +80,14 @@ static int pwm_backlight_ofdata_to_platdata(struct udevice *dev) if (ret != -ENOENT) return ret; } - ret = fdtdec_parse_phandle_with_args(blob, node, "pwms", "#pwm-cells", - 0, 0, &args); + ret = dev_read_phandle_with_args(dev, "pwms", "#pwm-cells", 0, 0, + &args); if (ret) { debug("%s: Cannot get PWM phandle: ret=%d\n", __func__, ret); return ret; } - ret = uclass_get_device_by_of_offset(UCLASS_PWM, args.node, &priv->pwm); + ret = uclass_get_device_by_ofnode(UCLASS_PWM, args.node, &priv->pwm); if (ret) { debug("%s: Cannot get PWM: ret=%d\n", __func__, ret); return ret; @@ -94,8 +95,8 @@ static int pwm_backlight_ofdata_to_platdata(struct udevice *dev) priv->channel = args.args[0]; priv->period_ns = args.args[1]; - index = fdtdec_get_int(blob, node, "default-brightness-level", 255); - cell = fdt_getprop(blob, node, "brightness-levels", &len); + index = dev_read_u32_default(dev, "default-brightness-level", 255); + cell = dev_read_prop(dev, "brightness-levels", &len); count = len / sizeof(u32); if (cell && count > index) { priv->default_level = fdt32_to_cpu(cell[index]); @@ -104,6 +105,7 @@ static int pwm_backlight_ofdata_to_platdata(struct udevice *dev) priv->default_level = index; priv->max_level = 255; } + debug("%s: done\n", __func__); return 0; -- cgit v0.10.2 From 1a9f3da917cd1d18ceea77ef8ae61221ad2b5550 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 12 Jun 2017 06:21:38 -0600 Subject: video: simple-panel: Add a little more debugging Add some debugging to show when the backlight is enabled. Signed-off-by: Simon Glass Acked-by: Anatolij Gustschin Tested-by: Marcel Ziswiler Tested-on: Beaver, Jetson-TK1 diff --git a/drivers/video/simple_panel.c b/drivers/video/simple_panel.c index baa95f6..c0ce199 100644 --- a/drivers/video/simple_panel.c +++ b/drivers/video/simple_panel.c @@ -25,8 +25,10 @@ static int simple_panel_enable_backlight(struct udevice *dev) struct simple_panel_priv *priv = dev_get_priv(dev); int ret; + debug("%s: start, backlight = '%s'\n", __func__, priv->backlight->name); dm_gpio_set_value(&priv->enable, 1); ret = backlight_enable(priv->backlight); + debug("%s: done, ret = %d\n", __func__, ret); if (ret) return ret; -- cgit v0.10.2 From 03bc3f18b77a3d3157ef7faa4533c7303ea78a80 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 12 Jun 2017 06:21:39 -0600 Subject: tegra: Fix up include file ordering Update these two files so include files in the right order. Signed-off-by: Simon Glass Tested-by: Marcel Ziswiler Tested-on: Beaver, Jetson-TK1 diff --git a/arch/arm/mach-tegra/board2.c b/arch/arm/mach-tegra/board2.c index 1e627ba..9905720 100644 --- a/arch/arm/mach-tegra/board2.c +++ b/arch/arm/mach-tegra/board2.c @@ -9,14 +9,8 @@ #include #include #include -#include -#include +#include #include -#include -#include -#include -#include -#include #include #include #include @@ -25,17 +19,17 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include #ifdef CONFIG_TEGRA_CLOCK_SCALING #include #endif -#include -#ifdef CONFIG_USB_EHCI_TEGRA -#include -#endif -#include #include -#include -#include #include "emc.h" DECLARE_GLOBAL_DATA_PTR; diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c index bac4211..668bbd2 100644 --- a/arch/arm/mach-tegra/clock.c +++ b/arch/arm/mach-tegra/clock.c @@ -7,6 +7,8 @@ /* Tegra SoC common clock control functions */ #include +#include +#include #include #include #include @@ -15,8 +17,6 @@ #include #include #include -#include -#include /* * This is our record of the current clock rate of each clock. We don't -- cgit v0.10.2 From db9f8f6ad5718909c57aee9a9f476309ac790e1f Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 12 Jun 2017 06:21:56 -0600 Subject: dm: serial: ns16550: Convert to livetree Update this driver to support a live device tree. Signed-off-by: Simon Glass Tested-by: Marcel Ziswiler Tested-on: Beaver, Jetson-TK1 diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c index 52c52c1..330c5e1 100644 --- a/drivers/serial/ns16550.c +++ b/drivers/serial/ns16550.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -395,7 +394,7 @@ int ns16550_serial_ofdata_to_platdata(struct udevice *dev) int err; /* try Processor Local Bus device first */ - addr = devfdt_get_addr(dev); + addr = dev_read_addr(dev); #if defined(CONFIG_PCI) && defined(CONFIG_DM_PCI) if (addr == FDT_ADDR_T_NONE) { /* then try pci device */ @@ -434,11 +433,8 @@ int ns16550_serial_ofdata_to_platdata(struct udevice *dev) plat->base = (unsigned long)map_physmem(addr, 0, MAP_NOCACHE); #endif - plat->reg_offset = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), - "reg-offset", 0); - plat->reg_shift = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), - "reg-shift", 0); - + plat->reg_offset = dev_read_u32_default(dev, "reg-offset", 0); + plat->reg_shift = dev_read_u32_default(dev, "reg-shift", 0); err = clk_get_by_index(dev, 0, &clk); if (!err) { err = clk_get_rate(&clk); @@ -450,9 +446,8 @@ int ns16550_serial_ofdata_to_platdata(struct udevice *dev) } if (!plat->clock) - plat->clock = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), - "clock-frequency", - CONFIG_SYS_NS16550_CLK); + plat->clock = dev_read_u32_default(dev, "clock-frequency", + CONFIG_SYS_NS16550_CLK); if (!plat->clock) { debug("ns16550 clock not defined\n"); return -EINVAL; -- cgit v0.10.2 From d09608534cb4864d1fbde6459d3501129c344a0c Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 12 Jun 2017 06:21:57 -0600 Subject: dm: serial: Separate out the core serial-device finding code This function is quite long. Move the core code into a separate function in preparation for adding livetree support. Signed-off-by: Simon Glass Tested-by: Marcel Ziswiler Tested-on: Beaver, Jetson-TK1 diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c index 200f4b9..7e42906 100644 --- a/drivers/serial/serial-uclass.c +++ b/drivers/serial/serial-uclass.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -27,11 +26,53 @@ static const unsigned long baudrate_table[] = CONFIG_SYS_BAUDRATE_TABLE; #error "Serial is required before relocation - define CONFIG_SYS_MALLOC_F_LEN to make this work" #endif +static int serial_check_stdout(const void *blob, struct udevice **devp) +{ + int node; + + /* Check for a chosen console */ + node = fdtdec_get_chosen_node(blob, "stdout-path"); + if (node < 0) { + const char *str, *p, *name; + + /* + * Deal with things like + * stdout-path = "serial0:115200n8"; + * + * We need to look up the alias and then follow it to the + * correct node. + */ + str = fdtdec_get_chosen_prop(blob, "stdout-path"); + if (str) { + p = strchr(str, ':'); + name = fdt_get_alias_namelen(blob, str, + p ? p - str : strlen(str)); + if (name) + node = fdt_path_offset(blob, name); + } + } + if (node < 0) + node = fdt_path_offset(blob, "console"); + if (!uclass_get_device_by_of_offset(UCLASS_SERIAL, node, devp)) + return 0; + + /* + * If the console is not marked to be bound before relocation, bind it + * anyway. + */ + if (node > 0 && !lists_bind_fdt(gd->dm_root, offset_to_ofnode(node), + devp)) { + if (!device_probe(*devp)) + return 0; + } + + return -ENODEV; +} + static void serial_find_console_or_panic(void) { const void *blob = gd->fdt_blob; struct udevice *dev; - int node; if (CONFIG_IS_ENABLED(OF_PLATDATA)) { uclass_first_device(UCLASS_SERIAL, &dev); @@ -40,47 +81,10 @@ static void serial_find_console_or_panic(void) return; } } else if (CONFIG_IS_ENABLED(OF_CONTROL) && blob) { - /* Check for a chosen console */ - node = fdtdec_get_chosen_node(blob, "stdout-path"); - if (node < 0) { - const char *str, *p, *name; - - /* - * Deal with things like - * stdout-path = "serial0:115200n8"; - * - * We need to look up the alias and then follow it to - * the correct node. - */ - str = fdtdec_get_chosen_prop(blob, "stdout-path"); - if (str) { - p = strchr(str, ':'); - name = fdt_get_alias_namelen(blob, str, - p ? p - str : strlen(str)); - if (name) - node = fdt_path_offset(blob, name); - } - } - if (node < 0) - node = fdt_path_offset(blob, "console"); - if (!uclass_get_device_by_of_offset(UCLASS_SERIAL, node, - &dev)) { + if (!serial_check_stdout(blob, &dev)) { gd->cur_serial_dev = dev; return; } - - /* - * If the console is not marked to be bound before relocation, - * bind it anyway. - */ - if (node > 0 && - !lists_bind_fdt(gd->dm_root, offset_to_ofnode(node), - &dev)) { - if (!device_probe(dev)) { - gd->cur_serial_dev = dev; - return; - } - } } if (!SPL_BUILD || !CONFIG_IS_ENABLED(OF_CONTROL) || !blob) { /* -- cgit v0.10.2 From f93472a0221b6e1eb7acce8aee6c2eb335904f58 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 12 Jun 2017 06:21:58 -0600 Subject: dm: serial: Add livetree support Add support for a live device tree to the core serial uclass. Signed-off-by: Simon Glass Tested-by: Marcel Ziswiler Tested-on: Beaver, Jetson-TK1 diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c index 7e42906..f360534 100644 --- a/drivers/serial/serial-uclass.c +++ b/drivers/serial/serial-uclass.c @@ -14,6 +14,7 @@ #include #include #include +#include DECLARE_GLOBAL_DATA_PTR; @@ -81,9 +82,20 @@ static void serial_find_console_or_panic(void) return; } } else if (CONFIG_IS_ENABLED(OF_CONTROL) && blob) { - if (!serial_check_stdout(blob, &dev)) { - gd->cur_serial_dev = dev; - return; + /* Live tree has support for stdout */ + if (of_live_active()) { + struct device_node *np = of_get_stdout(); + + if (np && !uclass_get_device_by_ofnode(UCLASS_SERIAL, + np_to_ofnode(np), &dev)) { + gd->cur_serial_dev = dev; + return; + } + } else { + if (!serial_check_stdout(blob, &dev)) { + gd->cur_serial_dev = dev; + return; + } } } if (!SPL_BUILD || !CONFIG_IS_ENABLED(OF_CONTROL) || !blob) { -- cgit v0.10.2 From 50d8c4a4652311e66e6ff1e44d09f17046261ee1 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 12 Jun 2017 06:21:59 -0600 Subject: tegra: Show a debug message if the LCD PMIC fails to start This error condition should have a debug() message. Add it. Signed-off-by: Simon Glass Tested-by: Marcel Ziswiler Tested-on: Beaver, Jetson-TK1 diff --git a/arch/arm/mach-tegra/board2.c b/arch/arm/mach-tegra/board2.c index 9905720..6b5fa7d 100644 --- a/arch/arm/mach-tegra/board2.c +++ b/arch/arm/mach-tegra/board2.c @@ -156,8 +156,10 @@ int board_init(void) #if defined(CONFIG_DM_VIDEO) board_id = tegra_board_id(); err = tegra_lcd_pmic_init(board_id); - if (err) + if (err) { + debug("Failed to set up LCD PMIC\n"); return err; + } #endif #ifdef CONFIG_TEGRA_NAND -- cgit v0.10.2 From f53dcc0e35b46f169432448d8db254b0d6776806 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 12 Jun 2017 06:22:01 -0600 Subject: tegra: fdt: Ensure that the console UART is enabled Many tegra boards have the console UART node disabled. With livetree this prevents serial from working since it does not 'force' the console to be bound. Updates the affected boards to fix this error. The boards were checked with: for b in $(grep tegra boards.cfg |grep -v integrator | \ awk '{print $7}' | sort); do echo $b; fdtgrep -c nvidia,tegra20-uart b/$b/u-boot.dtb |grep okay; done Signed-off-by: Simon Glass Tested-by: Marcel Ziswiler Tested-on: Beaver, Jetson-TK1 diff --git a/arch/arm/dts/tegra114-dalmore.dts b/arch/arm/dts/tegra114-dalmore.dts index 5f4df88..18bcb75 100644 --- a/arch/arm/dts/tegra114-dalmore.dts +++ b/arch/arm/dts/tegra114-dalmore.dts @@ -93,3 +93,7 @@ }; }; }; + +&uartd { + status = "okay"; +}; diff --git a/arch/arm/dts/tegra124-cei-tk1-som.dts b/arch/arm/dts/tegra124-cei-tk1-som.dts index c4d4f9d..b1dd418 100644 --- a/arch/arm/dts/tegra124-cei-tk1-som.dts +++ b/arch/arm/dts/tegra124-cei-tk1-som.dts @@ -475,3 +475,7 @@ }; }; }; + +&uartd { + status = "okay"; +}; diff --git a/arch/arm/dts/tegra124-jetson-tk1.dts b/arch/arm/dts/tegra124-jetson-tk1.dts index f1db952..d642043 100644 --- a/arch/arm/dts/tegra124-jetson-tk1.dts +++ b/arch/arm/dts/tegra124-jetson-tk1.dts @@ -480,3 +480,7 @@ }; }; }; + +&uartd { + status = "okay"; +}; diff --git a/arch/arm/dts/tegra124-venice2.dts b/arch/arm/dts/tegra124-venice2.dts index add9244..7e9c6aa 100644 --- a/arch/arm/dts/tegra124-venice2.dts +++ b/arch/arm/dts/tegra124-venice2.dts @@ -109,3 +109,7 @@ }; }; + +&uarta { + status = "okay"; +}; diff --git a/arch/arm/dts/tegra186-p2771-0000.dtsi b/arch/arm/dts/tegra186-p2771-0000.dtsi index 54b2539..a1319dc 100644 --- a/arch/arm/dts/tegra186-p2771-0000.dtsi +++ b/arch/arm/dts/tegra186-p2771-0000.dtsi @@ -76,3 +76,7 @@ }; }; }; + +&uarta { + status = "okay"; +}; diff --git a/arch/arm/dts/tegra20-colibri.dts b/arch/arm/dts/tegra20-colibri.dts index 3c10dd6..9171319 100644 --- a/arch/arm/dts/tegra20-colibri.dts +++ b/arch/arm/dts/tegra20-colibri.dts @@ -162,3 +162,7 @@ }; }; }; + +&uarta { + status = "okay"; +}; diff --git a/arch/arm/dts/tegra20-harmony.dts b/arch/arm/dts/tegra20-harmony.dts index dcbde7c..0c90705 100644 --- a/arch/arm/dts/tegra20-harmony.dts +++ b/arch/arm/dts/tegra20-harmony.dts @@ -812,3 +812,7 @@ clock-names = "pll_a", "pll_a_out0", "mclk"; }; }; + +&uartd { + status = "okay"; +}; diff --git a/arch/arm/dts/tegra20-trimslice.dts b/arch/arm/dts/tegra20-trimslice.dts index 7fb7dd0..31f509a 100644 --- a/arch/arm/dts/tegra20-trimslice.dts +++ b/arch/arm/dts/tegra20-trimslice.dts @@ -129,3 +129,7 @@ }; }; + +&uarta { + status = "okay"; +}; diff --git a/arch/arm/dts/tegra210-e2220-1170.dts b/arch/arm/dts/tegra210-e2220-1170.dts index 70cd72b..e6b0686 100644 --- a/arch/arm/dts/tegra210-e2220-1170.dts +++ b/arch/arm/dts/tegra210-e2220-1170.dts @@ -57,3 +57,7 @@ }; }; }; + +&uarta { + status = "okay"; +}; diff --git a/arch/arm/dts/tegra210-p2371-0000.dts b/arch/arm/dts/tegra210-p2371-0000.dts index d961296..539e7ce 100644 --- a/arch/arm/dts/tegra210-p2371-0000.dts +++ b/arch/arm/dts/tegra210-p2371-0000.dts @@ -58,3 +58,7 @@ }; }; }; + +&uarta { + status = "okay"; +}; diff --git a/arch/arm/dts/tegra210-p2371-2180.dts b/arch/arm/dts/tegra210-p2371-2180.dts index 0dc06a4..da4349b 100644 --- a/arch/arm/dts/tegra210-p2371-2180.dts +++ b/arch/arm/dts/tegra210-p2371-2180.dts @@ -109,3 +109,7 @@ }; }; }; + +&uarta { + status = "okay"; +}; diff --git a/arch/arm/dts/tegra210-p2571.dts b/arch/arm/dts/tegra210-p2571.dts index 2afcde5..16370c5 100644 --- a/arch/arm/dts/tegra210-p2571.dts +++ b/arch/arm/dts/tegra210-p2571.dts @@ -105,3 +105,7 @@ }; }; }; + +&uarta { + status = "okay"; +}; diff --git a/arch/arm/dts/tegra30-apalis.dts b/arch/arm/dts/tegra30-apalis.dts index 9e4ab8c..e739c59 100644 --- a/arch/arm/dts/tegra30-apalis.dts +++ b/arch/arm/dts/tegra30-apalis.dts @@ -332,3 +332,7 @@ }; }; }; + +&uarta { + status = "okay"; +}; diff --git a/arch/arm/dts/tegra30-beaver.dts b/arch/arm/dts/tegra30-beaver.dts index 4a32fcf..c1a15bb 100644 --- a/arch/arm/dts/tegra30-beaver.dts +++ b/arch/arm/dts/tegra30-beaver.dts @@ -346,3 +346,7 @@ }; }; }; + +&uarta { + status = "okay"; +}; diff --git a/arch/arm/dts/tegra30-cardhu.dts b/arch/arm/dts/tegra30-cardhu.dts index 70fd916..5b9798c 100644 --- a/arch/arm/dts/tegra30-cardhu.dts +++ b/arch/arm/dts/tegra30-cardhu.dts @@ -451,3 +451,7 @@ }; }; }; + +&uarta { + status = "okay"; +}; diff --git a/arch/arm/dts/tegra30-colibri.dts b/arch/arm/dts/tegra30-colibri.dts index 3cff2f6..49ebe91 100644 --- a/arch/arm/dts/tegra30-colibri.dts +++ b/arch/arm/dts/tegra30-colibri.dts @@ -106,3 +106,7 @@ }; }; }; + +&uarta { + status = "okay"; +}; diff --git a/arch/arm/dts/tegra30-tec-ng.dts b/arch/arm/dts/tegra30-tec-ng.dts index e924acc..f2a49b8 100644 --- a/arch/arm/dts/tegra30-tec-ng.dts +++ b/arch/arm/dts/tegra30-tec-ng.dts @@ -20,3 +20,7 @@ status = "okay"; }; }; + +&uartd { + status = "okay"; +}; -- cgit v0.10.2 From 99bb38e2cce9d99238458e0f6d1880c6d2e80a4d Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Tue, 13 Jun 2017 07:10:35 -0400 Subject: fdt: Check for NULL return from fdt_getprop in 'fdt set' While the previous pass through fixed one place where we knew that fdt_getprop would be given a positive len, in the case of 'fdt set' we do not, so check that we did no get NULL from fdt_getprop(). Cc: Simon Glass Reported-by: Coverity (CID: 163249) Fixes 72c98ed1ab48 ("fdt: Add a check to do_fdt() for coverity") Signed-off-by: Tom Rini Reviewed-by: Simon Glass diff --git a/cmd/fdt.c b/cmd/fdt.c index 31a5361..05e19f8 100644 --- a/cmd/fdt.c +++ b/cmd/fdt.c @@ -284,6 +284,10 @@ static int do_fdt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) len = 0; } else { ptmp = fdt_getprop(working_fdt, nodeoffset, prop, &len); + if (!ptmp) { + printf("prop (%s) not found!\n", prop); + return 1; + } if (len > SCRATCHPAD) { printf("prop (%d) doesn't fit in scratchpad!\n", len); -- cgit v0.10.2 From 766c28a548714a8944e9638a2727157191ff6cca Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 22 Jun 2017 16:50:01 +0900 Subject: dm: include from drivers/core/util.c Fix sparse warnings "... was not declared. Should it be static?" Also, fix redefinition of dm_warn/dm_dbg. Signed-off-by: Masahiro Yamada Reviewed-by: Bin Meng diff --git a/drivers/core/util.c b/drivers/core/util.c index 5ceac8b..2e232d5 100644 --- a/drivers/core/util.c +++ b/drivers/core/util.c @@ -5,9 +5,11 @@ */ #include +#include #include #include +#ifdef CONFIG_DM_WARN void dm_warn(const char *fmt, ...) { va_list args; @@ -16,7 +18,9 @@ void dm_warn(const char *fmt, ...) vprintf(fmt, args); va_end(args); } +#endif +#ifdef DEBUG void dm_dbg(const char *fmt, ...) { va_list args; @@ -25,6 +29,7 @@ void dm_dbg(const char *fmt, ...) vprintf(fmt, args); va_end(args); } +#endif int list_count_items(struct list_head *head) { -- cgit v0.10.2 From 252510ac69461c9fc7fa3ec25d655c6f56b0fa93 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 22 Jun 2017 16:54:03 +0900 Subject: dm: ofnode: use ofnode_read_bool() to check property existence This will clarify the code. Signed-off-by: Masahiro Yamada Acked-by: Simon Glass diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index da7c477..98c1186 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -582,22 +582,22 @@ int ofnode_read_simple_size_cells(ofnode node) bool ofnode_pre_reloc(ofnode node) { - if (ofnode_read_prop(node, "u-boot,dm-pre-reloc", NULL)) + if (ofnode_read_bool(node, "u-boot,dm-pre-reloc")) return true; #ifdef CONFIG_TPL_BUILD - if (ofnode_read_prop(node, "u-boot,dm-tpl", NULL)) + if (ofnode_read_bool(node, "u-boot,dm-tpl")) return true; #elif defined(CONFIG_SPL_BUILD) - if (ofnode_read_prop(node, "u-boot,dm-spl", NULL)) + if (ofnode_read_bool(node, "u-boot,dm-spl")) return true; #else /* * In regular builds individual spl and tpl handling both * count as handled pre-relocation for later second init. */ - if (ofnode_read_prop(node, "u-boot,dm-spl", NULL) || - ofnode_read_prop(node, "u-boot,dm-tpl", NULL)) + if (ofnode_read_bool(node, "u-boot,dm-spl") || + ofnode_read_bool(node, "u-boot,dm-tpl")) return true; #endif -- cgit v0.10.2 From cb7dbe1fb017f0a1ad050a9dc91ed2c10cb998e6 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 22 Jun 2017 16:54:04 +0900 Subject: dm: ofnode: simplify ofnode_read_prop() The code inside the if-block is the same as of_get_property(). Signed-off-by: Masahiro Yamada Acked-by: Simon Glass diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index 98c1186..d9441c8 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -434,17 +434,11 @@ int ofnode_decode_display_timing(ofnode parent, int index, const u32 *ofnode_read_prop(ofnode node, const char *propname, int *lenp) { - if (ofnode_is_np(node)) { - struct property *prop; - - prop = of_find_property(ofnode_to_np(node), propname, lenp); - if (!prop) - return NULL; - return prop->value; - } else { + if (ofnode_is_np(node)) + return of_get_property(ofnode_to_np(node), propname, lenp); + else return fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname, lenp); - } } bool ofnode_is_available(ofnode node) -- cgit v0.10.2 From 61e51babdb674e4619165cdc180786af7ec75ae9 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 22 Jun 2017 16:54:05 +0900 Subject: dm: ofnode: rename ofnode_read_prop() to ofnode_get_property() This function returns the pointer to the value of a node property. The current name ofnode_read_prop() is confusing. Follow the naming of_get_property() from Linux. The return type (const u32 *) is wrong. DT property values can be strings as well as integers. This is why of_get_property/fdt_getprop returns an opaque pointer. Signed-off-by: Masahiro Yamada Acked-by: Simon Glass diff --git a/drivers/core/lists.c b/drivers/core/lists.c index b79f26d..6067914 100644 --- a/drivers/core/lists.c +++ b/drivers/core/lists.c @@ -141,8 +141,7 @@ int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp) name = ofnode_get_name(node); dm_dbg("bind node %s\n", name); - compat_list = (const char *)ofnode_read_prop(node, "compatible", - &compat_length); + compat_list = ofnode_get_property(node, "compatible", &compat_length); if (!compat_list) { if (compat_length == -FDT_ERR_NOTFOUND) { dm_dbg("Device '%s' has no compatible string\n", name); diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index d9441c8..372d07a 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -432,7 +432,7 @@ int ofnode_decode_display_timing(ofnode parent, int index, return ret; } -const u32 *ofnode_read_prop(ofnode node, const char *propname, int *lenp) +const void *ofnode_get_property(ofnode node, const char *propname, int *lenp) { if (ofnode_is_np(node)) return of_get_property(ofnode_to_np(node), propname, lenp); @@ -503,7 +503,7 @@ int ofnode_read_pci_addr(ofnode node, enum fdt_pci_space type, * #size-cells. They need to be 3 and 2 accordingly. However, * for simplicity we skip the check here. */ - cell = ofnode_read_prop(node, propname, &len); + cell = ofnode_get_property(node, propname, &len); if (!cell) goto fail; diff --git a/drivers/core/read.c b/drivers/core/read.c index 36293ba..eafe727 100644 --- a/drivers/core/read.c +++ b/drivers/core/read.c @@ -116,7 +116,7 @@ int dev_read_phandle(struct udevice *dev) const u32 *dev_read_prop(struct udevice *dev, const char *propname, int *lenp) { - return ofnode_read_prop(dev_ofnode(dev), propname, lenp); + return ofnode_get_property(dev_ofnode(dev), propname, lenp); } int dev_read_alias_seq(struct udevice *dev, int *devnump) diff --git a/drivers/misc/cros_ec_sandbox.c b/drivers/misc/cros_ec_sandbox.c index c96e26e..5924ade 100644 --- a/drivers/misc/cros_ec_sandbox.c +++ b/drivers/misc/cros_ec_sandbox.c @@ -197,7 +197,7 @@ static int keyscan_read_fdt_matrix(struct ec_state *ec, ofnode node) int upto; int len; - cell = ofnode_read_prop(node, "linux,keymap", &len); + cell = ofnode_get_property(node, "linux,keymap", &len); ec->matrix_count = len / 4; ec->matrix = calloc(ec->matrix_count, sizeof(*ec->matrix)); if (!ec->matrix) { diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index 4223040..86df141 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -763,7 +763,7 @@ static int decode_regions(struct pci_controller *hose, ofnode parent_node, int len; int i; - prop = ofnode_read_prop(node, "ranges", &len); + prop = ofnode_get_property(node, "ranges", &len); if (!prop) return -EINVAL; pci_addr_cells = ofnode_read_simple_addr_cells(node); diff --git a/drivers/pinctrl/pinctrl-uclass.c b/drivers/pinctrl/pinctrl-uclass.c index 02e2690..114952a 100644 --- a/drivers/pinctrl/pinctrl-uclass.c +++ b/drivers/pinctrl/pinctrl-uclass.c @@ -134,7 +134,7 @@ static int pinconfig_post_bind(struct udevice *dev) * If this node has "compatible" property, this is not * a pin configuration node, but a normal device. skip. */ - ofnode_read_prop(node, "compatible", &ret); + ofnode_get_property(node, "compatible", &ret); if (ret >= 0) continue; diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h index c3d8db5..15ad519 100644 --- a/include/dm/ofnode.h +++ b/include/dm/ofnode.h @@ -473,14 +473,14 @@ int ofnode_decode_display_timing(ofnode node, int index, struct display_timing *config); /** - * ofnode_read_prop()- - read a node property + * ofnode_get_property()- - get a pointer to the value of a node property * * @node: node to read * @propname: property to read * @lenp: place to put length on success * @return pointer to property, or NULL if not found */ -const u32 *ofnode_read_prop(ofnode node, const char *propname, int *lenp); +const void *ofnode_get_property(ofnode node, const char *propname, int *lenp); /** * ofnode_is_available() - check if a node is marked available diff --git a/include/dm/read.h b/include/dm/read.h index 6dd1634..b86a2f5 100644 --- a/include/dm/read.h +++ b/include/dm/read.h @@ -446,7 +446,7 @@ static inline int dev_read_phandle(struct udevice *dev) static inline const u32 *dev_read_prop(struct udevice *dev, const char *propname, int *lenp) { - return ofnode_read_prop(dev_ofnode(dev), propname, lenp); + return ofnode_get_property(dev_ofnode(dev), propname, lenp); } static inline int dev_read_alias_seq(struct udevice *dev, int *devnump) -- cgit v0.10.2 From b2ec7ea731a1300fc3b888d9efa870fb4dafda79 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 22 Jun 2017 16:54:07 +0900 Subject: dm: ofnode: simplify ofnode_read_bool() Reuse ofnode_get_property() to simplify the implementation. Signed-off-by: Masahiro Yamada Acked-by: Simon Glass diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index 372d07a..be6447d 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -57,20 +57,16 @@ int ofnode_read_s32_default(ofnode node, const char *propname, s32 def) bool ofnode_read_bool(ofnode node, const char *propname) { - bool val; + const void *prop; assert(ofnode_valid(node)); debug("%s: %s: ", __func__, propname); - if (ofnode_is_np(node)) { - val = !!of_find_property(ofnode_to_np(node), propname, NULL); - } else { - val = !!fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), - propname, NULL); - } - debug("%s\n", val ? "true" : "false"); + prop = ofnode_get_property(node, propname, NULL); + + debug("%s\n", prop ? "true" : "false"); - return val; + return prop ? true : false; } const char *ofnode_read_string(ofnode node, const char *propname) -- cgit v0.10.2 From fce136aafe1f51b2dbca1439f3bf31a7e6d32ca9 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 22 Jun 2017 17:10:11 +0900 Subject: dm: include from driver/core/dump.c Include to fix sparse warnings: symbol 'dm_dump_all' was not declared. Should it be static? symbol 'dm_dump_uclass' was not declared. Should it be static? Signed-off-by: Masahiro Yamada Reviewed-by: Bin Meng Acked-by: Simon Glass diff --git a/drivers/core/dump.c b/drivers/core/dump.c index fd4596e..c3e109e 100644 --- a/drivers/core/dump.c +++ b/drivers/core/dump.c @@ -8,6 +8,7 @@ #include #include #include +#include static void show_devices(struct udevice *dev, int depth, int last_flag) { -- cgit v0.10.2 From 8c9eaadaaad888e0cd77512553d0d02d476b4dde Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 22 Jun 2017 17:57:50 +0900 Subject: dm: ofnode: use fdt32_t for DT property value to fix sparse warning DTB is encoded in big endian. When we retrieve property values, we need to use fdt32_to_cpu (aka be32_to_cpu) for endian conversion. This is a bit error-prone, but sparse is useful to detect endian mismatch. We need to use (fdt32_t *) instead of (u32 *) for a pointer of a property value. Otherwise sparse warns "cast to restricted __be32". Signed-off-by: Masahiro Yamada Reviewed-by: Simon Glass diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index be6447d..fd068b0 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -23,7 +23,7 @@ int ofnode_read_u32(ofnode node, const char *propname, u32 *outp) if (ofnode_is_np(node)) { return of_read_u32(ofnode_to_np(node), propname, outp); } else { - const int *cell; + const fdt32_t *cell; int len; cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), @@ -487,7 +487,7 @@ const uint8_t *ofnode_read_u8_array_ptr(ofnode node, const char *propname, int ofnode_read_pci_addr(ofnode node, enum fdt_pci_space type, const char *propname, struct fdt_pci_addr *addr) { - const u32 *cell; + const fdt32_t *cell; int len; int ret = -ENOENT; -- cgit v0.10.2